searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

基于Docker的容器迁移调研报告

2023-09-21 09:29:39
114
0

本文的重点是调研基于Docker的(无k8s集群的)容器迁移。在此之前,我们先简单了解下k8s集群环境中pod如何在节点间迁移。

一、k8s集群环境中pod的迁移

k8s集群环境中,如果某一节点需要停机维护,那么此时该节点上的pod应该如何处理呢?大概有如下三种处理方式:

  1. 默认迁移

基于Taint(污点)和Toleration(容忍)机制,在默认等待300s之后,k8s会自动将停机节点上的pod自动迁移到其他节点上。当然,默认的容忍时间是可以被修改的。

  1. 手动迁移

可以使用cordon、drain、uncordon三个命令实现节点的主动维护。

  • cordon:标记节点不可调度,后续新的pod不会被调度到此节点,但是该节点上的pod可以正常对外服务;
  • drain:驱逐节点上的pod至其他可调度节点;
  • uncordon:标记节点可调度;
  1. 平滑迁移

当pod 副本(replicas)大于1时,使用pdb(PodDisruptionBudget)可以做到平滑迁移,也就是主动驱逐保护,可以实现节点维护期间不低于一定数量的pod正常运行,从而保证服务的可用性。

二、基于Docker的容器迁移

由于没有k8s集群环境中的控制节点和调度功能,所以本文探讨的是两个节点间主动的容器迁移操作。最终通过两个脚本化的实例,来展示在node1节点通过脚本命令来一键迁移特定容器到node2节点。

目前Docker基本上都是基于CRIU(Checkpoint Restore in Userspace)来实现容器状态保存/恢复的功能。具体地,基于CRIU的Checkpoint/Restore功能,Docker可以冻结运行中的容器,将其状态保存为磁盘上的一系列文件,并可以后续基于这些文件恢复容器。这些功能针对的应用场景包括:

  • 重启主机,但是不需要重启容器
  • 为启动速度慢的应用提速,做法是启动后Checkpoint,以后从检查点启动容器
  • Rewinding进程到先前某个时刻

1、验证环境

  • 系统环境

操作系统为ctyunos23.01,内核版本是5.10

  • Docker版本

Docker的安装,本文不做讨论。本文中docker版本为20.10.12

  • criu版本

criu是很重要的软件包,在容器迁移中起到关键作用。调研过程中,最终选择了源码编译安装的最新的3.18版本;当然,前提是需要安装很多个编译依赖包。

tar xf criu-3.18.tar.gz

cd criu-3.18/

make install

需要提出的是,我开始是通过yum安装的3.16版本的criu,在跨节点迁移nginx容器过程中,在目的节点进行restore操作时,有如下的报错:

“Error response from daemon: OCI runtime restore failed: read unixpacket @->@: EOF: unknown”,所以最终更换了3.18的版本。

  • Docker特性

需要为Docker开启试验特性

更改配置后,需要重启docker服务:

systemctl daemon-reload

systemctl restart docker

  • 各节点ip地址

源节点,主机名:node1,ip:192.168.122.194

目的节点,主机名:node2,ip:192.168.122.81

2、跨主机的容器迁移

2.1、节点间免密操作

首先,节点间网络互通,是跨主机容器迁移的前提。

其次,源节点和目的节点间需要传输数据,采用scp命令;在源节点上远程执行目的节点的命令,用到ssh命令。这两个命令都需要输入目的节点的密码,为了方便,我们进行免密处理,有以下两种方式:

(1)在源节点上,ssh-keygen命令生成密钥对,通过ssh-copy-id命令将公钥传到目的节点。

(2)源节点上,yum安装sshpass包,通过sshpass命令进行免密操作,命令格式为:sshpass -p password command parameters

本文中采用方式(2)。

2.2、源节点创建并运行容器

以busybox容器迁移为例

docker run -d --name loop-n1 --security-opt seccomp=unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(($i+1)); sleep 1; done'

在源节点上运行busybox容器,实现每隔1s递增的输出一个数字的无限循环,返回的字符串为容器id。

其中,--security-opt seccomp=unconfined参数,关闭容器的(安全计算)seccomp限制。

docker logs loop-n1 -f可以看到输出数字在持续不断的递增

2.3、源节点创建checkpoint,并导出源容器镜像

docker checkpoint create loop-n1 cp1创建检查点cp1,容器会自动停止运行。

docker logs loop-n1查看最后的输出状态停留在“846”

通过commit和save命令,导出源容器镜像

2.4、传输源容器镜像到目的节点,并导入

结合sshpass命令,将上一步导出的源容器镜像免密传输到目的节点

在源节点上,结合sshpass命令,远程执行目的节点的导入镜像操作

2.5、目的节点创建而不运行对应容器

结合sshpass命令,远程执行目的节点上基于上一步导入镜像的创建容器操作,返回的字符串为目的节点上的容器id。

sshpass -p $pwd root@192.168.122.81 "docker create --name loop-n2 --security-opt seccomp=unconfined busybox:v1 /bin/sh -c 'i=0; while true; do echo $i; i=$(($i+1)); sleep 1; done'"

