很多朋友问我,到底怎么把一套 kubernetes 集群在最短时间内搭起来,既不是那种只能在笔记本上跑的单机玩具,也不是需要手动维护几十个二进制服务的硬核模式。我的答案一直是同一个:kubeadm。它是 Kubernetes 官方提供的集群初始化工具,也是我这些年搭测试环境、给团队做学习平台、甚至在正式环境做基础验证时用得最多的方式。用 kubeadm 快速部署一个 kubernetes 集群,从一台裸机到 master 节点就绪,大概十几分钟;再加上 worker 节点、网络插件、验证应用,一个小时内你就能拥有一套标准、可用、能继续扩展的 k8s 集群。
读这篇博文的人,我猜大概有三类:第一类是刚接触 k8s,想把官方工具链完整走一遍的新手;第二类是手头有虚拟机或内网服务器,需要快速搭一套用于开发和测试的环境;第三类是准备考证或者在生产环境做小范围验证的工程师。不管你是哪类,都不需要预先掌握太多原理。照着步骤操作一遍,再回头理解设计思路,会比死记命令快很多。
1. 为什么我推荐 kubeadm,而不是 minikube 或二进制部署
1.1 kubeadm 到底替你做了什么
很多人第一次接触 kubeadm 时,容易把它理解成“一键安装脚本”。实际上它做的事情比脚本更克制,也更巧妙。kubeadm init主要负责两件事:一是生成控制平面组件所需的一整套证书、私钥、kubeconfig 配置文件;二是把 etcd、kube-apiserver、kube-controller-manager、kube-scheduler 这些控制平面组件以静态 Pod 的方式,放到/etc/kubernetes/manifests目录下,交给 kubelet 来拉起和维护。
这个设计非常关键。控制面组件不再需要各自注册成 systemd 服务,而是统一用 Pod 清单来描述。任何组件的配置、日志、重启行为都变成了 Pod 级别,你可以用kubectl get pods -n kube-system查看状态,也可以借助容器运行时直接看日志。这种“用 kubelet 管控制面”的思路,从根源上降低了排障复杂度。kubeadm join则负责把工作节点接入集群:它会验证 token 和证书指纹,生成该节点单独的 kubelet 证书和引导配置,让节点上的 kubelet 去访问 apiserver 完成注册。
1.2 几种部署方式,到底该选哪个
我一直建议初学者用一张表格把常见方式放在一起比,比单独理解一个工具更清楚。这里是我自己的对比结论:
| 部署方式 | 适合场景 | 控制面组件形态 | 网络插件 | 生产适用性 | 学习价值 |
|---|---|---|---|---|---|
| minikube | 本地单机学习 | 单节点,通常不关注控制面细节 | 内置 | 不适合 | 中 |
| kind | 本地或 CI 跑测试 | 容器化的单/多节点 | 内置或自装 | 不适合 | 中 |
| kubeadm | 测试环境、生产基础 | 静态 Pod,由 kubelet 托管 | 自选 | 适合 | 高 |
| Kubespray | 大规模生产、批量部署 | 以容器方式运行控制面 | 自选 | 适合 | 中 |
| 二进制部署 | 深度定制、信创环境 | systemd 服务 | 自选 | 适合但维护重 | 很高 |
从这张表能看出来,kubeadm 的定位非常像“折腾和生产的折中点”:它保留了官方组件编排方式,没有引入太多额外抽象,生产环境中多控制面高可用方案就是基于它扩展的。如果你用二进制部署,确实能深入理解每一个组件的启动参数,但时间成本高很多,也不容易迁移到自动化的运维体系里。minikube 和 kind 则更适合个人电脑上做功能验证,它们对网络插件、多节点通信的模拟并不完全真实。
1.3 kubeadm 作为生产起点的三个理由
第一,升级路径清晰。Kubernetes 每三个月发一个小版本,安全更新很重要。kubeadm 提供kubeadm upgrade plan和kubeadm upgrade apply,官方会提前验证升级路径,你只需要按顺序处理控制面和节点。第二,证书管理内置。kubeadm 会自动生成 CA 和各组件证书,并提供kubeadm certs renew续期命令。第三,配置可查看、可审计。kubeadm config view能把集群初始化配置导出成 YAML,方便你保存到 Git 仓库里做变更管理。
我见过不少团队用 kubeadm 初始化后,再配合 Terraform、Ansible 或者裸机平台来自动化,效果相当好。它的配置结构简单、依赖少,不管上层用什么编排,底层始终是同一套标准目录和清单。
2. 部署前那些关键准备,漏一个都要回头补
2.1 节点规划:多大机器才够用
先说结论:如果你只是学习和验证,一台 master 加两台 worker 是最舒服的配置,保证能观察到 Pod 调度到不同节点的真实效果。单节点也可以,但你需要容忍 Master 和 Worker 混跑带来的 taint 处理,而且很多网络插件在单节点下容易出现与预期不符的情况。
硬件方面,控制面节点建议至少 2 核 4G 内存,工作节点建议 2 核 2G 起步。内存低于 2G 时,etcd 会频繁触发 OOM,哪怕集群起来了也会非常不稳。磁盘最好是 SSD,尤其 etcd 的数据目录/var/lib/etcd对 IO 延迟敏感。操作系统我建议选 Debian 系的长期支持版本,比如 Ubuntu 22.04 或 Debian 12,内核版本够新,对 overlay 网络和 iptables 的支持也友好。所有节点的主机名不要重复,比如k8s-master-01、k8s-node-01,并且建议在/etc/hosts里写好互相解析,避免有些组件反向解析出问题。
2.2 系统初始化四件套,每件都有原因
第一件事是关闭 swap。kubelet 在资源管理上假设节点没有 swap,如果开着,它统计内存水位时会出错,节点也会经常处于 Ready 但调度不稳定的状态。执行:
sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab第二件事是加载内核模块overlay和br_netfilter。前者是容器分层文件系统的底层依赖,后者让网桥流量能通过 iptables/netfilter 规则进行处理,这是 kube-proxy 和网络插件工作的前提。
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter第三件事是设置 sysctl 参数。有两个参数非常关键:net.bridge.bridge-nf-call-iptables=1确保经过 Linux 网桥的流量也受 iptables 规则管控;net.ipv4.ip_forward=1开启内核转发,Pod 之间的跨节点通信、Service 的转发都依赖它。
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sudo sysctl --system第四件事是时间同步。Kubernetes 的证书校验、日志时间戳、etcd 的一致性都依赖各节点时间接近。生产环境里节点时间漂移超过几百毫秒就可能引发奇怪问题。建议所有节点统一配置 NTP 时间同步服务,如果你用的是云主机,一般默认就带;裸机的话需要自己确认一下。
2.3 容器运行时:现在默认选 containerd
从 Kubernetes 1.24 开始,内置的 dockershim 被移除,官方默认推荐使用 containerd 作为容器运行时。你当然也可以用 CRI-O,但 containerd 生态成熟、兼容性最好,也是绝大多数发行版的默认选择。
安装 containerd 的方式很多,Debian/Ubuntu 上直接:
sudo apt-get update sudo apt-get install -y containerd安装后需要生成默认配置,并做一处关键修改:
sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml打开/etc/containerd/config.toml,找到SystemdCgroup这个配置。默认值是false,需要改成true:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] ... [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true这一步太容易踩坑了。kubelet 默认使用 systemd 作为 cgroup 驱动,containerd 如果还在用 cgroupfs,两边就不一致,节点注册后会一直处于 NotReady 状态,而日志里只会报一些含糊的 cgroup 错误。改完配置后重启 containerd 并设置开机自启:
sudo systemctl restart containerd sudo systemctl enable containerd2.4 安装 kubeadm、kubelet、kubectl
这三个工具建议在所有节点都装上,版本必须保持一致。官方提供了软件源,以 v1.30 为例:
sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl安装后一定记得锁定版本:
sudo apt-mark hold kubelet kubeadm kubectl不锁定版本的后果很直接:下次你执行apt-get upgrade,kubeadm 可能自动升到新版,kubelet 还在旧版,两边不兼容,集群直接罢工。安装完成后可以检查版本:
kubeadm version kubelet --version kubectl version --client这里有个需要留意的细节:无论是否使用官方源,你都要确认当前节点能访问你选择的软件源。如果是内网环境,提前把 deb 包镜像好,统一分发,比所有节点各自访问外网要稳定得多。
3. 初始化 master 节点,关键参数一次说明白
3.1 先看懂这条 init 命令再执行
在 master 节点上,最重要的就是一条命令。我建议你不要直接复制网上看到的命令,而是先理解每个参数的含义:
sudo kubeadm init \ --apiserver-advertise-address=192.168.1.10 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --image-repository=registry.k8s.io \ --kubernetes-version=v1.30.2参数逐个说。
--apiserver-advertise-address是 master 节点上 kube-apiserver 对外通告的 IP 地址。kubectl、worker 节点、外部负载均衡器都会连这个地址。如果节点有多块网卡,必须明确指定,否则可能出现 APIServer 监听在 0.0.0.0,但证书和负载均衡连接的 IP 不对的情况。
--pod-network-cidr是 Pod 网段。你之后安装网络插件时,插件默认的 CIDR 必须和它一致,否则 Pod 之间跨节点通信会断掉。这里我写10.244.0.0/16,是 Flannel 插件默认使用的网段;如果你计划用 Calico,它的默认网段是192.168.0.0/16,那 init 参数就要改成--pod-network-cidr=192.168.0.0/16。选哪个插件,提前想好,避免事后返工。
--service-cidr是 Service 的虚拟网段,默认10.96.0.0/12,一般不需要改。但要注意一点:这个网段一旦确定,后续很难变更,因为 kube-proxy 的 iptables 规则、DNS 的 ClusterIP 都会基于它生成。
--image-repository是控制面组件镜像的仓库地址。默认是registry.k8s.io,如果你的网络访问它不稳定,就换成一个本地可达的镜像同步仓库。第一次初始化建议先执行kubeadm config images pull --image-repository=<你的仓库>,确认镜像能拉下来再真正 init,能省很多等待时间。
--kubernetes-version建议明确写上,不要省略。省略时 kubeadm 会用最新稳定版,而你本地的 kubectl、kubelet 可能锁定在另一个版本,版本不匹配会引起很多奇怪问题。
3.2 执行 init,留意输出里的三块信息
执行 init 后,kubeadm 会做一系列预检,包括端口占用、swap 状态、内核参数等。如果预检失败,它会明确告诉你哪一项没过。预检通过后开始拉镜像、生成证书、启动静态 Pod,这一步可能需要几分钟。
init 成功时,最后一段输出会非常显眼:
Your Kubernetes control-plane has been initialized successfully!然后会给出三块你马上要用的信息。第一块是配置 kubectl 的命令:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config这一步一定要做,否则 kubectl 不知道集群在哪里。第二块是一整条kubeadm join命令,它包含 token 和--discovery-token-ca-cert-hash,是 worker 节点加入集群的钥匙。建议先存到本地文本文件里,后边要用。第三块是说明:Pod 网络尚未就绪之前,master 节点会一直显示 NotReady,这是正常现象,不用慌。
3.3 接入 Calico 网络插件
Pod 网络不装,节点永远无法 Ready,核心 DNS 服务也会一直 CrashLoopBackOff。网络插件我优先推荐 Calico,它性能不错,功能也多。
安装 Calico 的方式通常是这样:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico.yaml如果你在 init 时指定的--pod-network-cidr不是 Calico 默认的192.168.0.0/16,就需要先下载清单文件,找到环境变量CALICO_IPV4POOL_CIDR,改成你实际使用的网段,再 apply。这也是为什么我建议先把 CIDR 规划好,再初始化。
Calico 的清单里包含了一个 DaemonSet,会在每个节点上启动 calico-node Pod,同时安装 CNI 插件、生成/etc/cni/net.d/配置。这一步顺利完成后,等所有 calico 相关 Pod 进入 Running,再执行kubectl get nodes,节点应该会变成 Ready 状态。网络插件安装过程中偶尔会出现 calico-node 反复重启的情况,最常见原因是CALICO_IPV4POOL_CIDR和 init 参数不一致,或者节点时间不同步导致的证书问题。
3.4 控制平面组件都健康了吗
初始化完成、网络插件装好后,第一件事就是看核心组件状态:
kubectl get nodes kubectl get pods -Akubectl get nodes应该能看到 master 节点状态为 Ready;kubectl get pods -A能看到 kube-system 命名空间下的 etcd、kube-apiserver、kube-controller-manager、kube-scheduler、coredns、calico-node 等 Pod 都处于 Running 状态。
这里我想特别提醒一下:很多人习惯用kubectl get componentstatus来看控制面健康状态,但从很多版本开始,这个命令输出的结果已经不再反映真实情况了,它可能显示 etcd 是 healthy,但实际上 etcd Pod 早就坏了。不要依赖它,直接看 Pod 状态才是准确的。
4. 把 worker 节点加进来,让集群真正“集”起来
4.1 join 命令从哪儿来
worker 节点加入集群最标准的方式就是执行一条kubeadm join命令。这条命令在 init 成功输出里会直接打印出来,长这样:
kubeadm join 192.168.1.10:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>如果你当时没保存,可以在 master 节点上重新生成:
kubeadm token create --print-join-command这个命令的简介之处在于,它会自动生成 token,同时算出 CA 证书的 hash 并拼成完整命令。token 默认有效期是 24 小时,过期后重新跑一次就行。
有个细节值得展开:--discovery-token-ca-cert-hash的作用是让节点验证 master 的 CA 证书是否是可信的那张。简单说,它能防止你加入一个伪装成 master 的中间人。如果你从别处抄来的命令省略了这个参数,kubeadm 会进入交互式确认流程,不安全也不方便。
4.2 在 worker 节点上执行 join
在每个 worker 节点上,用 root 或者 sudo 执行上面的 join 命令。执行过程中,kubelet 会启动,节点会自动向 master 发起注册。执行完,回到 master 节点:
kubectl get nodes你就能看到新的 worker 节点出现在列表里。刚加入时它的状态大概率是 NotReady,因为 Calico 的 Pod 还没在这台机器上启动,网络插件还没有就绪。等几十秒到几分钟,再执行一次,状态就会变成 Ready。
这里还要提一个常见误区:有人会想“我能不能在 master 节点上 join 一次,让这台机器同时成为 worker 节点?”理论上可以,但默认 init 会给 master 打上node-role.kubernetes.io/control-plane的污点,普通工作负载不会调度上去。如果你确实想跑测试负载,需要单独去掉污点,而不是把一个节点既当 master 又当 worker 去 join。
4.3 跑个 nginx 验证集群是真的能用
节点全部 Ready 后,别急着收工,跑一个真实工作负载验证。我习惯用一个简单的 Deployment:
kubectl create deployment nginx --image=nginx:1.25 kubectl scale deployment nginx --replicas=3 kubectl get pods -o wide这时候你能看到三个 nginx Pod 分布在不同的节点上,这就是集群调度能力的直接体现。接着创建一个 Service 暴露它:
kubectl expose deployment nginx --port=80 --type=NodePort kubectl get svc nginx能看到 Service 分配了一个 NodePort 端口,可能是 30000 到 32767 之间的某个值。然后你从集群外部访问任意节点的这个端口,比如http://192.168.1.10:30080,如果 Nginx 页面正常返回,说明 Pod 网络、Service 转发、节点到容器的链路全部通畅。这一步的验证价值非常大,因为它同时验证了 kube-proxy 的 iptables 规则、CNI 的跨节点网络以及 DNS 转发能力。
5. 实操中最常见的坑,我全部帮你踩过
5.1 卡在等待 API server:镜像跟不上
现象是kubeadm init执行后一直停在“waiting for the Kubernetes API server to start”,日志里能看到一堆拉镜像失败的记录。最常见原因就是镜像仓库访问不稳定。解决办法有两个:第一个是在 init 前先执行kubeadm config images pull --image-repository=<你的仓库>,确认所有镜像都能拉下来;第二个是 init 时直接指定--image-repository参数,换成你本机可访问的镜像同步仓库。
如果已经卡住了,不用无限等待。先kubeadm reset -f清理现场,重新换镜像源再 init。很多人喜欢反复在同一台机器上试,残留的 etcd 数据和证书会干扰下一次初始化,所以 reset 之后最好再手动清理残留目录,下一小节我会展开。
5.2 节点 NotReady:按顺序查三处
节点状态一直是 NotReady,是出现频率最高的问题。我的排查顺序固定为三个层次。
第一层,查容器运行时:
systemctl status containerd确保 containerd 在运行且没频繁重启。
第二层,查 kubelet:
sudo systemctl status kubelet sudo journalctl -u kubelet -fkubelet 日志是定位问题最直接的信息源。最常见的报错有两个:一个是 cgroup 驱动不匹配,提示failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd" but is not a valid systemd cgroup driver,这种就是 containerd 配置里的SystemdCgroup没有改成true;另一个是 CNI 网络插件没就绪,报错network plugin is not ready: cni config uninitialized,对应 Calico Pod 没起来,或者 CIDR 不一致。
第三层,查 CNI 状态:
kubectl get pods -A -o wide | grep calico如果 calico-node Pod 一直 CrashLoopBackOff,去容器日志里找具体原因。实际遇到较多的是节点时间偏移导致证书验证失败,或者CALICO_IPV4POOL_CIDR与--pod-network-cidr不一致。
我记忆里有个真实案例:一台节点重启后,containerd 虽然安装了,但没配置开机自启,结果重启后 containerd 没起来,kubelet 一直拉不到容器。排查日志才发现根本不是网络问题,而是运行时没活着。所以第三层确认完之后,再回来看系统服务状态,往往能找到问题根源。
5.3 token 过期或 hash 校验失败
现象是执行 join 命令时提示 token 无效,或者--discovery-token-ca-cert-hash校验失败。原因通常是 token 超过 24 小时有效期,或者你从旧文档里抄了一条早就失效的命令。
解决办法很简单,在 master 节点上执行:
kubeadm token create --print-join-command它会返回一条完整可用的新命令。如果你手里的 join 命令是从别人那里抄来的,只有 token 没有 hash,也可以用下面的方式算出当前 CA 证书的 hash:
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'把输出拼到 join 命令里就行。这个技巧在调试高可用集群时尤其有用,因为多控制面节点加入时也需要这个 hash。
5.4 重复初始化前一定要彻底清理
很多新手在部署失败后,直接再跑一次kubeadm init,结果报端口被占用、证书已存在等错误。原因很简单:上一次失败留下的痕迹没有清理干净。
标准操作是:
sudo kubeadm reset -f sudo rm -rf /etc/kubernetes /var/lib/etcd ~/.kube /etc/cni/net.d sudo systemctl restart containerdkubeadm reset会尝试停止 kubelet 和清理容器,但某些残留文件可能不会被自动删除。手动删掉/etc/kubernetes(证书、静态 Pod 清单)、/var/lib/etcd(etcd 数据)、~/.kube(客户端配置)、/etc/cni/net.d(CNI 配置)这几处,基本能恢复到干净状态。
这里提醒一下:如果你已经给某个节点执行了 join,再对 master 执行 reset 前,最好先在 master 上kubectl delete node 对应节点名,避免残留对象。
5.5 证书只有一年,躺平不管会付出代价
Kubernetes 用 kubeadm 生成的集群,默认各组件证书有效期是一年。很多测试环境跑着跑着突然 apiserver 连不上了,一看日志才发现证书过期。
平时养成习惯,定期检查:
kubeadm certs check-expiration如果发现快到期,在证书过期前执行:
kubeadm certs renew all然后重启控制面组件。重启方式因为控制面是静态 Pod,最简单的方法是删除对应的 manifest 目录下文件让 kubelet 重建,或者直接重启 kubelet。证书续期本身不影响 etcd 数据和已有的 Pod,但建议操作前看一遍官方文档。
如果你管理的集群已经过了证书有效期,apiserver 起不来了,处理起来更麻烦,需要先重置时间窗口或者手动恢复证书。所以我的习惯是设置定期任务检查证书有效期,避免被动。这一点在生产环境里尤其重要。
6. 从测试环境到生产环境,还差这几步
6.1 高可用:多 master 和负载均衡
单 master 集群不适合作为生产环境,因为控制面一旦宕机,整个集群的调度和 API 无法工作。kubeadm 官方支持部署多控制面高可用集群,核心思路是在 kubeadm init 时加参数:
--control-plane-endpoint=<负载均衡地址>这个地址通常是集群外部的一个负载均衡器,比如 keepalived + haproxy 的组合,或者是云平台提供的负载均衡服务。它会把多个 master 节点的 6443 端口统一暴露成一个地址。之后每个 master 节点用相同参数初始化,其余 master 节点通过kubeadm join并加上--control-plane标志加入。
高可用还需要考虑 etcd 的部署方式。kubeadm 默认把 etcd 和控制面放在一起,三个 master 节点就组成一个三节点 etcd 集群。如果对数据安全要求高,也可以使用外部 etcd,但这属于进阶用法,官方文档里有单独的说明。我会先建议:学习阶段不必上高可用,但规划生产时一定要把它列入第一优先级。
6.2 版本升级:用好 kubeadm 自带的能力
Kubernetes 的版本迭代很快,安全更新也频繁。kubeadm 提供了相对清晰的升级路径。大致流程是:先升级 kubeadm 和 kubelet,再执行kubeadm upgrade plan查看可升级的版本,然后运行kubeadm upgrade apply升级控制面,最后到每个 worker 节点执行kubeadm upgrade node。
升级有两个容易踩的坑。第一,不要跨大版本跳级,建议从小版本到小版本稳步升级。第二,升级前重新检查证书有效期,kubeadm upgrade apply会自动更新相关证书,但最好先备份/etc/kubernetes目录。升级过程中,控制面组件会依次重启,短时间内的 API 不可用是正常的,生产环境升级要选维护窗口。
6.3 生产化补充:监控、日志与网络规划
集群能跑起来只是开始,真正要到生产环境,还需要考虑几个方面。监控方面,部署 Metrics Server 拿资源指标是基础,再配合一套完整的监控告警系统才能放心。日志方面,需要一套统一的日志采集链路,把所有节点容器 stdout 和文件日志集中到一起,否则日志分散在各节点,排查问题非常痛苦。镜像方面,如果团队里多人使用,最好搭建私有镜像仓库,并把集群的拉取策略配置好,避免每次都去公网拉取。
最后还想再强调一遍网络规划。Pod CIDR 和 Service CIDR 一旦确定,后续几乎无法修改,因为它们被写进了很多组件的证书、配置和 iptables 规则里。我在生产环境见过因为 CIDR 设计不合理,导致 Pod 数量不足,最后不得不整个集群重新搭建的案例。提前规划好网段,预留足够空间,是成本最低的“保险”。
我个人在实际操作中的体会是:kubeadm 这套工具链最大的价值,是让你能够按标准方式快速搭建集群,同时又不掩盖 Kubernetes 的运行机制。无论踩了多少坑,只要你理解静态 Pod 的托管逻辑、cgroup 驱动的一致性、网络插件的 CIDR 对齐这三点,大部分问题都能快速定位。最后再分享一个小技巧:每次用 kubeadm 初始化前,先手动执行一次kubeadm config images pull,确认镜像链路通畅,这一个小小的动作,能帮你省下好几次 reset 的时间。