深入探索Kubernetes中的Mirror Pod删除过程及其对Static Pod 的影响
这也是一篇研究pod移除流程的文章,这个文章专注mirror pod的移除。mirror pod这个名词可能很陌生,中文直译就是镜像pod,它是pod里的一种类型。
那我们先介绍pod的分类,pod来源分为file、http、apiserver。其中来自apiserver中的pod称为普通pod,其他来源的pod称为static pod(使用kubeadm安装集群的控制平面就是用static pod运行的)。为了管理pod方便,kubelet会在apiserver上为static pod生成对应的pod,这类型pod称为mirror pod,即可以理解是这个pod的替身(基本上跟static pod一模一样,只有uid不一样和annotations里多了"kubernetes.io/config.mirror")。
那么删除mirror pod会发生什么?对节点上static pod有没有影响,会不会移除节点上的static pod?
pod移除流程系列文章
- 深度解析Static Pod在kubelet中的移除流程
- Kubelet Bug:sandbox残留问题 - 探寻sandbox无法被清理的根源
- 为什么kubelet日志出现an error occurred when try to find container
本文使用kubernete版本是1.23和日志级别为4。
1 认识static pod和mirror pod
kubelet的static pod的机制生成的pod name为配置里的pod name加上node节点名。在这个例子中,定义的pod name为nginx-static-pod,而最终生成的pod名字为nginx-static-pod-10.11.251.2。
下面是kubelet上的static pod配置
apiVersion: v1
kind: Pod
metadata:
name: nginx-static-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
对应的mirror pod
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/config.hash: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.mirror: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.seen: "2023-11-23T14:05:21.400551188+08:00"
kubernetes.io/config.source: file
creationTimestamp: "2023-11-23T06:05:21Z"
name: nginx-static-pod-10.11.251.2
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: 10.11.251.2
uid: d2e3ebf6-2a70-434f-9142-0f74a1dd16bc
resourceVersion: "292107092"
uid: 1facfed2-ba67-40f8-9982-ab86a5e7fd33
spec:
containers:
- image: nginx:latest
imagePullPolicy: Always
name: nginx-container
ports:
- containerPort: 80
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: 10.11.251.2
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
operator: Exists
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:21Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:29Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:29Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:21Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://b6ca55d329230c8f5776eb1160fe161d6fefa01f2b31e55dbb820add90aadccc
image: nginx:latest
imageID: docker-pullable://nginx@sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee
lastState: {}
name: nginx-container
ready: true
restartCount: 0
started: true
state:
running:
startedAt: "2023-11-23T06:05:29Z"
hostIP: 10.11.251.2
phase: Running
podIP: 10.26.124.96
podIPs:
- ip: 10.26.124.96
qosClass: BestEffort
startTime: "2023-11-23T06:05:21Z"
2 实际测试
我们直接做个实验,使用kubectl删除mirror pod,然后watch pod变化
完整的kubelet日志和watch记录在 The log for mirror pod in kubelet
mirror pod的uid为1facfed2-ba67-40f8-9982-ab86a5e7fd33
# kubectl get pod nginx-static-pod-10.11.251.2 -o yaml -w
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/config.hash: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.mirror: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.seen: "2023-11-23T14:05:21.400551188+08:00"
kubernetes.io/config.source: file
creationTimestamp: "2023-11-23T06:05:21Z"
name: nginx-static-pod-10.11.251.2
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: 10.11.251.2
uid: d2e3ebf6-2a70-434f-9142-0f74a1dd16bc
resourceVersion: "292107092"
uid: 1facfed2-ba67-40f8-9982-ab86a5e7fd33
pod被删除,deletionTimestamp字段有值,且deletionGracePeriodSeconds为30
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/config.hash: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.mirror: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.seen: "2023-11-23T14:05:21.400551188+08:00"
kubernetes.io/config.source: file
creationTimestamp: "2023-11-23T06:05:21Z"
deletionGracePeriodSeconds: 30
deletionTimestamp: "2023-11-23T06:11:45Z"
name: nginx-static-pod-10.11.251.2
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: 10.11.251.2
uid: d2e3ebf6-2a70-434f-9142-0f74a1dd16bc
resourceVersion: "292110805"
uid: 1facfed2-ba67-40f8-9982-ab86a5e7fd33
再次被删除,deletionGracePeriodSeconds设置为0
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/config.hash: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.mirror: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.seen: "2023-11-23T14:05:21.400551188+08:00"
kubernetes.io/config.source: file
creationTimestamp: "2023-11-23T06:05:21Z"
deletionGracePeriodSeconds: 0
deletionTimestamp: "2023-11-23T06:11:15Z"
name: nginx-static-pod-10.11.251.2
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: 10.11.251.2
uid: d2e3ebf6-2a70-434f-9142-0f74a1dd16bc
resourceVersion: "292110806"
uid: 1facfed2-ba67-40f8-9982-ab86a5e7fd33
mirror pod从apiserver中移除(这里只有resourceVersion发生了变化)
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/config.hash: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.mirror: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.seen: "2023-11-23T14:05:21.400551188+08:00"
kubernetes.io/config.source: file
creationTimestamp: "2023-11-23T06:05:21Z"
deletionGracePeriodSeconds: 0
deletionTimestamp: "2023-11-23T06:11:15Z"
name: nginx-static-pod-10.11.251.2
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: 10.11.251.2
uid: d2e3ebf6-2a70-434f-9142-0f74a1dd16bc
resourceVersion: "292110807"
uid: 1facfed2-ba67-40f8-9982-ab86a5e7fd33
新的mirror pod创建,uid为7bdace8a-8cc5-4cb4-886b-f3961f07d3b8
(pod的uid发生变化,status里只有phase和qosClass字段)
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/config.hash: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.mirror: a8712c005851ee6b29cff91b9ab4b9c6
kubernetes.io/config.seen: "2023-11-23T14:05:21.400551188+08:00"
kubernetes.io/config.source: file
creationTimestamp: "2023-11-23T06:11:15Z"
name: nginx-static-pod-10.11.251.2
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: 10.11.251.2
uid: d2e3ebf6-2a70-434f-9142-0f74a1dd16bc
resourceVersion: "292110808"
uid: 7bdace8a-8cc5-4cb4-886b-f3961f07d3b8
...
status:
phase: Pending
qosClass: BestEffort
mirror pod的status更新
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:21Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:29Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:29Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2023-11-23T06:05:21Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://b6ca55d329230c8f5776eb1160fe161d6fefa01f2b31e55dbb820add90aadccc
image: nginx:latest
imageID: docker-pullable://nginx@sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee
lastState: {}
name: nginx-container
ready: true
restartCount: 0
started: true
state:
running:
startedAt: "2023-11-23T06:05:29Z"
hostIP: 10.11.251.2
phase: Running
podIP: 10.26.124.96
podIPs:
- ip: 10.26.124.96
qosClass: BestEffort
startTime: "2023-11-23T06:05:21Z"
3 分析kubelet日志
mirror pod被删除
I1123 14:11:15.664065 315900 config.go:278] "Setting pods for source" source="api"
I1123 14:11:15.664544 315900 kubelet.go:2130] "SyncLoop DELETE" source="api" pods=[default/nginx-static-pod-10.11.251.2]
podWorker执行syncPod(由于在podWorker中使用static pod来判断状态,而static pod未被删除,所以不执行syncTerminatingPod)
I1123 14:11:15.664591 315900 pod_workers.go:888] "Processing pod event" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 updateType=0
I1123 14:11:15.664610 315900 kubelet.go:1554] "syncPod enter"
在syncPod中执行再次删除mirror pod
I1123 14:11:15.664893 315900 kubelet.go:1724] "Trying to delete pod" pod="default/nginx-static-pod-10.11.251.2" podUID=1facfed2-ba67-40f8-9982-ab86a5e7fd33
I1123 14:11:15.664900 315900 mirror_client.go:130] "Deleting a mirror pod" pod="default/nginx-static-pod-10.11.251.2" podUID=1facfed2-ba67-40f8-9982-ab86a5e7fd33
感知到pod再次删除,随后从apiserver中移除
I1123 14:11:15.671615 315900 config.go:278] "Setting pods for source" source="api"
I1123 14:11:15.671989 315900 kubelet.go:2130] "SyncLoop DELETE" source="api" pods=[default/nginx-static-pod-10.11.251.2]
I1123 14:11:15.674620 315900 config.go:278] "Setting pods for source" source="api"
I1123 14:11:15.675067 315900 kubelet.go:2124] "SyncLoop REMOVE" source="api" pods=[default/nginx-static-pod-10.11.251.2]
删除完成并创建新的mirror pod
I1123 14:11:15.675108 315900 kubelet.go:1729] "Deleted mirror pod because it is outdated" pod="default/nginx-static-pod-10.11.251.2"
I1123 14:11:15.675121 315900 kubelet.go:1740] "Creating a mirror pod for static pod" pod="default/nginx-static-pod-10.11.251.2"
I1123 14:11:15.683985 315900 config.go:383] "Receiving a new pod"
syncPod执行完成
I1123 14:11:15.684056 315900 kubelet.go:1556] "syncPod exit" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 isTerminal=false
I1123 14:11:15.684085 315900 pod_workers.go:988] "Processing pod event done" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 updateType=0
podWorker继续执行syncPod(这个是之前sync REMOVE触发)
I1123 14:11:15.684093 315900 pod_workers.go:888] "Processing pod event" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 updateType=0
I1123 14:11:16.053579 315900 kubelet.go:1554] "syncPod enter" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6
感知到新创建的mirror pod
I1123 14:11:15.684281 315900 kubelet.go:2114] "SyncLoop ADD" source="api" pods=[default/nginx-static-pod-10.11.251.2]
重新执行删除mirror pod,syncPod执行完成,podWorker执行完成
I1123 14:11:16.053912 315900 mirror_client.go:130] "Deleting a mirror pod" pod="default/nginx-static-pod-10.11.251.2" podUID=1facfed2-ba67-40f8-9982-ab86a5e7fd33
I1123 14:11:16.058466 315900 kubelet.go:1556] "syncPod exit" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 isTerminal=false
I1123 14:11:16.058484 315900 pod_workers.go:988] "Processing pod event done" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 updateType=0
podWorker继续执行syncPod(SyncLoop ADD触发的),然后执行完成
I1123 14:11:16.058491 315900 pod_workers.go:888] "Processing pod event" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 updateType=0
I1123 14:11:17.057755 315900 kubelet.go:1554] "syncPod enter" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6
I1123 14:11:17.058187 315900 kubelet.go:1556] "syncPod exit" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 isTerminal=false
I1123 14:11:17.058208 315900 pod_workers.go:988] "Processing pod event done" pod="default/nginx-static-pod-10.11.251.2" podUID=a8712c005851ee6b29cff91b9ab4b9c6 updateType=0
mirror pod status更新(这个是由statusManager里的syncBatch触发更新)
I1123 14:11:21.465237 315900 kubelet.go:2127] "SyncLoop RECONCILE" source="api" pods=[default/nginx-static-pod-10.11.251.2]
感知到mirror pod status更新
I1123 14:11:21.465237 315900 kubelet.go:2127] "SyncLoop RECONCILE" source="api" pods=[default/nginx-static-pod-10.11.251.2]
3.1 执行流程图
4 总结
根据上面的现象删除mirror pod并不会移除static pod,而且kubelet还会重新创建一个新的mirror pod,创建出来的mirror pod并没有status condition和container status,最后kubelet进行mirror pod的status更新。实际上对mirror pod的操作并不会影响static pod,因为static pod只在kubelet内部可见,外部可以通过apiserver上的mirror pod或kubelet的HTTP server上的/runningpods/
接口进行查询static pod状态。
从源码方面分析,每次syncLoop触发podWorker都执行syncPod。
在syncPod里处理static pod逻辑:
- 如果该pod是static pod且mirror pod存在,检测这个mirror pod是否是这个static pod的合法镜像pod。如果不是合法mirror pod,则把这个mirror pod删除。
- 如果这个mirror pod已经被删除,则执行最后删除动作(设置deletionGracePeriodSeconds为0)。
- 如果static pod没有mirror pod,则创建mirror pod。
代码在 pkg/kubelet/kubelet.go#L1761-L1798
// Create Mirror Pod for Static Pod if it doesn't already exist
// 如果是static pod,则检查是否存在mirror pod,当mirror pod不存在时候进行创建
if kubetypes.IsStaticPod(pod) {
deleted := false
// 存在mirror pod
if mirrorPod != nil {
// mirrorPod被删除或mirrorPod不是pod的mirror pod
if mirrorPod.DeletionTimestamp != nil || !kl.podManager.IsMirrorPodOf(mirrorPod, pod) {
// The mirror pod is semantically different from the static pod. Remove
// it. The mirror pod will get recreated later.
klog.InfoS("Trying to delete pod", "pod", klog.KObj(pod), "podUID", mirrorPod.ObjectMeta.UID)
// pod.Name + "_" + pod.Namespace
podFullName := kubecontainer.GetPodFullName(pod)
var err error
// 调用api删除mirror pod(从podFullName解析出name和namespace)
deleted, err = kl.podManager.DeleteMirrorPod(podFullName, &mirrorPod.ObjectMeta.UID)
if deleted {
klog.InfoS("Deleted mirror pod because it is outdated", "pod", klog.KObj(mirrorPod))
} else if err != nil {
klog.ErrorS(err, "Failed deleting mirror pod", "pod", klog.KObj(mirrorPod))
}
}
}
// static pod没有mirror pod或mirror pod被删除,则在获取node未发生错误且node未被删除条件下,创建mirror pod
if mirrorPod == nil || deleted {
node, err := kl.GetNode()
// 当获取node发生错误或node被删除,则无需创建mirror pod
if err != nil || node.DeletionTimestamp != nil {
klog.V(4).InfoS("No need to create a mirror pod, since node has been removed from the cluster", "node", klog.KRef("", string(kl.nodeName)))
} else {
klog.V(4).InfoS("Creating a mirror pod for static pod", "pod", klog.KObj(pod))
// node没有被删除,则创建static pod的mirror pod
if err := kl.podManager.CreateMirrorPod(pod); err != nil {
klog.ErrorS(err, "Failed creating a mirror pod for", "pod", klog.KObj(pod))
}
}
}
}