Deployment 应用发布
Deployment 是最常用的工作负载控制器,适合无状态 API、Web 服务、消息消费者等"任意副本可互换"的应用。它管理 ReplicaSet,再由 ReplicaSet 维持 Pod 副本数,并为滚动更新、回滚和金丝雀发布提供版本化支持。
本篇目标:能写出生产可用的 Deployment,理解 Deployment 与 ReplicaSet 的分层架构,掌握 RollingUpdate 与 Recreate 两种策略,会用 rollout 做版本控制与回滚。

1. Deployment 与 ReplicaSet 架构设计
Deployment(发布策略和版本历史)
└── ReplicaSet(某个版本的副本集合)
└── Pod(实际运行的容器)
日常只直接维护 Deployment。ReplicaSet 主要用于支撑滚动更新与回滚:
- 每次模板变更(镜像、环境变量、资源)会创建新的 ReplicaSet,旧 ReplicaSet 保留用于回滚;
kubectl rollout history看到的 Revision 就是这些 ReplicaSet 的版本记录;- 不要把业务配置直接写成单独的 ReplicaSet。
kubectl get deployment,replicaset,pods -n learning -l app.kubernetes.io/name=api
kubectl rollout history deployment/api -n learning
2. 无状态应用的发布策略
2.1 两种更新策略
| 策略 | 行为 | 适用场景 |
|---|---|---|
RollingUpdate(默认) | 逐步替换,保证可用副本数 | 绝大多数无状态服务 |
Recreate | 先删光旧 Pod,再创建新 Pod | 不能同时存在新旧版本的场景(如数据库迁移) |
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 滚动期间最多有几个 Pod 不可用
maxSurge: 1 # 滚动期间最多多创建几个 Pod
# Recreate:短暂完全不可用,但避免新旧同时运行
strategy:
type: Recreate
2.2 滚动更新步骤推演
假设 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. 版本控制与运维操作
3.1 观察发布
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。
3.2 更新与回滚
# 测试环境快速更新镜像;生产应通过 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 副作用或已删除的数据。涉及兼容性变更时,应先设计向前/向后兼容的发布方案。
3.3 金丝雀发布: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
想把金丝雀规模锁定为恰好 1 个新 Pod,可先把 maxSurge 收紧为 1、maxUnavailable 置 0,再触发更新并 pause(详见第 21 章《生产实践》的组合策略)。
4. 生产级 Deployment YAML 详解
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: learning
labels:
app.kubernetes.io/name: api
spec:
replicas: 3
# 发布超时:超过此时间未完成则自动报告 ProgressDeadlineExceeded
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
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
readinessProbe: # 发布时决定何时把新 Pod 接入流量
httpGet:
path: /ready
port: 8080
livenessProbe: # 确认需要时才配置
httpGet:
path: /healthz
port: 8080
生产基线要点:
- 镜像使用可追踪版本或不可变 digest,不建议生产长期使用
latest; spec.selector.matchLabels必须匹配 Pod 模板标签,且创建后通常不可随意修改;- resources 来自压测数据(第 14 章),readinessProbe 是所有接收流量的服务必须项(第 15 章);
- 生产发布通过 Git 修改清单,由 CI 或 GitOps 工具交付。
5. 常见异常
| 现象 | 先检查 |
|---|---|
ProgressDeadlineExceeded | 新 Pod 的镜像、事件、readinessProbe、资源与调度情况 |
| 新旧 Pod 长时间并存 | maxUnavailable / maxSurge、终止优雅退出、PDB |
| 副本数达不到目标 | Node 资源、配额、污点、镜像拉取和 HPA |
| Service 无后端 | Pod labels 是否匹配 Service selector,readiness 是否成功 |
CrashLoopBackOff 发布后立即出现 | 新镜像启动失败,logs --previous 查看崩溃原因,立即回滚 |
6. 练习
练习 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恢复,确认发布完成- 对比
kubectl get rs里新旧 ReplicaSet 的 DESIRED 变化,理解版本历史机制
下一篇:StatefulSet 有状态服务。