部署与更新无状态应用
Deployment 是最常用的工作负载控制器,适合无状态 API、Web 服务、消息消费者等"任意副本可互换"的应用。它管理 ReplicaSet,再由 ReplicaSet 维持 Pod 副本数。
本篇目标:能写出生产可用的 Deployment,理解滚动更新的每个步骤,掌握金丝雀暂停和版本回滚。

1. Deployment 与 ReplicaSet 的关系
Deployment(发布策略和版本历史)
└── ReplicaSet(某个版本的副本集合)
└── Pod(实际运行的容器)
日常只直接维护 Deployment。ReplicaSet 主要用于支撑滚动更新与回滚;不要把业务配置直接写成单独的 ReplicaSet。
2. 最小生产基线
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: learning
spec:
replicas: 3
# 发布超时:超过此时间未完成则自动报告 ProgressDeadlineExceeded
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 滚动期间最多有几个 Pod 不可用
maxSurge: 1 # 滚动期间最多多创建几个 Pod
selector:
matchLabels:
app.kubernetes.io/name: api
template:
metadata:
labels:
app.kubernetes.io/name: api
spec:
containers:
- name: api
image: registry.example.com/api:1.4.2
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
镜像应使用可追踪版本或不可变 digest,不建议生产长期使用 latest。
3. 滚动更新步骤推演
假设 replicas: 3,maxUnavailable: 1,maxSurge: 1,将镜像从 api:1.4.2 更新到 api:1.4.3:
初始状态:3 个旧 Pod Running
Step 1:创建一个新 Pod(maxSurge=1),总 Pod 数=4
Step 2:新 Pod Ready 后,删除一个旧 Pod(maxUnavailable=1),总 Pod 数=3
Step 3:重复 Step 1-2,直到全部替换为 3 个新 Pod
过程中可用副本数始终 ≥ replicas - maxUnavailable = 2
3.1 两种更新策略
| 策略 | 行为 | 适用场景 |
|---|---|---|
RollingUpdate(默认) | 逐步替换,保证可用副本数 | 绝大多数无状态服务 |
Recreate | 先删光旧 Pod,再创建新 Pod | 不能同时存在新旧版本的场景(如数据库迁移) |
# Recreate:短暂完全不可用,但避免新旧同时运行
strategy:
type: Recreate
4. 观察发布
kubectl apply -f deployment.yaml
kubectl rollout status deployment/api -n learning --timeout=5m
kubectl get deployment,replicaset,pods -n learning -l app.kubernetes.io/name=api
kubectl rollout history deployment/api -n learning
rollout status 应进入发布流水线。它超时或失败时(ProgressDeadlineExceeded),先检查新 Pod 的事件、日志和探针,而不是立即重复 apply。
5. 更新与回滚
# 测试环境快速更新镜像;生产应通过 Git 修改清单
kubectl set image deployment/api api=registry.example.com/api:1.4.3 -n learning
kubectl rollout status deployment/api -n learning
# 回滚到上一个可用 Revision
kubectl rollout undo deployment/api -n learning
# 回滚到指定版本
kubectl rollout undo deployment/api -n learning --to-revision=3
回滚只回滚 Deployment 模板,不能自动回滚数据库迁移、外部 API 副作用或已删除的数据。涉及兼容性变更时,应先设计向前/向后兼容的发布方案。
6. 金丝雀发布:pause 与 resume
rollout pause 让 Deployment 暂停在"部分更新"的状态,适合验证金丝雀 Pod:
# 1. 更新镜像
kubectl set image deployment/api api=registry.example.com/api:1.4.3 -n learning
# 2. 创建第一个新 Pod 后立即暂停
kubectl rollout pause deployment/api -n learning
# 3. 验证金丝雀 Pod 的日志、指标和业务行为
kubectl get pods -n learning -l app.kubernetes.io/name=api
kubectl logs <new-pod> -n learning
# 4a. 验证通过:继续滚动
kubectl rollout resume deployment/api -n learning
kubectl rollout status deployment/api -n learning
# 4b. 验证失败:回滚
kubectl rollout undo deployment/api -n learning
pause 之后别忘了 resume
rollout pause 后 Deployment 会一直停在当前状态不再推进。如果 pause 超过 progressDeadlineSeconds,会触发 ProgressDeadlineExceeded 的 false positive 告警。金丝雀验证完成后务必执行 resume 或 undo。
7. 常见异常
| 现象 | 先检查 |
|---|---|
ProgressDeadlineExceeded | 新 Pod 的镜像、事件、readinessProbe、资源与调度情况 |
| 新旧 Pod 长时间并存 | maxUnavailable / maxSurge、终止优雅退出、PDB |
| 副本数达不到目标 | Node 资源、配额、污点、镜像拉取和 HPA |
| Service 无后端 | Pod labels 是否匹配 Service selector,readiness 是否成功 |
CrashLoopBackOff 发布后立即出现 | 新镜像启动失败,logs --previous 查看崩溃原因,立即回滚 |
8. 练习
练习 A
- 创建一个 Deployment(3 副本,
nginx:1.25-alpine),用rollout history确认初始版本 - 更新镜像到
nginx:1.27-alpine,在另一个终端kubectl get pods -w观察滚动过程 - 一次性回滚两个版本:
kubectl rollout undo --to-revision=1
练习 B
- 再次更新镜像,但在
rollout status进行中执行kubectl rollout pause - 确认新 Pod 已创建但旧 Pod 未被删除(验证 pause 效果)
kubectl rollout resume恢复,确认发布完成
验收清单
- 能解释 Deployment、ReplicaSet 与 Pod 的关系
- 能口述
maxUnavailable和maxSurge在滚动更新中的每一步行为 - 会用
rollout status、history与undo(包括指定版本回滚) - 会用
rollout pause/resume做金丝雀验证 - 知道回滚不等于回滚外部数据副作用
- 发布前会检查镜像版本、资源、探针和副本策略
下一篇:运行有状态应用。