容器热迁移是我这次毕业设计的题目,也和我目前在云厂商的工作比较接近。

技术基础

一开始的参考资料是 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 的作用:

  1. (热迁移源节点)watch 与热迁移有关的 CRD,根据其操作 kubelet,生成 checkpoint
  2. (热迁移源节点)把 checkpoint 文件传输到目标节点
  3. (热迁移目标节点)根据 checkpoint 文件生成镜像文件
  4. (热迁移目标节点)作为镜像服务器,直接在本地为容器运行时提供镜像(这样可以避免把 checkpoint 上传到其他镜像服务这一多余步骤)

可能的优化

不要使用 kubelet 生成 checkpoint,因为如此一来的时间线会是:

服务下线 -> 收集 checkpoint -> 传输 checkpoint -> 恢复 checkpoint -> 服务上线

这里必须先下线再收集,不然会有数据没有传输到目标节点

如果直接手动收集 checkpoint,利用上了 CRIU 的增量收集 checkpoint 的功能,就可以实现这样的时间线:

第一次收集 checkpoint -> 传输 -> 第二次收集 checkpoint -> 传输 -> ...... -> 服务下线 -> 最后一次收集 checkpoint -> 传输 -> 恢复 checkpoint -> 服务上线

当某次增量收集 checkpoint 获取到的文件小于某个阈值时,就可以服务下线了(可以认为最后一次传输耗时带来的服务下线时间是可以接受的了)

这样一来,通过收集传输的互相遮掩,可以大大减少服务的下线时间。