创建命令类似于2.2章节源节点上的命令,不同的是“create”,而不是“run -d”。

2.6、源节点checkpoint数据传输到目的节点,目的节点从checkpoint启动容器

传输checkpoint数据到目的节点:

sshpass -p $pwd scp -r 
/var/lib/docker/containers/c3a9ac86002b070277f589874cd3130b7fe066fdc481c218b4099780f34be129/checkpoints/cp1/  
root@192.168.122.81:/var/lib/docker/containers/9c24f5c4540782ac2161708c106d7e7c2cd10b751f4516d035578d19c7d12160/checkpoints

目的节点上从checkpoint检查点启动容器

2.7、验证迁移后的容器

登录到目的节点node2,查看容器运行情况

docker logs loop-n2 | head看到容器运行后,输出数字从“847”开始,是从源容器停止时的“断点处”延续执行的。

docker logs loop-n2 -f可以看到输出数字在持续不断的递增。

2.8、busybox容器迁移实例

基于2.2~2.6小节的步骤,我整合了一个完整脚本,来实现一键迁移busybox容器。

  • 在源节点上重新运行一个busybox容器:docker run -d --name loop-n1 --security-opt seccomp=unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(($i+1)); sleep 1; done';

或者

docker ps -a看到之前的busybox容器loop-n1还在,可以不用新建容器,直接启动容器即可。

  • 在目的节点上,停止busybox容器loop-n2(如果存在的话)。

  • 在源节点上执行~/migrate-loopbusybox脚本,即可完成容器迁移。

  • 在目的节点,通过docker logs loop-n2 -f可以看到容器从源容器停止时的“断点处”延续执行。

2.9、nginx容器迁移实例

一键迁移nginx容器的脚本,跟busybox基本相同。只是运行或者创建镜像时的参数不一样。

在源节点上运行nginx容器:

docker run -d --name nginx-zyc --security-opt seccomp=unconfined -v ~/v_nginx:/usr/share/nginx/html -p 8080:80 nginx

在目的节点上创建nginx容器:

docker create --name nginx-zyc --security-opt seccomp=unconfined -v ~/v_nginx:/usr/share/nginx/html -p 8080:80 nginx:v1

3、后记

通过本次调研尝试,基于CRIU的docker容器迁移基本可以实现。但是目前Docker依然将criu标记为实验性质的功能,存在一些兼容性问题,支持的热迁移功能也很有限。另外,可能并不是所有的容器应用都可以基于criu来实现Checkpoint/Restore功能,在使用中需要注意。

0条评论
0 / 1000
z****n
5文章数
0粉丝数
z****n
5 文章 | 0 粉丝
原创

基于Docker的容器迁移调研报告

2023-09-21 09:29:39
114
0

本文的重点是调研基于Docker的(无k8s集群的)容器迁移。在此之前,我们先简单了解下k8s集群环境中pod如何在节点间迁移。

一、k8s集群环境中pod的迁移

k8s集群环境中,如果某一节点需要停机维护,那么此时该节点上的pod应该如何处理呢?大概有如下三种处理方式:

  1. 默认迁移

基于Taint(污点)和Toleration(容忍)机制,在默认等待300s之后,k8s会自动将停机节点上的pod自动迁移到其他节点上。当然,默认的容忍时间是可以被修改的。

  1. 手动迁移

可以使用cordon、drain、uncordon三个命令实现节点的主动维护。

  • cordon:标记节点不可调度,后续新的pod不会被调度到此节点,但是该节点上的pod可以正常对外服务;
  • drain:驱逐节点上的pod至其他可调度节点;
  • uncordon:标记节点可调度;
  1. 平滑迁移

当pod 副本(replicas)大于1时,使用pdb(PodDisruptionBudget)可以做到平滑迁移,也就是主动驱逐保护,可以实现节点维护期间不低于一定数量的pod正常运行,从而保证服务的可用性。

二、基于Docker的容器迁移

由于没有k8s集群环境中的控制节点和调度功能,所以本文探讨的是两个节点间主动的容器迁移操作。最终通过两个脚本化的实例,来展示在node1节点通过脚本命令来一键迁移特定容器到node2节点。

目前Docker基本上都是基于CRIU(Checkpoint Restore in Userspace)来实现容器状态保存/恢复的功能。具体地,基于CRIU的Checkpoint/Restore功能,Docker可以冻结运行中的容器,将其状态保存为磁盘上的一系列文件,并可以后续基于这些文件恢复容器。这些功能针对的应用场景包括:

  • 重启主机,但是不需要重启容器
  • 为启动速度慢的应用提速,做法是启动后Checkpoint,以后从检查点启动容器
  • Rewinding进程到先前某个时刻

1、验证环境

  • 系统环境

操作系统为ctyunos23.01,内核版本是5.10

  • Docker版本

Docker的安装,本文不做讨论。本文中docker版本为20.10.12

  • criu版本

criu是很重要的软件包,在容器迁移中起到关键作用。调研过程中,最终选择了源码编译安装的最新的3.18版本;当然,前提是需要安装很多个编译依赖包。

tar xf criu-3.18.tar.gz

cd criu-3.18/

