bigywater.tech
Kubernetes · 80

静态 Pod:控制平面组件为什么是文件

为什么 kube-apiserver 自己是个 Pod?静态 Pod 和普通 Pod 有什么区别?kubectl delete 一个静态 Pod 会怎样?这篇用 kind 控制面节点的真实目录和往 worker 放文件的实验,把静态 Pod 的创建、修改、删除和限制都走一遍。

4 个文件
控制面节点 manifests 目录里的 etcd / apiserver / controller-manager / scheduler 就是 4 个静态 Pod
0.6 秒
往 worker 的 manifests 目录放一个文件,到 API 里出现镜像 Pod 并 Running 的时间
~90 秒
kubectl delete 镜像 Pod 后,kubelet 把它重建的时间(单次测量 86~89 秒)

控制面组件就是文件

实测 · 本机执行输出
  kubelet 配置 staticPodPath:staticPodPath: /etc/kubernetes/manifests
  控制面节点 /etc/kubernetes/manifests/:['etcd.yaml', 'kube-apiserver.yaml', 'kube-controller-manager.yaml', 'kube-scheduler.yaml']
  worker 节点 /etc/kubernetes/manifests/:(空)
  kube-system 里 config.source=file 的 Pod:['etcd-kx-main-control-plane', 'kube-apiserver-kx-main-control-plane', 'kube-controller-manager-kx-main-control-plane', 'kube-scheduler-kx-main-control-plane']
  kube-apiserver-kx-main-control-plane 的元数据:annotations 里 config.source=file,config.mirror=<hash>:True;ownerReferences=[('Node', 'kx-main-control-plane')];spec.nodeName=kx-main-control-plane

kubelet 配置里 staticPodPath: /etc/kubernetes/manifests。控制面节点这个目录下有 etcd.yaml、kube-apiserver.yaml、kube-controller-manager.yaml、kube-scheduler.yaml,正是 kube-system 里 kubernetes.io/config.source=file 的那 4 个 Pod。它们在 API 里是“镜像 Pod”:带 config.mirror 注解,ownerReferences 指向 Node。worker 节点的这个目录是空的。

放一个文件

实测 · 本机执行输出
  放入 hello.yaml 后 0.6 秒,API 里出现镜像 Pod hello-static-kx-main-worker(名字 = 文件里的 name + "-" + 节点名),phase=Running;uid=a6d5f3b9…
  它的 ownerReferences=[('Node', 'kx-main-worker')];annotations 里 config.source=file;tolerations=[(None, 'Exists', 'NoExecute')]
  kubectl delete 掉这个镜像 Pod:89 秒后又出现了(新的镜像 Pod uid=63e3ad89…;kubelet 周期性发现缺少镜像 Pod 并重建);节点上的容器一直在跑(crictl ps 里 1 个)——删的只是 API 里的影子

往 worker 的 manifests 目录放 hello.yaml,0.6 秒后 API 里就出现镜像 Pod hello-static-kx-main-worker(名字是文件里的 name 加 - 加节点名),phase 为 Running,ownerReferences 是 Node,带一条 Exists / NoExecute 的容忍。kubectl delete 掉这个镜像 Pod:约 86~89 秒后 kubelet 把它重新建出来(新 uid),节点上的容器一直没动——被删的只是 API 里的影子,真正的 Pod 由文件决定。

修改与删除

实测 · 本机执行输出
  把 echo v1 改成 echo v2:12.1 秒后 API 里的 Pod spec 已是 v2;0.0 秒内重新 Running;restartCount=0
  删除 hello.yaml 后 3.7 秒,镜像 Pod 从 API 消失;节点上容器 0 个

用 sed 把 echo v1 改成 echo v2:12.1 秒后镜像 Pod 的 spec 变成 v2,kubelet 按新文件重建了容器。rm hello.yaml:3.7 秒后镜像 Pod 从 API 消失,节点上的容器是 0 个。要停掉静态 Pod,只有删文件这一条路。

不能引用 API 对象

实测 · 本机执行输出
  静态 Pod 的容器里引用 ConfigMap(envFrom.configMapRef):kubectl get 退出码 1;Error from server (NotFound): pods "bad-static-kx-main-worker" not found
  kubelet 日志:['err="can\'t process config file \\"/etc/kubernetes/manifests/bad.yaml\\": static pods may not reference configmaps"']
  节点上有 bad-static 的沙箱吗:0 个

静态 Pod 的容器里写 envFrom.configMapRef:kubectl 里没有这个 Pod,节点上也没有沙箱,kubelet 日志是 can't process config file "/etc/kubernetes/manifests/bad.yaml": static pods may not reference configmaps。静态 Pod 不能引用 ConfigMap、Secret、ServiceAccount 等 API 对象——它们要在 API Server 还没起来时就能运行。

分步演示

静态 Pod
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0),在 worker 上用 docker exec 写入 /etc/kubernetes/manifests;每个耗时都是 0.2~1 秒间隔轮询得到的单次测量,其中“kubectl delete 镜像 Pod 后重建”在三次运行里分别是 86、89、89 秒左右,“改文件”是 12~14 秒;kubelet 日志用 journalctl 读取;每种情形各一次
    • 没有验证:kubeadm 升级控制面时对 manifests 的处理;静态 Pod 的 kubelet 参数 --pod-manifest-path 与 staticPodURL(HTTP 拉取);静态 Pod 失败时的重启策略与 crashloop;镜像 Pod 的 spec 是否可编辑(API 层面禁止);静态 Pod 用的 priorityClass;多控制面节点的 manifests 一致性;kubelet 读文件的并发问题(实验中 kubelet 曾在文件写入一半时读到一次 Kind is missing 的错误)
    京ICP备2026067502号-1京公网安备11010502063487号