容器热迁移是我这次毕业设计的题目,也和我目前在云厂商的工作比较接近。
技术基础
一开始的参考资料是 CIRU 的官网和相关的一些论文,但是后来看到了 Kubernetes 的 2022 年的一篇官方博客,发现 checkpoint 功能已经在 1.30 版本稳定了,我将以此功能为基础实现容器热迁移。
Kubernetes 的节点组件 kubelet 已经实现了对容器生成 checkpoint:
curl -X POST "https://localhost:10250/checkpoint/namespace/podId/container"
这样的操作可以在 var/lib/kubelet/checkpoints/checkpoint-<pod-name>_<namespace-name>-<container-name>-<timestamp>.tar
生成一个 tar 包,之后可以利用这个 tar 包恢复这个容器。
在容器排障的时候可以把这个容器在 kubernetes 集群之外恢复,再进入到节点之中检查。
而在容器热迁移的场景下,则可以通过工具 buildah 将这个 tar 包转换成容器镜像格式(虽然不是标准格式,但是 CRI-O 可以识别),再把这个镜像上传到镜像仓库中。之后需要恢复这个容器的时候,就可以把 pod container 的 image 字段填上这个镜像的地址。
设计方案
这里就可以利用上述的功能特性实现在 Kubernetes 集群环境中热迁移容器了。
需要的组件:
- 集群中多副本的 migration controller
- 每个节点上一个 migration agent(可以以 systemd 直接部署,也可以用 daemonset 部署)
- (optional) 控制面上的调度器插件
controller 主要用于调谐可以热迁移的 pod 以及与热迁移有关的 CRD,功能比较老生常谈。
这里主要讲 agent 的作用:
- (热迁移源节点)watch 与热迁移有关的 CRD,根据其操作 kubelet,生成 checkpoint
- (热迁移源节点)把 checkpoint 文件传输到目标节点
- (热迁移目标节点)根据 checkpoint 文件生成镜像文件
- (热迁移目标节点)作为镜像服务器,直接在本地为容器运行时提供镜像(这样可以避免把 checkpoint 上传到其他镜像服务这一多余步骤)
可能的优化
不要使用 kubelet 生成 checkpoint,因为如此一来的时间线会是:
服务下线 -> 收集 checkpoint -> 传输 checkpoint -> 恢复 checkpoint -> 服务上线
这里必须先下线再收集,不然会有数据没有传输到目标节点
如果直接手动收集 checkpoint,利用上了 CRIU 的增量收集 checkpoint 的功能,就可以实现这样的时间线:
第一次收集 checkpoint -> 传输 -> 第二次收集 checkpoint -> 传输 -> ...... -> 服务下线 -> 最后一次收集 checkpoint -> 传输 -> 恢复 checkpoint -> 服务上线
当某次增量收集 checkpoint 获取到的文件小于某个阈值时,就可以服务下线了(可以认为最后一次传输耗时带来的服务下线时间是可以接受的了)
这样一来,通过收集和传输的互相遮掩,可以大大减少服务的下线时间。