kubeadm init卡在[wait-control-plane]根本原因是kubelet未健康就绪,常见于swap未彻底关闭、cgroup驱动不一致(systemd/cgroupfs)、containerd配置错误、br_netfilter未加载或镜像拉取失败。

Kubernetes 不是“装完就能用”的黑盒,快速安装(如 kubeadm、kind、minikube)掩盖了大量底层依赖和状态初始化逻辑;跳过原理直接部署,90% 的集群启动失败、网络不通、Pod 无法 Ready 都源于对初始化阶段的误判。
为什么 kubeadm init 会卡在 [wait-control-plane] 或 etcd 健康检查失败
kubeadm init 并非单纯启动组件,而是按严格顺序执行一系列原子检查与初始化:
- 先验证系统参数:swapoff -a 必须生效、iptables -P FORWARD ACCEPT 必须设置、内核模块 br_netfilter 和 overlay 必须加载
- 再拉起临时 etcd 实例(使用 etcdctl 检查 /health 端点),若宿主机 Docker/containerd 的 cgroup driver(systemd vs cgroupfs)与 kubeadm 配置不一致,etcd 容器会因无法挂载 cgroup 路径而静默退出
- 最后才生成 kubeconfig、证书、Static Pod 清单并交由 kubelet 加载;此时若 kubelet 未配置为监听 /var/lib/kubelet/pki/ 下的 bootstrap 证书,API Server 就永远收不到节点心跳
常见错误现象:
-
kubectl get nodes返回空列表,但docker ps显示etcd、apiserver容器在运行 → kubelet 未成功注册 Node 对象,大概率是证书信任链断裂或 CRI socket 路径错配 -
kubeadm init卡在[wait-control-plane]→ 检查journalctl -u kubelet -n 100 --no-pager,90% 是failed to load KubeConfig或cgroups: cannot found cgroup mount destination
minikube 启动快,但它绕过了哪些真实集群必须面对的问题
minikube start 本质是启动一个单节点 VM(或容器),把所有 Control Plane 组件塞进一个进程空间(如 localkube 模式)或一组 tightly-coupled 容器中,并禁用多数生产级约束:
- etcd 默认单节点且无 Raft 成员管理,etcdctl member list 只返回本机 ID,无法模拟多节点脑裂场景
- kube-proxy 默认用 iptables 模式,但跳过 ip_vs 模块加载检查;若后续切换 IPVS,会因内核模块缺失直接 panic
- CNI 插件(如 cni-plugins)被预装进镜像,但不校验 /etc/cni/net.d/ 下配置是否匹配当前网络命名空间 —— 这导致你在 minikube 里跑通的 Pod 网络策略,在真实集群上因 calico/node 启动顺序或 BGP 邻居发现失败而彻底不通
使用场景提醒:
- 仅用于本地功能验证(YAML 语法、Deployment 基本行为)
- 不可用于测试 Service DNS 解析延迟、EndpointSlice 同步时效、kube-proxy 规则更新抖动等依赖真实网络栈的行为
-
minikube ssh进入后看到的/var/lib/etcd是 hostPath 挂载,不是独立文件系统,df -h显示的是宿主机磁盘,容易误判 etcd 存储压力
kubeadm 生成的 Static Pod 清单为什么不能手动改 YAML 直接 apply
Control Plane 组件(apiserver、controller-manager、scheduler、etcd)在 kubeadm 集群中全部以 Static Pod 方式运行,其清单位于 /etc/kubernetes/manifests/,由 kubelet 直接监控文件系统变化。但这些文件不是普通 YAML:
- 所有证书路径硬编码为 /etc/kubernetes/pki/ 下的固定位置,修改 volumeMounts 会导致组件启动失败
- etcd.yaml 中的 --initial-cluster 参数由 kubeadm 在 init/join 时动态注入,手改后 join 新节点会因集群成员信息不一致被拒绝
- apiserver.yaml 的 --advertise-address 来自 kubeadm init 时探测的网卡,默认不等于 hostname -i,强行替换可能造成 kubelet 无法连接 API Server
性能影响注意点:
- Static Pod 无 ReplicaSet 管理,组件崩溃后仅由 kubelet 重启,不会触发调度重试或跨节点迁移
- 若修改
resources限制,需同时调整 kubelet 的--system-reserved,否则 cgroup OOM Killer 可能先杀掉 etcd 进程而非应用容器
真正决定“安装是否成功”的三个不可跳过的验证点
快速安装工具只负责组件就位,能否稳定交付取决于以下三件事是否闭环: - etcd 数据一致性:运行etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint health,返回 healthy 且 isLeader=true
- API Server 可写性:执行 curl -k https://127.0.0.1:6443/api/v1/namespaces/default -X POST -H "Authorization: Bearer $(cat /etc/kubernetes/admin.conf | grep 'token:' | awk '{print $2}')" -H 'Content-Type: application/json' -d '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"test-validate"}}',能创建 namespace 才算 API Server 认证+授权链路通
- CNI 插件就绪:kubectl get pods -n kube-system 中所有 cni 相关 Pod(如 calico-node、coredns)必须为 Running 且 Ready 为 1/1;若 coredns 长期 Pending,大概率是 Node 未打 node-role.kubernetes.io/control-plane 标签,或 calico 的 IP_AUTODETECTION_METHOD 识别错了网卡
最常被忽略的复杂点:etcd 的 WAL 日志刷盘策略与宿主机 I/O 调度器强耦合。SSD 上默认 deadline 调度器可接受,但机械盘若仍用 cfq,etcd 写入延迟飙升会导致 kube-apiserver 请求超时,进而引发 controller-manager 失联 —— 此时看日志全是 “context deadline exceeded”,没人想到要查 cat /sys/block/sda/queue/scheduler。











