深色模式
Deployment 滚动更新与回滚
摘要:本文演示 Deployment 的完整发布流程:更新镜像触发滚动更新、用 maxSurge/maxUnavailable 控制节奏、暂停与继续、查看修订历史并回滚到指定版本。附一份可直接 apply 的 YAML。
适用环境
- 可用 K8s 集群 +
kubectl - 至少 2 个可用节点(单节点也能跑,但看不到跨节点效果)
- 示例镜像:
nginx:1.25-alpine→nginx:1.27-alpine
操作步骤
一、创建 Deployment
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 4
revisionHistoryLimit: 10
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 可超出期望副本数的上限
maxUnavailable: 0 # 更新期间允许不可用的副本数
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 801
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bash
kubectl apply -f web.yaml
kubectl rollout status deploy/web1
2
2
二、触发滚动更新
三种方式任选:
bash
kubectl set image deploy/web nginx=nginx:1.27-alpine
kubectl edit deploy/web # 手动改 image
kubectl apply -f web.yaml # 改文件后重新 apply1
2
3
2
3
实时观察:
bash
kubectl rollout status deploy/web
kubectl get rs -l app=web # 新旧 ReplicaSet 的副本此消彼长
kubectl get pod -l app=web -w1
2
3
2
3
三、更新策略参数怎么配
| 组合 | 效果 | 适用 |
|---|---|---|
maxSurge: 1, maxUnavailable: 0 | 先起新后删旧,零中断,需额外资源 | 生产推荐 |
maxSurge: 25%, maxUnavailable: 25% | 默认值,速度快 | 资源紧张 |
maxSurge: 0, maxUnavailable: 1 | 先删旧后起新,会短暂少一个副本 | 资源严重不足 |
注意
maxSurge: 0 且 maxUnavailable: 0 是非法配置,会导致 Pod 无法替换、更新卡死。
四、暂停与继续更新
bash
kubectl rollout pause deploy/web
# 此时可以连续做多次修改,只会积累不会触发滚动
kubectl set image deploy/web nginx=nginx:1.27-alpine
kubectl rollout resume deploy/web1
2
3
4
2
3
4
适合「改镜像 + 改环境变量 + 改资源」要一次性生效的场景。
五、查看历史与回滚
bash
kubectl rollout history deploy/web
kubectl rollout history deploy/web --revision=2 # 看某一版的详情
kubectl rollout undo deploy/web # 回滚到上一版
kubectl rollout undo deploy/web --to-revision=1 # 回滚到指定版本1
2
3
4
2
3
4
危险
kubectl rollout undo 会立即触发一次新的滚动更新。若新版本已造成数据格式变更,回滚不能修复已写入的数据。涉及数据库变更的发布必须先做向前兼容。
六、就绪门:确保新版真的可用
滚动更新只看 Pod 是否 Ready。如果容器起来但服务还没初始化完,旧 Pod 已被杀掉,就会出现中断。务必配 readinessProbe(见探针相关章节):
yaml
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 51
2
3
4
5
6
2
3
4
5
6
七、卡住的更新如何终止
bash
kubectl rollout status deploy/web --timeout=60s
# 若新版本起不来,直接回滚
kubectl rollout undo deploy/web
# 或设置进度超时自动标记失败
kubectl patch deploy/web -p '{"spec":{"progressDeadlineSeconds":120}}'1
2
3
4
5
2
3
4
5
验证
- [ ]
kubectl rollout status返回successfully rolled out - [ ] 更新过程中
curl服务始终可用(零中断组合下) - [ ]
rollout history能看到多个 revision - [ ]
undo后 Pod 镜像回到旧版本:kubectl get pod -o jsonpath='{.items[0].spec.containers[0].image}'
常见坑
- 更新一直不完成:新 Pod 起不来(镜像错、探针失败),
rollout status会一直等,配progressDeadlineSeconds让它自动失败。 - 回滚后又变回新版本:有人执行了
apply覆盖了回滚结果,或 GitOps 工具自动同步回仓库版本。 revisionHistoryLimit: 0导致无法回滚:历史 ReplicaSet 全被清理,rollout history为空,不要用 0。- 更新期间服务 502:未配 readinessProbe 或
maxUnavailable设得太大。 - 改了 ConfigMap 但 Pod 没更新:ConfigMap 变更不会自动触发滚动更新,需手动
kubectl rollout restart deploy/web。