k8S ReplicaSet 缩容时的 Pod 删除逻辑详解#

1. 默认的 Pod 删除顺序#

当 ReplicaSet 检测到当前的 Pod 数量(filteredPods)超过期望的数量(rs.Spec.Replicas)时,它会调用 manageReplicas 函数来处理缩容逻辑。核心的删除决策发生在 getPodsToDelete 函数中,该函数通过对候选 Pod 进行排序来选出需要删除的 Pod(位于 pkg/controller/replicaset/replica_set.gopkg/controller/controller_utils.go)。

排序过程依赖 getPodsRankedByRelatedPodsOnSameNode 函数计算排名 & controller.ActivePodsWithRanksLess 方法(定义在 pkg/controller/controller_utils.go)。排序遵循以下优先级,数字越小优先级越高(越先被删除):

  1. Pod 分配状态: 未分配到节点(pod.Spec.NodeName 为空)的 Pod 优先于已分配的 Pod。
  2. Pod Phase:Pending 状态的 Pod 优先于其他状态。
  3. Pod 就绪状态 (Readiness): RunningNot Ready 的 Pod 优先于 Running & Ready 的 Pod。
  4. Pod 删除成本 (Deletion Cost):
    • 控制器会检查 Pod 是否包含 controller.kubernetes.io/pod-deletion-cost 注解。
    • 该注解的值需要能被解析为 int32值越小优先级越高
    • 没有该注解或注解值无效的 Pod,其删除成本被视为 0。
  5. 同节点 Pod 数量: 运行在拥有更多关联 Pod(如:属于同一 Controller 管理的其他 ReplicaSet)的节点上的 Pod 会被优先删除。通过 getPodsRankedByRelatedPodsOnSameNode 计算得到的排名(Rank),Rank 值越高的 Pod 越优先被删除
  6. Pod 创建时间: 创建时间较早 (Older) 的 Pod 会被优先删除

2. 如何删除指定 Pod#

  • 删除成本足够低: 要确保某个 Pod 被优先删除,需要将其删除成本设置得显著低于其他候选 Pod。如,将其设置为负数,而其他 Pod 没有设置或设置为正数。
  • 其他高优先级条件相同: 需要注意的是,删除成本只是排序规则中的一项。如果存在更高优先级的差异(例如,一个 Pod 处于 Pending 状态,而另一个设置了低成本的 Pod 处于 RunningReady 状态),那么 Pending 状态的 Pod 仍然会被优先删除。

3. 实践#

  • 初始状态,3 个 pod,确保 Running & Ready

    1
    2
    3
    4
    5
    $ kubectl get pod 
    NAME READY STATUS RESTARTS AGE
    pod-7cdb499b56-48xtp 1/1 Running 0 14m
    pod-7cdb499b56-lbsz5 1/1 Running 0 15d
    pod-7cdb499b56-xxmnp 1/1 Running 0 14m
  • 设置 pod emqx-blue-replicant-7cdb499b56-48xtp 的删除成本为 -100,其他 pod 的删除成本为 100

    1
    2
    3
    kubectl --context test_eu_eks -n infra-iot-broker-core annotate pod pod-7cdb499b56-48xtp controller.kubernetes.io/pod-deletion-cost=-100
    kubectl --context test_eu_eks -n infra-iot-broker-core annotate pod pod-7cdb499b56-lbsz5 controller.kubernetes.io/pod-deletion-cost=100
    kubectl --context test_eu_eks -n infra-iot-broker-core annotate pod pod-7cdb499b56-xxmnp controller.kubernetes.io/pod-deletion-cost=100
  • 缩容到 2 个 pod

    1
    $ kubectl scale deployment pod --replicas=2
  • 查看结果

    1
    2
    3
    4
    $ kubectl get pod 
    NAME READY STATUS RESTARTS AGE
    pod-7cdb499b56-lbsz5 1/1 Running 0 15d
    pod-7cdb499b56-xxmnp 1/1 Running 0 40m