K8s安装踩坑全记录:kubeadm初始化与CNI网络插件配置

📅 发布时间:2026/10/20 11:23:46
K8s安装踩坑全记录:kubeadm初始化与CNI网络插件配置
K8s安装这件事说难不难说简单也不简单。最近我在某交付项目X里搭一套Kubernetes集群1台控制平面加2台工作节点本以为也就是几条命令的事结果从初始化到网络插件前前后后踩了一串坑。cgroup驱动不一致、pause镜像拉不下来、节点一直NotReady、CNI网络起不来这些问题对老手来说也许只是“十分钟排查”但对第一次装K8s的人任何一个都能让你卡住半天。这篇笔记就把我实际踩过的、排查过的问题和最终处理方式完整记录下来给正准备安装K8s的朋友一个参考。无论你是运维、开发还是想自己折腾一套集群的爱好者应该都能从中找到对应场景的解法。1. 安装前的版本选择与环境规划1.1 版本组合先定好能少踩一半坑K8s安装里最容易被忽略的其实是版本匹配。很多人习惯“最新版下载”结果kubeadm、kubelet、kubectl三个二进制版本不一致初始化时直接报错或者节点加入集群时出现未知版本错误。我这次选的是Kubernetes 1.28.5搭配containerd 1.7.x。为什么要强调版本组合因为kubeadm、kubelet和kubectl的版本差异必须在一个小版本范围内官方建议完全一致。比如你用了kubeadm 1.28.x去初始化一个1.27版本的集群大概率会碰到“unknown version”或者kubelet与apiserver之间的API版本不兼容。容器运行时方面1.28版本依然运行在containerd上但containerd版本不能太老1.6以上是底线1.7.x在稳定性上更合适。一个实用的核对方法在安装前先用kubeadm config images list --kubernetes-versionv1.28.5看一下这个版本需要哪些镜像同时确认当前环境是否已经可以正常拉取这些镜像。如果你的环境访问镜像仓库有困难这一步会提前暴露问题而不是等到kubeadm init进行到一半才卡住。1.2 三台机器的资源规划我这次用的环境是某项目X的测试环境三台虚机操作系统是Ubuntu 22.04每台机器2核4G内存磁盘40G。这个配置跑一个学习或测试用的集群完全够用但如果是生产环境4核8G会更舒适。节点角色主机名IP地址配置控制平面k8s-master192.168.200.22C4G / 40G工作节点k8s-node1192.168.200.32C4G / 40G工作节点k8s-node2192.168.200.42C4G / 40G主机名规划也有讲究。如果单机测试可以无所谓但多节点环境下最好提前统一命名规则并且所有节点的/etc/hosts都加上相互解析否则后面节点加入时kubelet通过主机名解析不了apiserver会直接导致TLS握手失败。我在实际操作中是把三台机器的主机名都写入各自hosts文件的这件事虽小但能省去后面很多“莫名其妙”的问题。2. 预置操作swap、内核参数与容器运行时2.1 关闭swap是硬性要求Kubernetes的kubelet在设计上不支持启用swap的节点因为它的内存管理基于cgroup如果启用了swapPod的内存隔离会被破坏。这一步如果在初始化前不做kubeadm会直接报错而且报错信息非常明确[ERROR Swap]: running with swap on is not supported. Please disable swap禁用swap的命令很简单swapoff -a sed -i /swap/s/^/#/ /etc/fstab第一行是临时关闭重启后失效第二行是注释掉/etc/fstab里的swap条目保证重启后也不会自动挂载swap。实际踩坑得到的教训是很多人只执行了swapoff -a没改fstab重启后又恢复原样然后第二次安装时又卡在同一个地方。所以这两条命令最好都执行然后用free -h确认Swap一栏为0。2.2 内核模块与网络参数K8s集群需要让节点转发bridge网络流量这个依赖内核开启overlay和br_netfilter模块。如果不做CNI插件可能起不来或者Pod之间无法通信而且问题会非常隐蔽——因为初始化阶段并不报错直到你开始ping Pod的IP才暴露出来。cat EOF | tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF modprobe overlay modprobe br_netfilter接着设置sysctl参数cat EOF | 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 sysctl --system其中net.ipv4.ip_forward是开启IPv4转发这个不开启的话Pod与外部网络的通信会失效。2.3 containerd的cgroup驱动配置这是安装K8s时“翻车率”最高的一步。kubelet默认使用systemd作为cgroup driver而containerd默认配置是cgroupfs两者不一致时kubeadm init会卡在kubelet启动阶段后面通过journalctl -u kubelet能看到类似kubelet cgroup driver: cgroupfs is different from docker cgroup driver: systemd的报错。解决方法是修改containerd的配置文件。先安装containerd然后生成默认配置containerd config default | tee /etc/containerd/config.toml修改/etc/containerd/config.toml两处关键内容[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true同时在[plugins.io.containerd.grpc.v1.cri]下面把sandbox_image改成环境中能正常拉取的pause镜像地址。这一步很多人会忽略等初始化到etcd镜像拉取那一步时才会意识到问题。改完配置后重启containerdsystemctl restart containerd一个我踩过的坑是改完配置忘了重启服务直接执行kubeadm init结果containerd还在用旧配置报错后我一度以为是kubeadm的问题。所以配置类和重启类操作顺序上一定别跳步。3. kubeadm init与三个高频报错3.1 初始化命令及提前拉镜像验证当你确定环境准备无误后就可以初始化控制平面了。实际操作中我推荐先执行镜像拉取验证不要直接kubeadm initkubeadm config images pull --kubernetes-versionv1.28.5这条命令会提前把初始化所需的apiserver、controller-manager、scheduler、etcd、pause等镜像拉好。如果这个环境里的镜像仓库访问有问题这一步就会暴露出来而不是让kubeadm init在中间卡住。拉取成功后再执行kubeadm init \ --apiserver-advertise-address192.168.200.2 \ --pod-network-cidr10.244.0.0/16 \ --kubernetes-versionv1.28.5--pod-network-cidr的选择需要与后续网络插件匹配。比如Flannel通常使用10.244.0.0/16Calico则常用10.244.0.0/16或192.168.0.0/16。你在这里填了什么段后面装CNI时就必须用同一个段否则Pod网段和CNI默认网段对不上网络插件会一直报错。3.2 报错一swap未关闭这个我在实验环境里试过不关swap直接kubeadm init报错信息开门见山[ERROR Swap]: running with swap on is not supported. Please disable swap处理方法参考2.1。这里多提一句如果你是在云服务器上操作有些镜像模板默认带了swap分区只执行swapoff -a还是不够必须同步改掉fstab否则重启就是“返工现场”。3.3 报错二pause/etcd镜像拉取失败kubeadm init中间卡住最典型的表现是长时间停留在[etcd] Creating static pod for local etcd或者日志里出现failed to pull image。原因是初始化时kubelet会以静态Pod的方式启动etcd和apiserver而containerd需要先拉取pause镜像以及etcd镜像。如果这个环境中默认镜像地址的访问速度很慢甚至不可达初始化就无限期卡住。解决思路很简单手动修改/etc/containerd/config.toml中的sandbox_image把它换成环境中可用的镜像地址。同时还可以用kubeadm config images pull提前把所有初始化需要的镜像都存到containerd里。实际操作里我习惯用crictl images确认镜像是否已经存在crictl需要单独安装但排查这类问题非常顺手。3.4 报错三kubelet启动后处于异常状态如果kubeadm init最终输出了类似“kubelet is restarting with crash-loop”的信息最直接的处理方式是查看kubelet日志journalctl -u kubelet -f我这次遇到的是cgroup驱动不匹配。日志里明确写着kubelet cgroup driver: systemd is different from runtime cgroup driver: cgroupfs。定位到问题后回到/etc/containerd/config.toml把SystemdCgroup改成true重启containerd然后执行kubeadm reset清掉这次不完整的初始化残留再重新执行kubeadm init。这里特别提醒一件事不要直接再次kubeadm init初始化失败后残留的etcd数据目录和kubelet状态文件会干扰后续重试kubeadm reset是必须的步骤。4. 网络插件安装与节点加入4.1 控制平面成功后的第一件事当kubeadm init成功退出后会让你依次执行三组命令来配置kubectlmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config然后需要立即安装CNI网络插件否则控制平面节点会一直处于NotReady状态。这是因为Kubernetes集群的Pod网络是由CNI插件提供的没有网络插件kubelet的NodeStatus里网络条件永远是ReadyFalse即使你看到节点状态是Ready了新建Pod也会一直卡在Pending。这次用的是Flannel。安装命令kubectl apply -f kube-flannel.yml执行后观察Pod状态kubectl get pods -n kube-flannel -o wide如果CrashLoopBackOff用kubectl logs查看。Flannel在启动时要向etcd里写入子网配置也需要从镜像仓库拉取flannel镜像。我在实验环境里遇到过一个情况flannel Pod一直报Failed to create pod sandbox最后定位到是containerd的sandbox_image地址不可用导致Pod沙箱创建失败。4.2 工作节点如何加入集群控制平面初始化完成后命令行末尾会输出加入集群的命令类似kubeadm join 192.168.200.2:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxx如果当时没保存或者token过期了可以在控制平面节点上重新生成kubeadm token create --print-join-command这个命令会输出一条新的加入命令。我在现场踩过的一个坑是复制了命令但没检查token状态。token的默认有效期为24小时如果集群搭到一半隔了一天再继续这个命令就失效了。重新生成命令的成本很低不要傻傻地怀疑网络。加入后回到控制平面节点用kubectl get nodes查看节点状态。如果新节点一直NotReady优先检查新节点的kubelet服务是否正常以及CNI bridge是否创建成功。一般工作节点不需要单独安装CNI它会自动从控制平面同步。4.3 节点NotReady的排查链路节点NotReady是安装阶段最让人头疼的状态因为单看表面信息很难定位。我的排查顺序一般是在控制平面执行kubectl describe node 节点名看Conditions里的Ready项为什么是False通常会写明原因到节点本机执行systemctl status kubelet确认服务存活状态执行journalctl -u kubelet -n 50看最近日志执行journalctl -u containerd -n 50看容器运行时日志其中一条比较容易忽略的原因是节点时间不同步。如果某台节点的时间偏差过大kubelet与apiserver之间的TLS证书验证会失败表现就是加入集群后立即NotReady。所以多节点环境里配置NTP时间同步非常有必要别等到排查证书问题时才想起来。5. 安装阶段常见问题速查表这里汇总了我在多次搭建集群过程中遇到的高频问题。每一个都是稳定复现过的场景不是网上抄来的。问题现象根因解决办法kubeadm init报swap错误节点swap未关闭swapoff -a并注释fstab初始化卡在etcd等待镜像拉不下来修改sandbox_image用kubeadm config images pull提前拉kubelet一直crashcgroup驱动不一致设置SystemdCgrouptrue重启containerd节点显示NotReady未安装CNI或CNI异常安装flannel/calico检查kube-flannel日志加入集群命令失效token过期kubeadm token create --print-join-command重新生成kubelet日志报证书错误节点时间不同步部署NTP服务确保节点时间一致Pod一直Pending没有可调度的节点或内存不足检查节点资源查看kubectl describe node控制平面节点Ready但Pod卡ContainerCreatingpause镜像不可用修改sandbox_image并重启containerd重试初始化时各种异常上次初始化残留未清理先执行kubeadm reset再重新init在做kubeadm reset时有个细节值得注意reset会重置kubelet、iptables规则和本地的etcd数据但不会自动清理/etc/kubernetes下的证书目录如果证书本身已损坏或过期建议手动清理后再init。我实际操作中会执行rm -rf /etc/kubernetes /var/lib/etcd但要注意这是危险操作只适合在明确要重装的环境中使用。5.1 一张比较有用的工具清单排错过程中会用到一些官方工具它们本身也是安装使用的一部分kubectl控制集群状态crictl命令行容器运行时管理工具可以从containerd层面看镜像和容器kubeadm负责集群生命周期管理etcdctl直接在etcd中查看集群存储数据其中crictl的使用频率很高比如查看容器状态crictl ps -a crictl images它能帮你快速确认一个Pod起不来是因为镜像没拉下来还是容器运行时本身有问题。6. 实测下来最有用的几个习惯我在这里再分享几条自己折腾这么久之后一直保留的操作习惯它们不直接出现在官方文档里但能明显降低排查问题的难度。第一每次安装前先在三个节点上跑一遍系统检查。命令无非就是free -h、df -h、swapoff -a、modprobe之类的但跑一遍可以排除最基础的硬件和系统配置问题而不是等到kubeadm init之后才发现某个基础项没满足。第二kubeadm的提示信息本身非常详细。很多人在报错时只看最后几行其实kubeadm init在遇到错误时会输出几十行上下文尤其是[preflight]阶段几乎会完整列出哪一项没通过。学会看这段输出能帮你节省大量时间。第三改配置文件时永远先备份再改。containerd的配置改错会导致容器运行时服务起不来这种情况比改前还要麻烦。我踩过一次改完配置没备份、又忘了怎么改回去的情况最后用containerd config default重新生成了默认配置再一步步改回去白白浪费了半小时。第四如果你准备长期使用这个集群安装完成后立即做一个节点快照。不管是虚拟机还是云主机快照都是一个成本极低的保险。后续测试网络策略或者升级组件时出了问题直接回滚快照比逐个排查快得多。我这次的项目X环境就是在装完基础集群后立刻打了快照后续几次试验出问题都靠它恢复。K8s安装的报错本质上就那几类环境配置、镜像拉取、驱动匹配、网络插件。把这些点提前处理好装一套集群的时间可以缩短到一小时以内。希望这篇笔记能帮你从那些“看起来毫无头绪”的报错中快速跳出来。