K8s Pod 何时会被删除?
最近在梳理 Kubelet 的源码实现,从源码入手整理了下 Kubelet 以及 kube-controller 删除 Pod 的场景。
本文K8s版本参考v1.20.6
Kube-Controller
workload controller 触发删除
-
- 如果 job 处于 failed 状态,删除所有 activePod(
deleteJobPods
) - 如果 activePod 大于 job.Spec.Parallelism 并行数,删除多余 Pod(
manageJob
)
- 如果 job 处于 failed 状态,删除所有 activePod(
-
- 根据 taints、资源、selector 等条件判断 Pod 是否需要运行在某节点上,如果不需要则调用
syncNodes
删除
- 根据 taints、资源、selector 等条件判断 Pod 是否需要运行在某节点上,如果不需要则调用
-
- 根据实际的 Pod 数与 Spec 的 Pod 数比较,如果多了就调用删除 Pod(
manageReplicas
)
- 根据实际的 Pod 数与 Spec 的 Pod 数比较,如果多了就调用删除 Pod(
replication
- rc 已基本不使用
statefulset(主要在更新函数
updateStatefulSet
中)- 状态是 failed 的 Pod 删除重建
- 缩容时按照顺序删除 Pod
- 如果版本号旧的 Pod 也删除
NodeController 触发删除
nodeController主要通过污点导致Pod的删除
K8s Admission 为所有 Pod 打上Toleration
- DefaultTolerationSeconds admission 为所有 Pod 打上 NotReady 的 NoExecute 容忍,容忍时间是 5 分钟(如果之前没有相同 KEY 的污点的话)
- 源码参考:plugin/pkg/admission/defaulttolerationseconds/admission.go
节点不可用时
对于 NotReady 的 Node,NodeController 会自动打上污点
1
2
3
4
5
6
7taints:
- effect: NoSchedule
key: node.kubernetes.io/not-ready
timeAdded: "2021-12-02T10:08:44Z"
- effect: NoExecute
key: node.kubernetes.io/not-ready
timeAdded: "2021-12-02T10:08:47Z"NoExecute 污点与
TaintBasedEvictions
特性相关;monitorNodeHealth 会长期检查 Node 状态,如果 NotReady,会调用 processTaintBaseEviction.markNodeForTainting 将该 Node 加入 zoneNoExecuteTainter 队列,doNoExecuteTaintingPass 会周期循环这个队列打上对应的污点NoSchedule 污点为 doNoScheduleTaintingPass 函数打的,启用了
TaintNodeByCondition
feature-gates 后,nodeUpdate 后会根据 Node 的 Condition 打上对应的污点,映射关系如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16v1.NodeReady: {
v1.ConditionFalse: v1.TaintNodeNotReady,
v1.ConditionUnknown: v1.TaintNodeUnreachable,
},
v1.NodeMemoryPressure: {
v1.ConditionTrue: v1.TaintNodeMemoryPressure,
},
v1.NodeDiskPressure: {
v1.ConditionTrue: v1.TaintNodeDiskPressure,
},
v1.NodeNetworkUnavailable: {
v1.ConditionTrue: v1.TaintNodeNetworkUnavailable,
},
v1.NodePIDPressure: {
v1.ConditionTrue: v1.TaintNodePIDPressure,
},源码参考:pkg/controller/nodelifecycle/node_lifecycle_controller.go
Pod 容忍时间达到5分钟后,Pod 被 taintManager 驱逐
源码参考:pkg/controller/nodelifecycle/scheduler/taint_manager.go 的 processPodOnNode
Pod GC Controller
- pkg/controller/podgc/gc_controller.go
- gcTerminated
- 根据创建时间排序,删除大于 kube-controller-manager
terminated-pod-gc-threshold
配置(我们数据面集群配置 12500 )个数的 Pod
- 根据创建时间排序,删除大于 kube-controller-manager
- gcOrphaned
- 删除 bind node 不存在的 Pod
- gcUnscheduledTerminating
- 遍历所有pods,过滤那些terminating(
pod.DeletionTimestamp != nil
)并且未调度成功的(pod.Spec.NodeName为空)的pods
- 遍历所有pods,过滤那些terminating(
- gcTerminated
Kubelet
Kubelet 不会主动调用 client-go 删除 Pod,只会在 APIServer 收到 Pod 优雅删除请求后,如果 Pod 所占用的 cgroups、volume 等资源都释放了,则会调用强制删除接口(GracePeriodSeconds 为 0)删除 Pod
以下三种情况会触发 SyncPodKill 事件,此时 Kubelet 会调用 CRI stop running container
驱逐(https://kubernetes.io/zh/docs/concepts/scheduling-eviction/node-pressure-eviction/)
- kubelet 具有以下默认硬驱逐条件:
- memory.available<100Mi
nodefs.available<10%
nodefs.available<10%
imagefs.available<15%
nodefs.inodesFree<5%
(Linux 节点)- imagefs.inodesFree、pid.available 未配置
- kubelet 具有以下默认硬驱逐条件:
抢占(https://kubernetes.io/zh/docs/concepts/scheduling-eviction/pod-priority-preemption/)
- PriorityClass 还有两个可选字段:
globalDefault
和description
。globalDefault
字段表示这个 PriorityClass 的值应该用于没有priorityClassName
的 Pod。 系统中只能存在一个globalDefault
设置为 true 的 PriorityClass。 如果不存在设置了globalDefault
的 PriorityClass, 则没有priorityClassName
的 Pod 的优先级为零。 - 当没有悬决 Pod,或者悬决 Pod 的优先级等于或低于牺牲者时,不得发生抢占。
- Kube-controller-manager 等三大件优先级高。
- PriorityClass 还有两个可选字段:
节点 shutdown (pkg/kubelet/nodeshutdown/nodeshutdown_manager_linux.go processShutdownEvent)