本文介绍如何使用滚动更新将运行中的 Deployment 更新到新版本。滚动更新会逐步用新 Pod 替换旧 Pod,因此你的应用在整个更新过程中保持可用。
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
你需要一个已存在的 Deployment。如果你还没有, 可以按照使用 Deployment 运行无状态应用中的说明创建一个 nginx Deployment:
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
验证该 Deployment 运行了两个 Pod:
kubectl get deployment nginx-deployment
输出类似于这样:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 10s
对 Deployment 的 .spec.template 字段的任何更改都会触发滚动更新。
Kubernetes 会使用更新后的配置创建新 Pod,并逐步终止旧 Pod。
kubectl apply 进行更新 你可以通过编辑 Deployment 清单文件并应用更改来触发滚动更新。 当你将清单文件保存在版本控制中时,这种方法效果很好。
将当前 Deployment 导出到本地文件:
kubectl get deployment nginx-deployment -o yaml > /tmp/nginx-deployment.yaml
编辑 /tmp/nginx-deployment.yaml,将 .spec.template.spec.containers[0].image
从 nginx:1.14.2 改为 nginx:1.16.1。
在应用之前,将本地更改与集群状态进行比较:
kubectl diff -f /tmp/nginx-deployment.yaml
输出类似于这样:
diff -u -N /tmp/LIVE/apps.v1.Deployment.default.nginx-deployment /tmp/MERGED/apps.v1.Deployment.default.nginx-deployment
--- /tmp/LIVE/apps.v1.Deployment...
+++ /tmp/MERGED/apps.v1.Deployment...
@@ -29,7 +29,7 @@
containers:
- - image: nginx:1.14.2
+ - image: nginx:1.16.1
name: nginx
应用更新后的清单:
kubectl apply -f /tmp/nginx-deployment.yaml
要在不编辑清单文件的情况下更新容器镜像,请使用 kubectl set image:
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
输出类似于这样:
deployment.apps/nginx-deployment image updated
验证镜像已更新:
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].image}'
输出类似于这样:
nginx:1.16.1
使用 kubectl rollout status 来观察滚动更新的进度:
kubectl rollout status deployment/nginx-deployment
输出类似于这样:
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 2 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 2 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
上线完成后,验证该 Deployment:
kubectl get deployment nginx-deployment
输出类似于这样:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 2m
你可以暂停上线过程,以便检查部分更新或将多个更改合并到一次上线中。
kubectl rollout pause deployment/nginx-deployment
输出类似于这样:
deployment.apps/nginx-deployment paused
当上线暂停时,你可以进行其他更改。这些更改在你恢复上线之前不会触发新的上线:
kubectl set image deployment/nginx-deployment nginx=nginx:1.17.0
你可以对暂停的 Deployment 进行多次更改。当你恢复上线时,Kubernetes 会将所有更改一起应用。
kubectl rollout resume deployment/nginx-deployment
输出类似于这样:
deployment.apps/nginx-deployment resumed
验证上线是否完成:
kubectl rollout status deployment/nginx-deployment
Deployment 支持两种更新策略类型:
对于 RollingUpdate 策略,以下参数控制 Kubernetes 执行更新的方式:
| 参数 | 控制内容 | 默认值 | 示例 |
|---|---|---|---|
maxUnavailable | 更新期间不可用 Pod 的最大数量 | 25% | 1 或 25% |
maxSurge | 更新期间允许创建的额外 Pod 的最大数量 | 25% | 1 或 25% |
maxUnavailable 和 maxSurge 接受绝对数值或百分比。Kubernetes 基于所需副本数计算百分比,
对 maxUnavailable 向下取整,对 maxSurge 向上取整。
要配置这些参数,请使用 kubectl patch:
kubectl patch deployment nginx-deployment -p \
'{"spec":{"strategy":{"rollingUpdate":{"maxUnavailable":"25%","maxSurge":"25%"}}}}'
你也可以在 Deployment 清单的 .spec.strategy.rollingUpdate 下设置这些字段。有关详细示例,请参阅 Deployment
概念文档中的最大不可用数量和最大峰值。
如果上线过程在 .spec.progressDeadlineSeconds(默认:600 秒)指定的时间内没有进展,Kubernetes 会将
Deployment 的 Progressing 状况标记为 False。你可以通过描述 Deployment 来检查此状况:
kubectl describe deployment nginx-deployment
在输出的 Conditions 部分查找 Progressing 状况。停滞的上线通常表明新 Pod 启动失败。输出的
Events 部分可以帮助诊断问题。
如果新版本引入了问题,你可以回滚到之前的版本。
kubectl rollout history deployment/nginx-deployment
输出类似于这样:
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
CHANGE-CAUSE 列显示每个版本对应时刻 kubernetes.io/change-cause 注解的值。
此注解不会被自动设置,但如果你使用自动化方案来管理 Deployment,你所使用的工具可能会将一些文本写入该注解。
kubectl rollout undo deployment/nginx-deployment
输出类似于这样:
deployment.apps/nginx-deployment rolled back
kubectl rollout undo deployment/nginx-deployment --to-revision=1
验证回滚是否完成:
kubectl rollout status deployment/nginx-deployment
Deployment 的版本历史存储在其控制的 ReplicaSet 中。默认情况下,Kubernetes 会保留 10 个旧
ReplicaSet。你可以通过在 Deployment 清单中设置 .spec.revisionHistoryLimit 来更改此限制。
将其设置为 0 将完全禁用回滚。
删除该 Deployment:
kubectl delete deployment nginx-deployment