跳到主要内容

部署与更新无状态应用

Deployment 是最常用的工作负载控制器,适合无状态 API、Web 服务、消息消费者等"任意副本可互换"的应用。它管理 ReplicaSet,再由 ReplicaSet 维持 Pod 副本数。

本篇目标:能写出生产可用的 Deployment,理解滚动更新的每个步骤,掌握金丝雀暂停和版本回滚。

Kubernetes Deployment 与 ReplicaSet 发布关系


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

  1. 创建一个 Deployment(3 副本,nginx:1.25-alpine),用 rollout history 确认初始版本
  2. 更新镜像到 nginx:1.27-alpine,在另一个终端 kubectl get pods -w 观察滚动过程
  3. 一次性回滚两个版本:kubectl rollout undo --to-revision=1

练习 B

  1. 再次更新镜像,但在 rollout status 进行中执行 kubectl rollout pause
  2. 确认新 Pod 已创建但旧 Pod 未被删除(验证 pause 效果)
  3. kubectl rollout resume 恢复,确认发布完成

验收清单

  • 能解释 Deployment、ReplicaSet 与 Pod 的关系
  • 能口述 maxUnavailable 和 maxSurge 在滚动更新中的每一步行为
  • 会用 rollout status、history 与 undo(包括指定版本回滚)
  • 会用 rollout pause/resume 做金丝雀验证
  • 知道回滚不等于回滚外部数据副作用
  • 发布前会检查镜像版本、资源、探针和副本策略

下一篇:运行有状态应用。