内容提要
本文分析 Kubernetes v1.28 中 Deployment 滚动更新的源码实现。DeploymentController 通过 syncDeployment 入口,依次检测删除、暂停、回滚、扩缩容和更新,每次同步只执行一种操作。扩缩容按比例逐步调整各 ReplicaSet 副本数,避免可用副本骤降;滚动更新则不断扩容新 ReplicaSet、缩容旧 ReplicaSet,并依据最大不可用数控制缩容,直至达到期望状态。
延伸解读
同步入口的串行化设计
syncDeployment 每次同步只执行一种操作,依次检测删除、暂停、回滚、扩缩容和更新。这种设计避免了多种操作并发导致的竞态,但也意味着一次同步无法同时处理扩缩容和滚动更新。读者需注意,Deployment 的收敛是多次同步循环的结果,而非单次调用完成。
扩缩容按比例调整的用意
scale 方法不会直接调整到目标副本数,而是按比例逐步调整各 ReplicaSet。扩容时优先新的 ReplicaSet,缩容时优先旧的,并计算 allowedSize 限制超出期望的 Pod 数量。这降低了不可用副本骤增的风险,但比例分配后剩余数量会集中给第一个 ReplicaSet,可能造成副本分布不均。
滚动更新的缩容安全边界
reconcileOldReplicaSets 计算 maxScaledDown 时,不仅考虑最大不可用数,还减去新 ReplicaSet 的不可用 Pod 数。这防止新 Pod 尚未就绪时旧 Pod 被过度缩容。文中示例说明,若新 ReplicaSet 故障,缩容会被阻止,直到回滚或模板更新改变不可用计数。
删除操作的实际执行者
Deployment 删除时,syncDeployment 调用 syncStatusOnly 仅同步状态,真正的删除由 GarbageCollector 控制器完成。这表明 DeploymentController 不直接删除 Pod 或 ReplicaSet,而是依赖 GC 的级联删除机制。读者排查删除问题时,需同时关注 GC 控制器的行为。
Q&A
Deployment 和 ReplicaSet 有什么区别,为什么生产环境不直接使用 ReplicaSet?
Deployment 为 Pod 和 ReplicaSet 提供声明式更新能力,支持滚动更新、水平扩容、自动回滚等高级特性;而 ReplicaSet 功能较底层,仅能维护一组 Pod 的运行状态并指定期望副本数,无法完成水平扩容等高级操作。
DeploymentController 每次同步 Deployment 时会执行哪些操作?
syncDeployment 入口依次检测:删除、暂停、回滚、扩缩容、更新(滚动更新或全量更新)。每次同步只执行其中一种操作,例如执行了扩容就不会再执行更新。
Deployment 扩缩容时为什么不是直接调整到目标副本数?
为避免可用副本数量骤降引发节点性能故障风险,Kubernetes 会按比例逐步调整各 ReplicaSet 的副本数,类似滚动升级的设计理念。扩容时优先以新的 ReplicaSet 为基准,缩容时优先缩减旧的 ReplicaSet。
Deployment 滚动更新的核心实现逻辑是什么?
rolloutRolling 方法通过不断扩容新的 ReplicaSet、缩容旧的 ReplicaSet,此消彼长直至达到期望状态。缩容时依据最大不可用数控制,确保可用副本不低于最小可用量。
滚动更新缩容旧 ReplicaSet 时如何计算最大可缩容数量?
最大缩容数量 = 所有 Pod 总数 - 最小可用量(期望副本数减最大不可用数) - 新 ReplicaSet 的不可用 Pod 数。若结果小于等于 0 则不缩容,从而避免可用性进一步降低。
Deployment 的删除操作是由 DeploymentController 直接完成的吗?
不是。DeploymentController 的 syncStatusOnly 方法仅更新 Deployment 状态,真正的删除操作由 GarbageCollector(GC)控制器完成。