如果说 Pod 解决的是“怎么运行一个实例”,那么 Deployment 解决的就是“怎么稳定地运行一组实例,并且安全地升级它们”。在真实业务里,我们几乎不会手动维护单个 Pod,而是让 Deployment 负责声明目标状态,再由它背后的 ReplicaSet 去确保 Pod 副本数量始终符合预期。::cite[386]::cite[387]
这一章的重点,是把 Deployment 和 ReplicaSet 的职责边界讲清楚:为什么要有这两个对象、滚动更新是如何发生的、什么时候能回滚、什么时候该暂停发布,以及做版本发布时有哪些容易踩坑的地方。::cite[386]::cite[387]
2.2.1 为什么需要 ReplicaSet 与 Deployment
先看 ReplicaSet:保证“应该有几个 Pod”
ReplicaSet 的核心职责很单纯:维持指定数量的 Pod 副本持续存在。如果有 Pod 挂掉了,它会补;如果你把副本数调大,它会创建;如果调小,它会删除多余的实例。::cite[387]
这解决了“副本数量稳定性”的问题,但 ReplicaSet 本身并不擅长发布管理。官方文档也明确指出:ReplicaSet 不直接支持滚动更新。::cite[387]
再看 Deployment:保证“怎么升级这组 Pod”
Deployment 在 ReplicaSet 之上再封装了一层,提供的是 声明式更新能力。你只需要说清楚“我希望应用最终变成什么样子”,Deployment 控制器就会按受控节奏,创建新的 ReplicaSet、缩容旧的 ReplicaSet,并把整个过程编排起来。::cite[386]
可以这样理解它们的关系:
| 对象 | 主要职责 |
|---|---|
| Pod | 运行单个实例 |
| ReplicaSet | 保证副本数 |
| Deployment | 管理版本发布、滚动更新、回滚、暂停与恢复 |
为什么业务里通常直接写 Deployment?
因为绝大多数无状态应用都需要这几件事:
- 副本数控制
- 发布升级
- 失败回滚
- 观察发布状态
- 清理旧版本历史
这些都是 Deployment 的长项,所以官方也建议:通常直接管理 Deployment,而不要手动管理由 Deployment 创建出来的 ReplicaSet。::cite[386]
2.2.2 Deployment 的核心工作机制
Deployment 的本质是:
- 你提交一个目标状态。
- Deployment 控制器比较“当前状态”和“目标状态”。
- 它创建一个新的 ReplicaSet。
- 再按照发布策略,逐步扩新、逐步缩旧。::cite[386]
一个最小可用的 Deployment
先从最基础的 YAML 开始:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
这个配置表达了三个意思:
- 想要 3 个副本。
- 由标签
app: web选中并管理这些 Pod。 - Pod 模板里跑的是
nginx:1.27。::cite[386]
实操步骤
- 创建 Deployment。
kubectl apply -f web-deployment.yaml
- 查看 Deployment。
kubectl get deployments
- 查看 ReplicaSet。
kubectl get rs
- 查看 Pod。
kubectl get pods --show-labels
观察重点:Deployment 会自动创建一个 ReplicaSet,再由 ReplicaSet 创建并维持 Pod。::cite[386]
2.2.3 Deployment 的副本控制与滚动更新
副本控制:replicas
最直观的能力就是副本数控制。你可以通过修改 spec.replicas 来扩缩容。Deployment 不会直接一个个管理 Pod,而是调整底层 ReplicaSet 的期望副本数。::cite[386]
例如,把副本改成 5:
kubectl scale deployment/web-deployment --replicas=5
什么操作会触发滚动更新?
只有 Pod 模板发生变化时,Deployment 才会触发新的 rollout。
也就是说,像下面这些修改会触发发布:
- 修改镜像版本
- 修改容器命令
- 修改环境变量
- 修改资源限制
- 修改挂载卷
但单纯修改 replicas 不会产生新的版本修订。::cite[386]
滚动更新是怎么做的?
Deployment 默认的发布策略是 RollingUpdate。它会在“新旧版本并存”的情况下逐步替换:
- 一边拉起新 Pod
- 一边下掉旧 Pod
- 始终尽量保证服务可用性::cite[386]
官方文档给出的默认行为是:
maxUnavailable: 25%maxSurge: 25%
这意味着:
- 更新期间最多允许 25% 的副本临时不可用
- 更新期间最多允许额外多创建 25% 的副本::cite[386]
一个更完整的滚动更新示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 4
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
更新镜像版本
kubectl set image deployment/web-deployment nginx=nginx:1.28
查看发布状态:
kubectl rollout status deployment/web-deployment
查看新旧 ReplicaSet 变化:
kubectl get rs
观察重点:Deployment 会新建一个 ReplicaSet,并逐步把副本从旧 ReplicaSet 挪到新 ReplicaSet。::cite[386]
2.2.4 回滚、暂停与恢复发布
线上发布一定会出错,所以 Deployment 的价值不只是“能发布”,更是“出错时能不能有序恢复”。::cite[386]
1)查看发布历史
kubectl rollout history deployment/web-deployment
如果想看某个 revision 的具体内容:
kubectl rollout history deployment/web-deployment --revision=2
Deployment 会为每次模板变更创建 revision。只要是 Pod 模板变化,都会形成可回滚的修订版本。::cite[386]
2)回滚到上一个版本
kubectl rollout undo deployment/web-deployment
3)回滚到指定版本
kubectl rollout undo deployment/web-deployment --to-revision=2
这在镜像写错、配置错误、资源设置不合理时非常好用。官方示例就展示了因为镜像名拼错导致发布卡住,再通过回滚恢复服务的过程。::cite[386]
4)暂停发布
当你准备连续改多个字段时,不希望每改一次都触发一次 rollout,可以先暂停:
kubectl rollout pause deployment/web-deployment
然后你可以继续做多次变更,例如:
kubectl set image deployment/web-deployment nginx=nginx:1.28
kubectl set resources deployment/web-deployment -c=nginx --limits=cpu=300m,memory=512Mi
5)恢复发布
kubectl rollout resume deployment/web-deployment
恢复后,之前积累的变更会一起进入新的 rollout。::cite[386]
一个重要注意点
暂停中的 Deployment 不能回滚,必须先恢复。::cite[386]
2.2.5 版本发布策略与常见注意事项
发布策略 1:RollingUpdate(默认、最常用)
这是最适合大多数无状态应用的方式。优点是:
- 发布过程平滑
- 能尽量保持服务可用
- 适合持续交付::cite[386]
发布策略 2:Recreate(简单粗暴)
如果业务允许短暂中断,也可以用 Recreate:
strategy:
type: Recreate
这种方式会先停旧 Pod,再起新 Pod。适用于对版本并存敏感、但能接受瞬时不可用的场景。
金丝雀 / 蓝绿 发布如何做?
严格来说,Deployment 本身没有一个 type: Canary 或 type: BlueGreen 的原生字段。常见做法是:
- 金丝雀发布:创建两个 Deployment,分别承载稳定版本与少量新版本流量。
- 蓝绿发布:准备两套完整环境,通过 Service 或 Ingress 切流。::cite[386]
所以你可以说:Deployment 是这些高级发布模式的基础构件,但不是全部自动化方案本身。
2.2.6 常见踩坑点
1)selector 与模板标签不一致
Deployment 的 spec.selector.matchLabels 必须能匹配 spec.template.metadata.labels。不一致时,控制器就无法正确识别自己该管哪些 Pod。::cite[386]
2)不要与其他控制器使用重叠选择器
如果两个控制器都能选中同一批 Pod,行为会变得不可预测。官方明确提醒不要让不同 Deployment 或 StatefulSet 的选择器重叠。::cite[386]
3)apps/v1 下 selector 不可变
在 apps/v1 中,Deployment 的 selector 创建后不可修改。也就是说,标签规划最好在一开始就想清楚。::cite[386]
4)Readiness Probe 缺失会让发布看起来“成功”,但流量体验可能很差
Deployment 的滚动更新是否平稳,和 Pod 是否真正 Ready 密切相关。如果没有合理的 readiness 检查,新 Pod 虽然进程起来了,但业务可能还没准备好接请求。
5)发布时资源峰值会暂时升高
因为 maxSurge 允许额外起 Pod,所以 rollout 期间实际 Pod 总数可能超过目标副本数;再叠加老 Pod 的优雅终止时间,短时资源占用往往比平时高。::cite[386]
6)不要手动改 Deployment 管理下的 ReplicaSet
手动缩放或编辑由 Deployment 托管的 ReplicaSet,很容易让控制器状态变复杂。一般情况下,直接改 Deployment 即可。::cite[386]
2.2.7 一套推荐的无状态发布模板
下面是一份更贴近生产习惯的模板:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: api
spec:
replicas: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: nginx:1.27
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
这个模板的思路是:
maxUnavailable: 0:尽量避免更新时掉副本。maxSurge: 1:控制额外资源开销。- 配好 readiness / liveness:让 Deployment 知道“什么时候真的可以接流量”。
- 控制
revisionHistoryLimit:保留回滚历史,但不要无限增长。
2.2.8 本章小结
这一章你要真正记住的是:
- ReplicaSet 负责保副本,Deployment 负责做发布。
- 改 Pod 模板才会触发 rollout,改单纯副本数不会。
- 滚动更新本质上是新旧 ReplicaSet 的受控切换。
- 回滚、暂停、恢复,是 Deployment 在生产环境里最有价值的能力。
- 发布是否平稳,不只看 Deployment,还要看探针、标签、资源与容量。
当你日常管理无状态应用时,推荐默认思路是:
- 用 Deployment 管理服务
- 用 Service 提供稳定访问入口
- 用 Probe 保证流量只进到健康实例
- 用
kubectl rollout系列命令管理发布生命周期
📝 版权声明:本文为原创技术博客,转载请注明出处。
如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!