服务器-电脑一:192.168.229.134
客户端-电脑二:192.168.229.133
两台电脑的操作系统选择Ubuntu18.04.5 Desktop(64-bit)
docker使用版本 17.06.0~ce-0。
CRIU的版本选择3.14。
CRIU(Checkpoint/Restore In Userspace)是Linux上的一个软件。它可以用来暂停运行中的容器或者是进程,根据CRIU暂停生成的文件从断点恢复容器或者是进程,然后继续执行。
实验涉及两台电脑(虚拟机)因此两台电脑间的通信使用NFS(network file system)。
1. 安装NFS
- 服务器端(电脑一:192.168.229.134)
首先说明服务器端安装nfs的过程。使用apt-get下载完成nfs-kernel-server之后,将要挂载到客户端的目录添加到/etc/exports文件中。
# config host network
sudo apt-get install nfs-kernel-server -y
# config NFS
sudo gedit /etc/exports
# 在 exports file添加下行:
# /home 192.168.229.133(rw,sync,no_root_squash,no_subtree_check)
# Then restart nfs-kernel-server service
sudo systemctl restart nfs-kernel-server
在实验过程中根据需要,在服务器exports文件中加入了/home/proc和/home/container目录,分别储存进程迁移、容器迁移的相关文件。
完成上述配置之后,对防火墙进行配置。其中要允许客户端(IP为192.168.229.133)的访问。如下:
# config firewall
# First, check firewall status
sudo ufw status
#状态:不活动
#If ufw is inactive, use the below command to enable ufw:
sudo ufw enable
在系统启动时启用和激活防火墙
# Make ufw allow incoming and outgoing:
sudo ufw default allow incoming
#默认的 incoming 策略更改为 “allow”
#(请相应地更新你的防火墙规则)
sudo ufw default allow outgoing
#默认的 outgoing 策略更改为 “allow”
#(请相应地更新你的防火墙规则)
# Make client server can access host server
sudo ufw allow from 192.168.229.133 to any port nfs
#规则已添加
- 配置客户端的代码如下。
其中只挂载了/home目录,其他的目录挂载可以根据需要调整。
#!/bin/bash
# install nfs
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo rm -f /etc/apt/sources.list
sudo cp ./sources.txt /etc/apt/sources.list #这个没找到
echo "finish changing source"
sudo apt update
sudo apt upgrade -y -f
# config host network
sudo apt-get install nfs-common -y
# mount the host /home
sudo mkdir -p /nfs/home
sudo mount 192.168.229.134:/home /nfs/home
# 返回 mount.nfs: access denied by server while mounting 192.168.229.134:/home
# check mount status
sudo df -h
客户端输入sudo df -h
后返回
root@yqq2-HP-Pro-3348-MT:~# df -h
文件系统 容量 已用 可用 已用% 挂载点
udev 1.9G 0 1.9G 0% /dev
tmpfs 383M 1.6M 381M 1% /run
/dev/sda2 457G 8.6G 426G 2% /
tmpfs 1.9G 144M 1.8G 8% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/sda1 511M 6.2M 505M 2% /boot/efi
tmpfs 383M 60K 383M 1% /run/user/1000
/dev/loop0 30M 30M 0 100% /snap/snapd/8542
/dev/loop1 56M 56M 0 100% /snap/core18/1885
/dev/loop2 63M 63M 0 100% /snap/gtk-common-themes/1506
/dev/loop3 256M 256M 0 100% /snap/gnome-3-34-1804/36
/dev/loop4 2.5M 2.5M 0 100% /snap/gnome-calculator/748
/dev/loop5 384K 384K 0 100% /snap/gnome-characters/550
/dev/loop6 1.0M 1.0M 0 100% /snap/gnome-logs/100
/dev/loop7 2.3M 2.3M 0 100% /snap/gnome-system-monitor/148
tmpfs 383M 0 383M 0% /run/user/0
/dev/loop8 56M 56M 0 100% /snap/core18/1932
/dev/loop9 32M 32M 0 100% /snap/snapd/10492
/dev/loop10 384K 384K 0 100% /snap/gnome-characters/570
/dev/loop11 2.5M 2.5M 0 100% /snap/gnome-calculator/826
/dev/loop12 65M 65M 0 100% /snap/gtk-common-themes/1514
/dev/loop13 218M 218M 0 100% /snap/gnome-3-34-1804/60
192.168.229.134:/home 457G 8.5G 426G 2% /nfs/home
2.安装docker
(1)docker同样使用apt安装,而非源码编译。首先将docker(和CRIU)所需要的支持软件全部安装好,如下:
#build dependent
sudo apt install build-essential -f -y
sudo apt install pkg-config -f -y
sudo apt install libnet-dev python-yaml libaio-dev -f -y
sudo apt install libprotobuf-dev libprotobuf-c-dev protobuf-c-compiler protobuf-compiler python-protobuf libnl-3-dev libcap-dev libbsd-dev -f -y
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common -y -f
(2)之后将docker加入sources.list,并且下载对应版本的docker。此处下载的docker版本为17.06.0,下载旧版本的docker是为了保证checkpoint不出现bug(使用apt-cache madison docker-ce指令查看全部可下载版本)。
如果成功下载hello-world并且运行则说明安装成功。
# install docker
# remove docker
sudo apt-get remove docker docker-engine docker.io containerd runc
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# add repo
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
# update and install
sudo apt-get update
sudo apt-get install docker-ce=17.06.0~ce-0~ubuntu -y
# check
sudo docker run hello-world
- docker 17.06.0的下载方式。
如使用apt-cache madison docker-ce
找不到要下载的docker版本,执行下面五条命令可以解决:
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"
sudo apt-get install docker-ce=17.06.0~ce-0~ubuntu -y
(3)安装完成docker之后需要开启experiment属性,代码如下:
# add experiment to docker
sudo echo "{\"experimental\": true}" >> /etc/docker/daemon.json
sudo systemctl restart docker
3.安装CRIU
CRIU的安装使用源码编译安装的方式。下载的CRIU版本为最新的3.14版。编译源代码时可能会要求安装其他的依赖软件,可以根据提示添加。最后如果criu check输出结果为Looks good.说明没有产生问题。
# criu install
curl -O -sSL http://download.openvz.org/criu/criu-3.14.tar.bz2
tar xjf criu-3.14.tar.bz2
cd criu-3.14
make
sudo cp ./criu/criu /usr/local/bin
# check
sudo criu check
4.容器热迁移
容器热迁移和进程热迁移类似,只需要加入docker的操作即可。基本的思路是在服务器上创建容器,然后暂停容器,查看运行的输出。在客户端恢复容器之后查看输出,如果运行的输出是紧接服务器输出即说明热迁移成功。整个过程都发生在服务器的/home/container目录下,客户端将服务器的/home/container目录挂载到本地的/home/container下。
- 服务器端
(1)首先使用docker创建容器looper2,该程序递增地输出i,每个一秒输出一次。
docker run -d --name looper2 --security-opt seccomp:unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
报错Unable to find image 'busybox:latest' locally
不用管,等待一段时间,会自动下载依赖解决
root@yqq-HP-Pro-3348-MT:~/software/criu-3.14# docker run -d --name looper2 --security-opt seccomp:unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
5f5dd3e95e9f: Pull complete
Digest: sha256:9f1c79411e054199210b4d489ae600a061595967adb643cd923f8515ad8123d2
Status: Downloaded newer image for busybox:latest
0eb909831c3078fbd6545b90531c4a692cbce929325133484a07f7f8663c8fe3
(2)等待输出一段时间后中断程序,中断程序后会产生对应的目录,存储容器的运行状态,给恢复容器时使用。
sudo docker checkpoint create --checkpoint-dir=/home/container/ looper2 checkpoint2
(3)查看logs如下:
sudo docker logs looper2
root@yqq1-HP-Pro-3348-MT:~# docker logs looper2
0
1
2
3
4
5
PS:在服务器输入如下语句可恢复looper2运行。(这里先不恢复,若迁移未成功,再恢复重新迁移)
docker start looper2
- 客户端
(1)使用docker恢复容器,注意这里–checkpoint-dir只需要指定到checkpoints目录即可,不需要进一步制定checkpoint2(已经由–checkpoint指定)
docker create --name looper-clone --security-opt seccomp:unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
docker start --checkpoint-dir=/home/container/0dc28109740d76c73c26de4c8a1eeb18e5228b63fbc5d14b3ab5961dad8c8448/checkpoints/ --checkpoint=checkpoint2 looper-clone
(2)恢复容器后可以使用同样的指令查看运行结果。如下:
root@yqq2-HP-Pro-3348-MT:~# docker logs looper-clone
6
7
8
9
...
PS: 可以为一个容器创建多个 checkpoint,每个起不同的名字就是了。列出已创建的checkpoint
docker checkpoint ls looper-clone
CHECKPOINT NAME
一些辅助命令:
(1)查看docker中所有的容器
docker ps -a
(2)获取某个docker容器的详细信息
docker inspect looper2(3)启动
docker start looper2
docker start 容器ID或容器名(4)停止
docker stop
容器ID或容器名(5)重启
docker restart
容器ID或容器名 可以不管容器是否启动,直接重启容器(6)查看container
docker container ls
-(7)查看镜像文件目录
ls /var/lib/docker/containers/0dc28109740d76c73c26de4c8a1eeb18e5228b63fbc5d14b3ab5961dad8c8448
0dc28109740d76c73c26de4c8a1eeb18e5228b63fbc5d14b3ab5961dad8c8448-json.log config.v2.json
checkpoints hostconfig.json
ls /var/lib/docker/containers/0dc28109740d76c73c26de4c8a1eeb18e5228b63fbc5d14b3ab5961dad8c8448/checkpoints/
-(8)查看docker的所有镜像
docker images
遇到的问题
- (1)使用docker 18.06.1ce3-0版本,报
Error response from daemon: custom checkpointdir is not supported
的错误。如下:
root@yqq-HP-Pro-3348-MT:~/software# docker create --name looper-clone --security-opt seccomp:unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
5f5dd3e95e9f: Pull complete
Digest: sha256:9f1c79411e054199210b4d489ae600a061595967adb643cd923f8515ad8123d2
Status: Downloaded newer image for busybox:latest
0dc28109740d76c73c26de4c8a1eeb18e5228b63fbc5d14b3ab5961dad8c8448
root@yqq-HP-Pro-3348-MT:~/software# docker start --checkpoint-dir=/home/container/1101bde4f985176cab26a3fae2957763c35be3c8d0c27f0fa9e469c1a4ff5928/checkpoints/ --checkpoint=checkpoint2 looper-clone
Error response from daemon: custom checkpointdir is not supported
据说是因为 docker 对 docker start 命令中的 —-checkpoint-dir 选项不支持,可以手动把 checkpoint 文件目录加入到对应容器的默认位置 /var/lib/docker/containers/<CONTAINER_ID>/checkpoints/。(我没试)
原理知识补充
- 1.CRIU
CRIU的功能的实现基本分为两个过程,checkpoint和restore。在checkpoint过程,criu主要通过ptrace机制把一段特殊代码动态注入到dumpee进程(待备份的程序进程)并运行,这段特殊代码就实现了收集dumpee进程的所有上下文信息,然后criu把这些上下文信息按功能分类存储为一个个镜像文件。在restore过程。criu解析checkpoint过程产生的镜像文件,以此来恢复程序备份前的状态没,让程序从备份前的状态继续运行。