OpenKruise原地升级
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
pod中spec部分可修改内容很有限。
步骤2:设置conditionType InPlaceUpdateReady false来摘流(SidecarSet除外)
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
手动触发原地升级
修改Pod镜像版本(从nginx:1.9改成nginx:1.10)
kubectl edit pod nginx-deployment-74fb98df8b-92r6n
业务容器重建了,pause容器没有重建
确认新容器使用的镜像是nginx:1.10