make install

需要提出的是,我开始是通过yum安装的3.16版本的criu,在跨节点迁移nginx容器过程中,在目的节点进行restore操作时,有如下的报错:

“Error response from daemon: OCI runtime restore failed: read unixpacket @->@: EOF: unknown”,所以最终更换了3.18的版本。

  • Docker特性

需要为Docker开启试验特性

更改配置后,需要重启docker服务:

systemctl daemon-reload

systemctl restart docker

  • 各节点ip地址

源节点,主机名:node1,ip:192.168.122.194

目的节点,主机名:node2,ip:192.168.122.81

2、跨主机的容器迁移

2.1、节点间免密操作

首先,节点间网络互通,是跨主机容器迁移的前提。

其次,源节点和目的节点间需要传输数据,采用scp命令;在源节点上远程执行目的节点的命令,用到ssh命令。这两个命令都需要输入目的节点的密码,为了方便,我们进行免密处理,有以下两种方式:

(1)在源节点上,ssh-keygen命令生成密钥对,通过ssh-copy-id命令将公钥传到目的节点。

(2)源节点上,yum安装sshpass包,通过sshpass命令进行免密操作,命令格式为:sshpass -p password command parameters

本文中采用方式(2)。

2.2、源节点创建并运行容器

以busybox容器迁移为例

docker run -d --name loop-n1 --security-opt seccomp=unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(($i+1)); sleep 1; done'

在源节点上运行busybox容器,实现每隔1s递增的输出一个数字的无限循环,返回的字符串为容器id。

其中,--security-opt seccomp=unconfined参数,关闭容器的(安全计算)seccomp限制。

docker logs loop-n1 -f可以看到输出数字在持续不断的递增

2.3、源节点创建checkpoint,并导出源容器镜像

docker checkpoint create loop-n1 cp1创建检查点cp1,容器会自动停止运行。

docker logs loop-n1查看最后的输出状态停留在“846”

通过commit和save命令,导出源容器镜像

2.4、传输源容器镜像到目的节点,并导入

结合sshpass命令,将上一步导出的源容器镜像免密传输到目的节点

在源节点上,结合sshpass命令,远程执行目的节点的导入镜像操作

2.5、目的节点创建而不运行对应容器

结合sshpass命令,远程执行目的节点上基于上一步导入镜像的创建容器操作,返回的字符串为目的节点上的容器id。

sshpass -p $pwd root@192.168.122.81 "docker create --name loop-n2 --security-opt seccomp=unconfined busybox:v1 /bin/sh -c 'i=0; while true; do echo $i; i=$(($i+1)); sleep 1; done'"

创建命令类似于2.2章节源节点上的命令,不同的是“create”,而不是“run -d”。

2.6、源节点checkpoint数据传输到目的节点,目的节点从checkpoint启动容器

传输checkpoint数据到目的节点:

sshpass -p $pwd scp -r 
/var/lib/docker/containers/c3a9ac86002b070277f589874cd3130b7fe066fdc481c218b4099780f34be129/checkpoints/cp1/  
root@192.168.122.81:/var/lib/docker/containers/9c24f5c4540782ac2161708c106d7e7c2cd10b751f4516d035578d19c7d12160/checkpoints

目的节点上从checkpoint检查点启动容器

2.7、验证迁移后的容器

登录到目的节点node2,查看容器运行情况

docker logs loop-n2 | head看到容器运行后,输出数字从“847”开始,是从源容器停止时的“断点处”延续执行的。

docker logs loop-n2 -f可以看到输出数字在持续不断的递增。

2.8、busybox容器迁移实例

基于2.2~2.6小节的步骤,我整合了一个完整脚本,来实现一键迁移busybox容器。

  • 在源节点上重新运行一个busybox容器:docker run -d --name loop-n1 --security-opt seccomp=unconfined busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(($i+1)); sleep 1; done';

或者

docker ps -a看到之前的busybox容器loop-n1还在,可以不用新建容器,直接启动容器即可。

  • 在目的节点上,停止busybox容器loop-n2(如果存在的话)。

  • 在源节点上执行~/migrate-loopbusybox脚本,即可完成容器迁移。

  • 在目的节点,通过docker logs loop-n2 -f可以看到容器从源容器停止时的“断点处”延续执行。

2.9、nginx容器迁移实例

一键迁移nginx容器的脚本,跟busybox基本相同。只是运行或者创建镜像时的参数不一样。

在源节点上运行nginx容器:

docker run -d --name nginx-zyc --security-opt seccomp=unconfined -v ~/v_nginx:/usr/share/nginx/html -p 8080:80 nginx

在目的节点上创建nginx容器:

docker create --name nginx-zyc --security-opt seccomp=unconfined -v ~/v_nginx:/usr/share/nginx/html -p 8080:80 nginx:v1

3、后记

通过本次调研尝试,基于CRIU的docker容器迁移基本可以实现。但是目前Docker依然将criu标记为实验性质的功能,存在一些兼容性问题,支持的热迁移功能也很有限。另外,可能并不是所有的容器应用都可以基于criu来实现Checkpoint/Restore功能,在使用中需要注意。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0