05 | 控制器模式与 Deployment:编排的本质 系列专栏《深入剖析 Kubernetes》· 基于张磊极客时间专栏思想整理 · 适合 CSDN 发布05 | 控制器模式与 Deployment编排的本质上一篇我们讲了 Pod 是最小调度单元。但 Pod 自己不会保持几个副本、不会滚动更新、不会回滚。这些让应用按期望运行的能力全部来自 K8s 的控制器模式Controller Pattern。这篇文章我们先抓住 K8s 最提纲挈领的一个思想再落地到最常用的Deployment。一、控制器模式K8s 的灵魂Kubernetes 整个编排系统的核心可以浓缩成一句话声明式 API 调谐循环Reconcile Loop。你不是下命令去启动 3 个 Pod那是命令式而是声明一个期望状态Desired State“我要 3 个 Pod 在跑”。剩下的交给一个叫controller的死循环它不断对比实际状态和期望状态发现差距就动手弥合。用户 (kubectl apply) | 声明期望状态: replicas3 v ------------- watch ---------------------- | Etcd | -------------- | Controller | | (实际/期望 | | (调谐循环) | | 状态存储) | ------------- | | ------------- 读取实际状态 | if 实际 ! 期望: | | 创建/删除 Pod | ---------------------- ^ | | v ----------- 反复 reconcile ------- 直到 实际期望这就是所谓的level-triggered基于水平触发的调谐控制器不在乎发生了什么事件只在乎当前状态对不对。网络抖动、进程崩溃、节点宕机只要最终状态不对它就会持续纠偏。这正是 K8s 自愈能力的来源。二、Deployment → ReplicaSet → Pod 控制链Deployment是用户最常用的工作负载但它不直接管 Pod。它的真实结构是三层委托Deployment (声明副本数、镜像版本、更新策略) | 管理 v ReplicaSet (保证某一版本恰好有 N 个 Pod) | 管理 v Pod (真正跑容器的实例) 滚动更新时 Deployment 创建 新的 ReplicaSet (v2) 旧 ReplicaSet (v1) 缩容 - 0 新 ReplicaSet (v2) 扩容 - N 两个 RS 短暂共存实现不停机更新为什么要中间加一层ReplicaSet因为ReplicaSetRS的职责是保证某个固定 Pod 模板的副本数。当你改镜像版本触发滚动更新Deployment 会新建一个 RS 来管理新版本 Pod旧 RS 保留下来——这正好就是回滚的基石旧 RS 还在随时可拉回来。三、副本与水平扩展一个最精简的 DeploymentapiVersion:apps/v1kind:Deploymentmetadata:name:nginxspec:replicas:3# 期望副本数RS 会维持恰好 3 个 Podselector:matchLabels:app:nginxtemplate:# Pod 模板Pod 怎么造写在这里metadata:labels:app:nginxspec:containers:-name:nginximage:nginx:1.25resources:requests:{cpu:100m,memory:128Mi}limits:{cpu:200m,memory:256Mi}参数解释replicas声明式副本数。改这个值就是扩缩容当然生产用 HPA 更优雅见第 12 篇。selector.matchLabelsRS 靠这个标签筛出归我管的 Pod务必与template.labels一致。resources.requests/limits调度依据与资源上限避免单 Pod 吃满 Node。扩容只是改个数字kubectl scale deployment nginx --replicas5。四、滚动更新与回滚Deployment 默认用RollingUpdate滚动更新分批替换旧 Pod保证服务不中断。spec:strategy:type:RollingUpdaterollingUpdate:maxSurge:1# 最多比期望多 1 个 Pod更新时临时超出maxUnavailable:0# 更新期间最多 0 个 Pod 不可用保证容量参数解释maxSurge滚动中额外能创建的 Pod 数可为百分比如25%。1表示先起 1 个新 Pod 再下 1 个旧的。maxUnavailable滚动中允许不可用的 Pod 数。0表示全程不丢容量代价是临时多占用资源。触发更新改镜像即可kubectlsetimage deployment/nginxnginxnginx:1.26 kubectl rollout status deployment/nginx# 观察滚动进度# 查看历史版本kubectl rollouthistorydeployment/nginx# 回滚到上一版kubectl rollout undo deployment/nginx# 回滚到指定版本kubectl rollout undo deployment/nginx --to-revision2回滚之所以快是因为旧ReplicaSet从未被删除只是副本数被置 0。undo 本质上是把旧 RS 拉回前台。五、和经典 PaaS 的作业副本对比传统 PaaS如 Cloud Foundry / Heroku也能跑多副本、也能滚动发布区别在哪维度经典 PaaSK8s Deployment抽象以应用为中心以资源对象 控制器为中心发布平台托管黑盒RS 版本化可精确回滚扩展通常只能扩副本任意对象可自定义控制器扩展灵活性受限平台给什么用什么可编写自定义控制器/CRD见第 08 篇经典 PaaS 把副本管理做成了一个写死的功能点而 K8s 把它抽象成通用机制控制器 声明式 API于是你不仅能用 Deployment还能用同样的模式造出 StatefulSet、DaemonSet甚至自己的 Operator。这就是 K8s “可扩展” 与 “声明式” 的真正威力。小结 / 核心要点控制器模式 声明式 API Reconcile 循环你描述想要什么系统持续纠偏到实际期望。Deployment 不直接管 Pod而是Deployment → ReplicaSet → Pod三层委托。ReplicaSet 保留旧版本是实现快速回滚的关键。滚动更新靠maxSurge/maxUnavailable控制多建几个、允许停几个实现不停机发布。K8s 把副本管理做成通用机制这是它远比传统 PaaS 灵活、可扩展的根本原因。