导出 docker container 运行时快照并从快照运行
之前讲 docker container 生命周期的时候, 看到 pause container 命令, 突然想到是否能够对一个正在运行的container 做个快照, 把全部文件和内存运行数据都dump出来, 之后根据快照随时继续运行呢?
于是 Google 了一把, 发现也有不少人有同样的疑问, 很多人的回答都提到了 docker commit, 不过这不是我想要的. docker commit 只是把改动的文件内容覆盖到原来的 image, 重新做了一个 image, 然而丢失了正在运行的进程的全部数据, 比如内存和寄存器里面的数据. 而我期望的是能保存这些进程的运行时信息, 等继续运行的时候, 能在进程应该继续执行的下一个指令的地方继续运行.
那么到底有没有神奇的方法, 能做到期望的行为呢? 其实 Docker 已经考虑了这个需求, 做为实验命令, 只是还没有正式发布, 那就是通过docker checkpoint
子命令. 官方链接.
它的主要过程就是: 当一个container 正在运行时, 通过 docker checkpoint create
dump一个包含container文件系统和运行时内存数据的快照, 并把它保存到磁盘. 之后通过docker start --checkpoint checkpoint_id container_name
来继续运行. 由于我们保存快照到文件系统, 所以可以复制很多份, 之后可以随时启动它, 随时查看当时的状态.
下面是官方的一个例子:
安装 CRIU 依赖, Docker 其实是依赖这个包才能完成container冻结和恢复的.
supra@suprabox:~$ sudo apt install criu -y
首先启动这个每隔一秒钟打印一个数字的container, 名字是cr
supra@suprabox:~$ docker run --security-opt=seccomp:unconfined --name cr -d busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' 0e09ac6f369f965af18e429ec78fcab8875610fdfd69313d6c7ecb0b86e61d7
查看打印的数据
supra@suprabox:~$ docker logs -f cr 0 1 2
生成快照
--leave-running
表示快照生成完继续运行--checkpoint-dir
表示要保存的文件夹supra@suprabox:~$ docker checkpoint create cr checkpoint1 --leave-running --checkpoint-dir /tmp/ checkpoint1
查看之前的container 还在运行, 查看我们保存快照的文件夹, 发现里面各种以 .img 结尾的文件
supra@suprabox:~$ docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ecb0b86e61d7 busybox "/bin/sh -c 'i=0; wh…" 10 minutes ago Up 10 minutes cr supra@suprabox:~$ sudo ls -alh /tmp/checkpoint1/ total 224K drwx------ 2 root root 4.0K Jan 28 18:40 . drwxrwxrwt 22 root root 12K Jan 28 18:42 .. -rw-r--r-- 1 root root 356 Jan 28 18:40 cgroup.img -rw-r--r-- 1 root root 1.8K Jan 28 18:40 core-1.img -rw-r--r-- 1 root root 1.8K Jan 28 18:40 core-1034.img -rw------- 1 root root 45 Jan 28 18:40 descriptors.json -rw-r--r-- 1 root root 44 Jan 28 18:40 fdinfo-2.img -rw-r--r-- 1 root root 44 Jan 28 18:40 fdinfo-3.img
恢复运行 - 各种失败 - 没有达到预期
去掉各种参数, 按照官方方法, 在 Ubuntu 22.04 上照样不能成功. 失败supra@suprabox:~$ docker start --checkpoint checkpoint1 cr Error response from daemon: OCI runtime restore failed: criu failed: type NOTIFY errno 0 log file: /run/containerd/io.containerd.runtime.v2.task/moby/63263d8b31317dbe1f6cf19eac2198f3e078a12f9d872e4e134eae1a4f465d49/work/restore.log: unknown supra@suprabox:~$ sudo tail -f /run/containerd/io.containerd.runtime.v2.task/moby/63263d8b31317dbe1f6cf19eac2198f3e078a12f9d872e4e134eae1a4f465d49/work/restore.log (00.274155) pie: 52: mmap(0x7fffb69f7000 -> 0x7fffb69fb000, 0x3 0x32 -1) (00.274162) pie: 52: mmap(0x7fffb69fb000 -> 0x7fffb69fd000, 0x7 0x32 -1) (00.274170) pie: 52: Preadv 0x1612000:8192... (3 iovs) (00.274193) pie: 52: `- returned 20480 (00.274198) pie: 52: `- skip pagemap (00.274203) pie: 52: `- skip pagemap (00.274208) pie: 52: `- skip pagemap (00.488504) 1: Error (criu/cr-restore.c:1480): 52 killed by signal 11: Segmentation fault (00.488867) mnt: Switching to new ns to clean ghosts (00.489104) Error (criu/cr-restore.c:2447): Restoring FAILED.
官方 CRIU 最新版本是 3.17.1, 我本地版本是 3.16.1-2 不知道是不是有问题.
upra@suprabox:~$ apt show criu
Package: criu
Version: 3.16.1-2
但是这篇 blog 在2015年当时已经成功了: https://kubernetes.io/blog/2015/07/how-did-quake-demo-from-dockercon-work/
不论如何, 想要做快照, 并且从快照恢复一个进程, 已经有很多研究了, 更多看这里: https://criu.org/