服務(wù)器-電腦一:192.168.229.134
客戶端-電腦二:192.168.229.133
兩臺(tái)電腦的操作系統(tǒng)選擇Ubuntu18.04.5 Desktop(64-bit)
docker使用版本 17.06.0~ce-0。
CRIU的版本選擇3.14。
CRIU(Checkpoint/Restore In Userspace)是Linux上的一個(gè)軟件。它可以用來暫停運(yùn)行中的容器或者是進(jìn)程,根據(jù)CRIU暫停生成的文件從斷點(diǎn)恢復(fù)容器或者是進(jìn)程,然后繼續(xù)執(zhí)行。
實(shí)驗(yàn)涉及兩臺(tái)電腦(虛擬機(jī))因此兩臺(tái)電腦間的通信使用NFS(network file system)。
1. 安裝NFS
- 服務(wù)器端(電腦一:192.168.229.134)
首先說明服務(wù)器端安裝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
在實(shí)驗(yàn)過程中根據(jù)需要,在服務(wù)器exports文件中加入了/home/proc和/home/container目錄,分別儲(chǔ)存進(jìn)程遷移、容器遷移的相關(guān)文件。
完成上述配置之后,對(duì)防火墻進(jìn)行配置。其中要允許客戶端(IP為192.168.229.133)的訪問。如下:
# config firewall
# First, check firewall status
sudo ufw status
#狀態(tài):不活動(dòng)
#If ufw is inactive, use the below command to enable ufw:
sudo ufw enable
在系統(tǒng)啟動(dòng)時(shí)啟用和激活防火墻
# Make ufw allow incoming and outgoing:
sudo ufw default allow incoming
#默認(rèn)的 incoming 策略更改為 “allow”
#(請(qǐng)相應(yīng)地更新你的防火墻規(guī)則)
sudo ufw default allow outgoing
#默認(rèn)的 outgoing 策略更改為 “allow”
#(請(qǐng)相應(yīng)地更新你的防火墻規(guī)則)
# Make client server can access host server
sudo ufw allow from 192.168.229.133 to any port nfs
#規(guī)則已添加
- 配置客戶端的代碼如下。
其中只掛載了/home目錄,其他的目錄掛載可以根據(jù)需要調(diào)整。
#!/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 #這個(gè)沒找到
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
文件系統(tǒng) 容量 已用 可用 已用% 掛載點(diǎn)
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,并且下載對(duì)應(yīng)版本的docker。此處下載的docker版本為17.06.0,下載舊版本的docker是為了保證checkpoint不出現(xiàn)bug(使用apt-cache madison docker-ce指令查看全部可下載版本)。
如果成功下載hello-world并且運(yùn)行則說明安裝成功。
# 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版本,執(zhí)行下面五條命令可以解決:
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版。編譯源代碼時(shí)可能會(huì)要求安裝其他的依賴軟件,可以根據(jù)提示添加。最后如果criu check輸出結(jié)果為L(zhǎng)ooks good.說明沒有產(chǎn)生問題。
# 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.容器熱遷移
容器熱遷移和進(jìn)程熱遷移類似,只需要加入docker的操作即可。基本的思路是在服務(wù)器上創(chuàng)建容器,然后暫停容器,查看運(yùn)行的輸出。在客戶端恢復(fù)容器之后查看輸出,如果運(yùn)行的輸出是緊接服務(wù)器輸出即說明熱遷移成功。整個(gè)過程都發(fā)生在服務(wù)器的/home/container目錄下,客戶端將服務(wù)器的/home/container目錄掛載到本地的/home/container下。
- 服務(wù)器端
(1)首先使用docker創(chuàng)建容器looper2,該程序遞增地輸出i,每個(gè)一秒輸出一次。
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'
報(bào)錯(cuò)Unable to find image 'busybox:latest' locally不用管,等待一段時(shí)間,會(huì)自動(dòng)下載依賴解決
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)等待輸出一段時(shí)間后中斷程序,中斷程序后會(huì)產(chǎn)生對(duì)應(yīng)的目錄,存儲(chǔ)容器的運(yùn)行狀態(tài),給恢復(fù)容器時(shí)使用。
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:在服務(wù)器輸入如下語句可恢復(fù)looper2運(yùn)行。(這里先不恢復(fù),若遷移未成功,再恢復(fù)重新遷移)
docker start looper2
- 客戶端
(1)使用docker恢復(fù)容器,注意這里–checkpoint-dir只需要指定到checkpoints目錄即可,不需要進(jìn)一步制定checkpoint2(已經(jīng)由–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)恢復(fù)容器后可以使用同樣的指令查看運(yùn)行結(jié)果。如下:
root@yqq2-HP-Pro-3348-MT:~# docker logs looper-clone
6
7
8
9
...
PS: 可以為一個(gè)容器創(chuàng)建多個(gè) checkpoint,每個(gè)起不同的名字就是了。列出已創(chuàng)建的checkpoint
docker checkpoint ls looper-clone
CHECKPOINT NAME
一些輔助命令:
(1)查看docker中所有的容器
docker ps -a(2)獲取某個(gè)docker容器的詳細(xì)信息
docker inspect looper2(3)啟動(dòng)
docker start looper2docker start 容器ID或容器名(4)停止
docker stop容器ID或容器名(5)重啟
docker restart容器ID或容器名 可以不管容器是否啟動(dòng),直接重啟容器(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版本,報(bào)
Error response from daemon: custom checkpointdir is not supported的錯(cuò)誤。如下:
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
據(jù)說是因?yàn)?docker 對(duì) docker start 命令中的 —-checkpoint-dir 選項(xiàng)不支持,可以手動(dòng)把 checkpoint 文件目錄加入到對(duì)應(yīng)容器的默認(rèn)位置 /var/lib/docker/containers/<CONTAINER_ID>/checkpoints/。(我沒試)
原理知識(shí)補(bǔ)充
- 1.CRIU
CRIU的功能的實(shí)現(xiàn)基本分為兩個(gè)過程,checkpoint和restore。在checkpoint過程,criu主要通過ptrace機(jī)制把一段特殊代碼動(dòng)態(tài)注入到dumpee進(jìn)程(待備份的程序進(jìn)程)并運(yùn)行,這段特殊代碼就實(shí)現(xiàn)了收集dumpee進(jìn)程的所有上下文信息,然后criu把這些上下文信息按功能分類存儲(chǔ)為一個(gè)個(gè)鏡像文件。在restore過程。criu解析checkpoint過程產(chǎn)生的鏡像文件,以此來恢復(fù)程序備份前的狀態(tài)沒,讓程序從備份前的狀態(tài)繼續(xù)運(yùn)行。