摘要:Deployment 是生产环境中最常用的工作负载控制器。本文详解 Deployment 如何通过 ReplicaSet 管理 Pod 副本,实现滚动更新、版本回滚、弹性伸缩和自愈能力,并深入分析其内部工作机制。
一、为什么不直接创建 Pod?
直接创建 Pod(裸 Pod)存在四个核心问题:Pod 终止后无法自动重建、扩容需要手动逐一创建、版本更新需要手动删旧建新且有停机风险、回滚需要手动操作且容易出错。Deployment 通过声明式管理解决了所有这些问题。
使用 Deployment
Pod 终止 → 自动重建
扩容 → 一条命令完成
更新 → 滚动更新,零停机
回滚 → 一键回滚任意版本
直接管理 Pod
Pod 终止 → 无自动重建
扩容 → 手动逐一创建
更新 → 删旧建新,有停机
回滚 → 手动操作,易出错
上图对比了直接管理 Pod 与使用 Deployment 的差异。Deployment 控制器持续监听实际状态与期望状态的差异,自动执行 Pod 的创建、删除和更新。
二、Deployment → ReplicaSet → Pod 层级关系
Kubernetes 通过三级资源层级管理应用副本:Deployment 管理 ReplicaSet,ReplicaSet 管理 Pod。用户只需操作 Deployment,底层由控制器自动协调。
Deployment
ReplicaSet
Pod 1
Pod 2
Pod 3
上图展示了 Deployment 的三级资源层级。Deployment 通过 ownerReferences 关联 ReplicaSet,ReplicaSet 同样通过 ownerReferences 关联 Pod,形成清晰的所有权链。
各层职责对比
| 资源 | 核心职责 | 用户是否直接操作 |
|---|---|---|
| Deployment | 管理 ReplicaSet 的创建和版本;控制滚动更新策略;支持版本回滚;记录部署历史 | 是(主要操作对象) |
| ReplicaSet | 确保指定数量的 Pod 副本在运行;Pod 终止后自动创建新副本;多余 Pod 自动删除 | 否(由 Deployment 管理) |
| Pod | 运行实际的应用容器 | 否(由 ReplicaSet 管理) |
注意:不要直接创建或修改 ReplicaSet,应始终通过 Deployment 管理。直接操作 ReplicaSet 会导致 Deployment 控制器状态不一致。
ReplicaSet 控制循环
ReplicaSet 控制器持续执行以下逻辑:
- 通过
spec.selector标签选择器查找匹配的 Pod - 对比当前 Pod 数量与
spec.replicas期望值 - Pod 数量不足 → 根据 Pod 模板创建新 Pod
- Pod 数量过多 → 按策略删除多余 Pod(优先删除 Pending/未调度的 Pod)
三、创建 Deployment
3.1 YAML 示例
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
minReadySeconds: 5
selector:
matchLabels:
app: nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: nginx
version: v1
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "250m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 10
3.2 YAML 字段详解
Deployment spec 核心字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
spec.replicas |
int | 1 | 期望的 Pod 副本数量 |
spec.selector |
object | 必填 | 标签选择器,标识 Deployment 管理的 Pod。创建后不可修改 |
spec.template |
object | 必填 | Pod 模板,定义 Pod 的 spec。模板的 labels 必须与 selector 匹配 |
spec.strategy |
object | RollingUpdate | 更新策略,支持 RollingUpdate 和 Recreate |
spec.revisionHistoryLimit |
int | 10 | 保留的历史 ReplicaSet 数量,用于回滚 |
spec.progressDeadlineSeconds |
int | 600 | 部署进度截止时间(秒),超时则标记为 Failed |
spec.minReadySeconds |
int | 0 | Pod 就绪后等待多少秒才视为 Available。用于确保新 Pod 稳定运行后再继续更新 |
spec.paused |
bool | false | 是否暂停 Deployment,暂停后修改不会触发滚动更新 |
strategy 字段
| 字段 | 说明 |
|---|---|
strategy.type |
RollingUpdate(默认):逐步替换,零停机;Recreate:先全部终止再创建,有停机 |
strategy.rollingUpdate.maxSurge |
更新期间允许超出 replicas 的 Pod 数量(数字或百分比) |
strategy.rollingUpdate.maxUnavailable |
更新期间允许不可用的 Pod 最大数量(数字或百分比) |
3.3 创建与验证
bash
# 创建 Deployment
kubectl apply -f deployment.yaml
# 查看 Deployment 状态
kubectl get deployment nginx-deployment
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx-deployment 3/3 3 3 30s
# 查看创建的 ReplicaSet
kubectl get rs -l app=nginx
# NAME DESIRED CURRENT READY AGE
# nginx-deployment-5d66cc795f 3 3 3 30s
# 查看 Pod
kubectl get pods -l app=nginx -o wide
3.4 资源命名规则
执行 kubectl apply 后,Deployment 控制器自动创建 ReplicaSet,ReplicaSet 再创建指定数量的 Pod:
nginx-deployment
nginx-deployment-5d66cc795f
...-5d66cc795f-abc12
...-5d66cc795f-def34
...-5d66cc795f-ghi56
上图展示了资源命名的层级关系。ReplicaSet 名称 = Deployment 名 + Pod 模板 hash(5d66cc795f);Pod 名称 = ReplicaSet 名 + 随机后缀。Pod 模板 hash 确保模板变更时创建新的 ReplicaSet。
四、滚动更新(Rolling Update)
滚动更新是 Deployment 的核心能力,通过逐步替换旧版 Pod 为新版 Pod 来实现零停机更新。
4.1 滚动更新流程
当更新镜像版本(如 nginx:1.24 → nginx:1.25)时,Deployment 控制器创建新 ReplicaSet 并逐步扩容,同时缩容旧 ReplicaSet。整个过程中始终保持足够的 Pod 对外提供服务。
ReplicaSet v2 ReplicaSet v1 Deployment ReplicaSet v2 ReplicaSet v1 Deployment 初始:3 Pod (nginx:1.24) Pod 4 Ready Pod 5 Ready Pod 6 Ready 0 Pod(保留用于回滚) 3 Pod (nginx:1.25) 创建新 ReplicaSet 启动 Pod 4 缩容:终止 Pod 1 启动 Pod 5 缩容:终止 Pod 2 启动 Pod 6 缩容:终止 Pod 3
上图展示了滚动更新的完整时序:新 Pod 就绪后才缩减旧 Pod,保证服务不中断。
4.2 更新策略配置
yaml
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
常见策略组合及适用场景:
| maxSurge | maxUnavailable | 特点 | 适用场景 |
|---|---|---|---|
| 1 | 0 | 保守:始终保持完整服务能力,更新较慢 | 流量敏感的生产服务 |
| 25% | 25% | 默认:平衡速度和稳定性 | 大多数场景 |
| 50% | 50% | 激进:快速更新,服务能力有波动 | 非关键服务、测试环境 |
| 100% | 0 | 蓝绿风格:先创建全部新 Pod,再删除旧 Pod | 资源充足时快速切换 |
Recreate 策略:先终止所有旧 Pod,再创建新 Pod。会导致短暂停机,仅在应用不支持多版本共存(如数据库 schema 迁移)时使用。
4.3 触发更新的条件
只有 Pod 模板(.spec.template)发生变化才会触发滚动更新。以下操作不会创建新 ReplicaSet:
- 修改
spec.replicas(仅扩缩容) - 修改
spec.strategy - 修改
metadata.labels或metadata.annotations
触发更新的命令:
bash
# 方式一:直接修改镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.25
# 方式二:修改环境变量等 Pod 模板字段
kubectl set env deployment/nginx-deployment APP_VERSION=v2
# 方式三:编辑 YAML
kubectl edit deployment nginx-deployment
# 方式四:修改 YAML 文件后 apply
kubectl apply -f deployment.yaml
# 查看更新状态(阻塞直到完成或超时)
kubectl rollout status deployment/nginx-deployment
4.4 Deployment 状态条件
通过 kubectl describe deployment 可以查看 Deployment 的 Conditions,用于判断部署是否健康:
| Condition | 含义 |
|---|---|
Progressing |
正在创建新 ReplicaSet 或扩缩 Pod。超过 progressDeadlineSeconds 仍未完成则变为 False |
Available |
Pod 达到 minReadySeconds 后标记为 Available。当可用 Pod 数 ≥ replicas - maxUnavailable 时为 True |
ReplicaFailure |
ReplicaSet 创建 Pod 失败(如资源配额不足) |
五、版本回滚
Deployment 自动保留历史 ReplicaSet(由 spec.revisionHistoryLimit 控制,默认 10),旧版本的 ReplicaSet 副本数缩为 0 但不删除,使回滚只需将旧 ReplicaSet 重新扩容。
Deployment
RS v1 nginx:1.22 → 0 Pod
RS v2 nginx:1.23 → 0 Pod
RS v3 nginx:1.24 → 0 Pod
RS v4 nginx:1.25 → 3 Pod ✓
上图展示了 Deployment 保留的 4 个 ReplicaSet 版本,仅当前版本(v4)有活跃 Pod。回滚时 Deployment 控制器将目标版本的 ReplicaSet 扩容到期望副本数,同时将当前版本缩为 0。
bash
# 查看部署历史
kubectl rollout history deployment/nginx-deployment
# REVISION CHANGE-CAUSE
# 1 <none>
# 2 <none>
# 3 <none>
# 4 <none>
# 记录变更原因(推荐在 apply 时添加 --record,但该参数已废弃,
# 建议改用 annotations:kubernetes.io/change-cause)
kubectl annotate deployment/nginx-deployment \
kubernetes.io/change-cause="update to nginx:1.25"
# 查看某个版本的详情(Pod 模板内容)
kubectl rollout history deployment/nginx-deployment --revision=2
# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
# 回滚到指定版本
kubectl rollout undo deployment/nginx-deployment --to-revision=2
# 暂停/恢复更新(用于批量修改后一次性触发更新)
kubectl rollout pause deployment/nginx-deployment
# 执行多次修改...
kubectl rollout resume deployment/nginx-deployment
六、扩缩容
6.1 手动扩缩容
bash
# 扩容到 5 个副本
kubectl scale deployment nginx-deployment --replicas=5
# 缩容到 2 个副本
kubectl scale deployment nginx-deployment --replicas=2
# 条件扩容(仅当前副本数为 3 时才扩到 5,避免竞争)
kubectl scale deployment nginx-deployment --replicas=5 --current-replicas=3
6.2 自动扩缩容(HPA)
HPA(Horizontal Pod Autoscaler)根据 CPU、内存等指标自动调整 Pod 副本数。HPA 控制器周期性(默认 15 秒)查询 Metrics Server 获取资源使用率,与目标阈值对比后计算期望副本数。
查询指标
调整 replicas
HPA 控制器
Metrics Server
Deployment
ReplicaSet
Pod × N
上图展示了 HPA 的工作流程:HPA 控制器从 Metrics Server 获取指标,计算期望副本数,然后修改 Deployment 的 replicas 字段。
bash
# 快速创建 HPA
kubectl autoscale deployment nginx-deployment \
--min=2 --max=10 --cpu-percent=70
HPA YAML 配置(支持多指标):
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
scaleUp:
stabilizationWindowSeconds: 60
HPA 关键字段说明:
| 字段 | 说明 |
|---|---|
scaleTargetRef |
指向被控制的 Deployment(或其他支持 scale 子资源的控制器) |
minReplicas |
最小副本数,HPA 不会缩容到此值以下 |
maxReplicas |
最大副本数,HPA 不会扩容超过此值 |
metrics[].type |
指标类型:Resource(CPU/内存)、Pods(自定义指标)、Object(外部对象指标) |
metrics[].resource.target |
目标值,Utilization 为百分比,AverageValue 为绝对值 |
behavior.scaleDown.stabilizationWindowSeconds |
缩容稳定窗口期,防止指标波动导致频繁缩容。默认 300 秒 |
behavior.scaleUp.stabilizationWindowSeconds |
扩容稳定窗口期,默认 0(立即扩容) |
bash
# 查看 HPA 状态
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# nginx-hpa Deployment/nginx-deployment 35%/70% 2 10 3
# 查看 HPA 详情(含事件和扩缩历史)
kubectl describe hpa nginx-hpa
前提条件 :HPA 依赖 Metrics Server 提供资源使用数据。Pod 必须设置
resources.requests,否则 HPA 无法计算利用率。
七、Deployment 常用命令速查
bash
# ========== 创建与更新 ==========
kubectl apply -f deployment.yaml
kubectl set image deployment/nginx-deployment nginx=nginx:1.25
kubectl edit deployment nginx-deployment
# ========== 查看状态 ==========
kubectl get deployments
kubectl get deployment nginx-deployment -o yaml
kubectl describe deployment nginx-deployment
kubectl get rs -l app=nginx
kubectl get pods -l app=nginx -o wide
# ========== 滚动更新 ==========
kubectl rollout status deployment/nginx-deployment
kubectl rollout pause deployment/nginx-deployment
kubectl rollout resume deployment/nginx-deployment
# ========== 版本回滚 ==========
kubectl rollout history deployment/nginx-deployment
kubectl rollout history deployment/nginx-deployment --revision=2
kubectl rollout undo deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment --to-revision=2
# ========== 扩缩容 ==========
kubectl scale deployment nginx-deployment --replicas=5
kubectl autoscale deployment nginx-deployment --min=2 --max=10 --cpu-percent=70
# ========== 重启(触发所有 Pod 重建) ==========
kubectl rollout restart deployment/nginx-deployment
# ========== 删除 ==========
kubectl delete deployment nginx-deployment
八、常见问题
Q1:滚动更新卡住怎么办?
排查步骤:
kubectl rollout status deployment/nginx-deployment--- 查看更新进度kubectl get rs -l app=nginx--- 确认新旧 ReplicaSet 的 DESIRED/CURRENT/READYkubectl get pods -l app=nginx--- 查看新 Pod 状态(Pending / ImagePullBackOff / CrashLoopBackOff)kubectl describe pod <new-pod>--- 查看 Events 中的具体错误kubectl logs <new-pod>--- 查看应用日志
常见原因:镜像名称错误或不存在、镜像仓库认证失败、资源不足无法调度、readiness 探针配置错误导致 Pod 始终未就绪。
Q2:如何实现蓝绿部署或金丝雀发布?
Deployment 原生支持的是滚动更新。其他发布策略的实现方式:
| 策略 | 实现方式 |
|---|---|
| 蓝绿部署 | 创建两个 Deployment(blue/green),通过修改 Service 的 selector 切换流量 |
| 金丝雀发布 | 方式一:两个 Deployment 共用同一 Service(通过相同 label),控制副本比例(如 9:1);方式二:使用 Istio VirtualService 按权重分流;方式三:使用 Argo Rollouts |
Q3:revisionHistoryLimit 设置多少合适?
默认值为 10。每个历史 ReplicaSet 副本数为 0,资源占用极低,但在 etcd 中仍有存储开销。建议:
- 开发/测试环境:3-5
- 生产环境:5-10
- 频繁发布的服务:可适当调大
Q4:kubectl rollout restart 的原理是什么?
kubectl rollout restart 通过修改 Pod 模板的 annotation(kubectl.kubernetes.io/restartedAt)触发滚动更新。由于模板发生了变化,Deployment 控制器会创建新 ReplicaSet 并逐步替换所有 Pod。常用于不改代码但需重启 Pod 的场景(如刷新挂载的 ConfigMap)。
Q5:Deployment 更新超时怎么处理?
progressDeadlineSeconds(默认 600 秒)控制更新超时。超时后 Deployment 的 Progressing 条件变为 False,但不会自动回滚 。需要手动执行 kubectl rollout undo 回滚,或修复问题后重新触发更新。
九、总结
| 核心概念 | 说明 |
|---|---|
| 层级关系 | Deployment → ReplicaSet → Pod,三级控制器链,通过 ownerReferences 关联 |
| 滚动更新 | 逐步替换旧 Pod 为新 Pod,通过 maxSurge / maxUnavailable 控制更新节奏 |
| 版本回滚 | 历史 ReplicaSet 副本缩为 0 保留,回滚时重新扩容目标版本 |
| 弹性伸缩 | 手动 kubectl scale 或 HPA 根据 CPU/内存等指标自动调整副本数 |
| 自愈能力 | Pod 终止后 ReplicaSet 控制器自动创建新副本,维持期望状态 |
| 状态监控 | 通过 Conditions(Progressing / Available / ReplicaFailure)判断部署健康状态 |
生产建议:
- 始终使用 Deployment 而非裸 Pod
- 设置合理的
resources.requests/limits,HPA 依赖 requests 计算利用率 - 配置 readiness + liveness 探针,确保滚动更新能正确判断新 Pod 是否就绪
- 设置
minReadySeconds(如 5-10 秒),避免新 Pod 刚启动就接收全部流量 - 保留足够的
revisionHistoryLimit用于快速回滚 - 使用
kubectl annotate记录每次变更原因,便于回滚时决策