滚动更新、回退、蓝绿、金丝雀
目标
能够调整 Deployment 的发布参数,累积修订版本并回滚到指定位置,还能只用标签、选择器和副本数构建蓝绿发布与金丝雀发布。
为什么重要
理解 Deployment 会管理多个 ReplicaSet 后,其他内容便会顺理成章。更换镜像会创建新的 ReplicaSet,旧 ReplicaSet 则以副本数 0 保留。rollout undo 之所以能立即生效,是因为它并非重新拉取镜像,而是重新扩容已经存在的 ReplicaSet。如果将 revisionHistoryLimit 设为 0,这道安全网就会消失。
maxSurge 和 maxUnavailable 是“速度”与“安全性”之间的权衡。maxUnavailable: 0 会在部署期间维持可用 Pod 数量,但必须等待新 Pod Ready,因此速度较慢。而且,这项安全保障只有在配置 Readiness Probe 时才有意义——没有探针时,容器一启动便被视为 Ready。
无需额外 CRD,仅用标签即可构建蓝绿发布和金丝雀发布。差别在于 Service 选择器的限定范围。如果选择器还包含版本标签,就只会选择其中一方(蓝绿);如果只包含公共标签,两边都会被选中,流量会按副本数比例分配(金丝雀)。
步骤
- 创建命名空间
ckad-deploy和 Deploymentweb。镜像nginx:1.25,副本数 4。(容器名称会是nginx。) - 将
web的策略设为RollingUpdate,并设置maxSurge: 1、maxUnavailable: 0。 - 将
web的镜像升级为nginx:1.26,并为 Deployment 添加注解kubernetes.io/change-cause=nginx 1.26 으로 업데이트。 - 再次将
web的镜像升级为nginx:1.27,并将注解更新为kubernetes.io/change-cause=nginx 1.27 으로 업데이트。此时应至少存在 3 个 ReplicaSet。 - 将
web回滚到修订版本 2。回滚本身也是一次向前推进的变更,因此会新建修订版本 4,且该版本的镜像必须为nginx:1.26。 - 构建蓝绿发布。创建 Deployment
checkout-blue(副本数 2、标签app=checkout和version=blue、镜像nginx:1.26)以及checkout-green(副本数 2、标签app=checkout和version=green、镜像nginx:1.27);Servicecheckout(端口 80、targetPort 80)的选择器设为app=checkout+version=green。 - 构建金丝雀发布。创建 Deployment
pay-stable(副本数 9、标签app=pay和track=stable、镜像nginx:1.26)以及pay-canary(副本数 1、标签app=pay和track=canary、镜像nginx:1.27);Servicepay(端口 80、targetPort 80)的选择器只设置一个app=pay。 - 先对
web执行kubectl rollout pause,然后将镜像改为nginx:1.28,并将revisionHistoryLimit设为 3。由于处于暂停状态,不应创建新的 ReplicaSet。(不要恢复发布,副本数仍保持 4。)
参考
kubectl patch deployment web -n ckad-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'kubectl annotate deployment web -n ckad-deploy kubernetes.io/change-cause='...' --overwrite- 使用
kubectl rollout history deployment/web -n ckad-deploy和--revision=2查看各修订版本的内容。 - 常见错误 1:在
kubectl set image中使用 Deployment 名称,而非容器名称。应像deployment/web nginx=nginx:1.26这样使用컨테이너=이미지。 - 常见错误 2:在金丝雀发布的 Service 选择器中加入
track。这样只会选择一方,变成蓝绿发布而非金丝雀发布。 - 第 8 步必须先执行
pause才有意义。顺序相反时,发布已经开始。
创建命名空间与 Deployment
创建命名空间 ckad-deploy 和 Deployment web。镜像 nginx:1.25,副本数 4。(容器名称会是 nginx。)
为 kubectl create deployment 提供 --image 和 --replicas。确认所创建 Deployment 的标签和选择器——后续步骤会用到。
调整滚动更新参数
将 web 的策略设为 RollingUpdate,并设置 maxSurge: 1、maxUnavailable: 0。
这两个值位于 spec.strategy.rollingUpdate 下。可使用 kubectl edit 修改,也可通过 kubectl patch 提交 JSON。maxUnavailable: 0 表示部署期间仍维持原有数量。
更新镜像并记录 change-cause
将 web 的镜像升级为 nginx:1.26,并为 Deployment 添加注解 kubernetes.io/change-cause=nginx 1.26 으로 업데이트。
命令格式为 kubectl set image deployment/이름 컨테이너=이미지。必须准确填写容器名称。CHANGE-CAUSE 需要直接添加为 kubernetes.io/change-cause 注解。
再次升级以累积修订版本
再次将 web 的镜像升级为 nginx:1.27,并将注解更新为 kubernetes.io/change-cause=nginx 1.27 으로 업데이트。此时应至少存在 3 个 ReplicaSet。
修订版本会以 ReplicaSet 形式保留。使用 kubectl get rs -n <ns> 查看累积了多少个,并使用 kubectl rollout history 查看修订版本编号。
回滚到指定修订版本
将 web 回滚到修订版本 2。回滚本身也是一次向前推进的变更,因此会新建修订版本 4,且该版本的镜像必须为 nginx:1.26。
为 kubectl rollout undo 提供 --to-revision=번호。回滚不会让修订版本编号减小,而会分配新编号。使用 kubectl rollout history --revision=N 查看各修订版本使用的镜像。
蓝绿发布——切换 Service 选择器
构建蓝绿发布。创建 Deployment checkout-blue(副本数 2、标签 app=checkout 和 version=blue、镜像 nginx:1.26)以及 checkout-green(副本数 2、标签 app=checkout 和 version=green、镜像 nginx:1.27);Service checkout(端口 80、targetPort 80)的选择器设为 app=checkout + version=green。
两个 Deployment 具有一个公共标签和各自不同的版本标签。Service 选择器包含版本标签后,只有对应一方会进入 Endpoint。创建 Service 后只切换选择器,就是这种模式的全部要点。
金丝雀发布——按副本比例分配流量
构建金丝雀发布。创建 Deployment pay-stable(副本数 9、标签 app=pay 和 track=stable、镜像 nginx:1.26)以及 pay-canary(副本数 1、标签 app=pay 和 track=canary、镜像 nginx:1.27);Service pay(端口 80、targetPort 80)的选择器只设置一个 app=pay。
金丝雀发布反而要将 Service 选择器设得更宽泛,让两个 Deployment 的 Pod 都能进入。这样流量比例便由副本数比例决定。各 Deployment 仍应分别保留用于区分的标签。
综合:在暂停状态下汇总变更
先对 web 执行 kubectl rollout pause,然后将镜像改为 nginx:1.28,并将 revisionHistoryLimit 设为 3。由于处于暂停状态,不应创建新的 ReplicaSet。(不要恢复发布,副本数仍保持 4。)
先执行 kubectl rollout pause 后,后续模板变更会累积,不会立即创建新 ReplicaSet。顺序相反时,发布已经开始。同时设置保留旧 ReplicaSet 数量的字段。