OpenKruise原地升级

发布时间 2023-06-12 10:56:15作者: 王景迁

OpenKruise master

为什么使用原地升级

原地升级含义:更新容器镜像,只升级容器,不触发Pod重建
原地升级优势:节省了调度、CNI和CSI、大部分拉取镜像耗时
针对k8s集群大量Pod升级场景,减小k8s集群压力。
在OpenKruise中支持原地升级的workload/controller是CloneSet、Advanced StatefulSet、Advanced DaemonSet、SidecarSet。

原地升级流程

步骤1:判断是否支持原地升级容器
pkg/controller/daemonset/daemonset_update.go
canPodInPlaceUpdate方法

pkg/controller/daemonset/daemonset_util.go
ContainsReadinessGate方法

1.Pod spec要有ReadinessGates且conditionType是InPlaceUpdateReady
2.Pod上修改的是annotation/lables或者容器镜像或者基于annotation/labels生成的env
步骤2:设置conditionType InPlaceUpdateReady false来切流
Pod是否Ready除了看容器是否Ready之外,k8s 1.12新增了readinessGates conditionType来自定义控制Pod Ready。
Pod notReady后kube-controller-manager中EndpointController更新endpoints来触发kube-proxy摘流。
步骤3:优雅等待升级
确保摘流完成
pkg/controller/cloneset/sync/cloneset_update.go
Update方法

从Pod注解apps.kruise.io/inplace-update-grace中获取优雅升级等待时间。
步骤4:kruise-manager更新Pod image等字段
步骤5:kubelet或者kruise-daemon停止容器
针对更新镜像场景,kubelet停止容器;针对更新env场景,kruise-daemon停止容器。
kubelet在创建Pod.spec.containers容器时会计算hash值,镜像更新后hash值变化,重拉容器。
步骤6:kubelet拉起新容器
步骤7:kruise-manager根据imageId是否更新来确认原地升级是否已完成
pkg/control/sidecarcontrol/sidecarset_control.go
IsSidecarContainerUpdateCompleted函数

之所以不使用imageName来判断,是因为kubelet通过CRI来获取容器镜像信息,存在不同镜像名字镜像id相同的情况。
步骤8:kruise-manager设置condition InPlaceUpdateReady true后kubelet设置Pod Ready

参考资料

揭秘:如何为 Kubernetes 实现原地升级
OpenKruise-原地升级
OpenKruise 源码剖析之原地升级