Deployment 是大多数人每天都会碰到的控制器。ReplicaSet 负责把副本数量维持住,Deployment 则负责版本变更、滚动发布和回滚历史。很多发布问题表面上像“应用起不来”,实际上根因常常藏在 Deployment 这条控制链路里。
这两个控制器分别干什么
- ReplicaSet:维持匹配 Pod 的副本数量。
- Deployment:创建和更新 ReplicaSet。
- 滚动更新:让旧版本和新版本按策略交替切换。
日常操作里,你通常应该管理 Deployment,而不是直接去改 ReplicaSet。
为什么还需要 Deployment
只有 ReplicaSet,并不足以支撑日常发布。你还需要:
- 发布历史
- 回滚能力
- 更新进度跟踪
- 更安全的滚动策略
Deployment 就是在 ReplicaSet 之上补了这一层发布语义。
所以,手动删 Pod 不应该成为发版方式。真正可靠的做法,是修改期望状态,让控制器完成收敛。
最小示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: nginx:1.25
最重要的一条规则:selector 和 labels 必须对上
Deployment 的 selector 必须和 Pod 模板里的 labels 对齐。如果两者漂移,控制器会接管失败,流量和发布行为都会变得很奇怪。
这也是为什么 Deployment 创建后通常不要再轻易改 selector。
一次 rollout 实际上发生了什么
当你修改 Pod 模板时,Kubernetes 并不是在原地改老的 ReplicaSet,而是:
- 创建一个新的 ReplicaSet
- 把新 ReplicaSet 扩上去
- 把旧 ReplicaSet 缩下来
- 一直跟踪状态,直到发布完成
这就是为什么你会看到 rollout history,也解释了为什么老的 ReplicaSet 还会暂时保留下来。
RollingUpdate 和 Recreate 怎么选
RollingUpdate
默认也是最常见的选择。
适合:
- 新旧版本可以短暂共存
- 希望发布更平滑
- 业务不能轻易中断
Recreate
先停旧版本,再起新版本。
只适合:
- 新旧版本不能同时存在
- 独占锁、兼容性或启动顺序不允许并行
最值得记住的 rollout 命令
kubectl rollout status deploy/api
kubectl rollout history deploy/api
kubectl rollout undo deploy/api
kubectl rollout pause deploy/api
kubectl rollout resume deploy/api
出问题时,这些命令通常比“现场改配置碰运气”有用得多。
滚动更新参数怎么理解
两个关键字段:
maxSurge:发布过程中允许额外多出来多少 PodmaxUnavailable:发布过程中允许少掉多少可用副本
对关键 API 来说,maxUnavailable: 0 往往是更稳的起点。
为什么探针会直接影响 Deployment
Deployment 的安全性很大程度依赖 readiness。如果 readiness 配得不对,Kubernetes 可能:
- 把坏 Pod 当成好 Pod
- 把好 Pod 长时间挡在流量之外
- 让 rollout 一直卡住
很多人以为是“发布失败”,其实根因是探针设计失败。
镜像标签和版本历史
尽量用明确版本号,不要在生产里依赖 latest。
版本 tag 固定下来之后,rollout history 才真正有意义。否则你连“这次到底变了什么”都很难说清楚。
requests / limits 也是发布稳定性的一部分
如果没有 requests,调度器缺少有效信号,HPA 也更难做出靠谱判断,节点更容易出现资源争抢。
所以发布策略不只是“镜像怎么切”,也包括“集群有没有能力把新副本稳定放下去”。
Deployment 和 StatefulSet 的边界
适合 Deployment:
- 副本可互换
- 不需要稳定身份
- 存储可丢弃或外置
适合 StatefulSet:
- 每个副本都有独立身份
- 每个副本都有独立数据
- 启动顺序和更新顺序很重要
很多看似“数据库发不稳”的问题,本质上是控制器选错了。
常见发布故障
rollout 卡住
常见原因:
- readiness 一直不过
- 镜像拉取失败
- requests 导致无法调度
maxUnavailable和副本数设置太保守,当前容量兜不住
Pod 活着,但流量不通
这往往不是 Deployment 本身的 bug,而是 Service selector 和 Pod labels 对不上。
旧版本迟迟不下线
可能是 rollout 没真正结束,也可能是 endpoints 还指向旧 Pod,或者 readiness / termination 过慢。
实用排障顺序
kubectl describe deploy api
kubectl get rs
kubectl describe rs <replicaset>
kubectl get pods -l app=api
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl get events --sort-by=.metadata.creationTimestamp
先从 Deployment 往下看,再进入 ReplicaSet、Pod、事件,这样最容易看清发布链路卡在哪一段。
发布前建议检查什么
- selector 和 labels 是否一致
- 镜像 tag 是否明确
- readiness 是否代表真实可用
- requests / limits 是否合理
- 回滚命令是否明确
- Service 是否仍然能正确匹配新 Pod
FAQ
Q: 可以直接改 ReplicaSet 吗? A: 一般不建议。ReplicaSet 是 Deployment 管理出来的发布产物,直接修改容易造成混乱和漂移。
Q: 为什么改了一次 Deployment 就会出现新的 ReplicaSet? A: 因为 Pod 模板变化就意味着一个新的版本边界,Kubernetes 需要新的 ReplicaSet 来承载发布历史和回滚能力。
Q: 为什么 staging 发布正常,生产环境却卡住? A: 生产环境通常资源更紧、探针更严格、流量更真实,Service 依赖也更复杂,所以很多问题会在生产里被放大。
下一步阅读
- 接着读
kubernetes-quickstart-probes.md - 再读
kubernetes-quickstart-service.md - 如果你要做更稳妥的发布,继续看 canary 和 rollout 相关 tips
收个尾
Deployment 不只是“多副本容器管理器”,它本质上是你的基础发布控制器。只要把 rollout 状态、ReplicaSet 历史和 readiness 行为看清楚,大量看似玄学的发布故障都会变得可解释。