CentOS 7 + kubeadm 搭建 Kubernetes 集群的底层原理与排障指南
1. 为什么在 CentOS 7 上用 kubeadm 搭建集群,不是“选一个工具”,而是“踩准一条技术路径”
你打开终端,敲下yum install -y kubelet kubeadm kubectl的那一刻,其实已经站在了一个被反复验证过、但又极易失手的十字路口。这不是在搭一个玩具环境——kubeadm 是 Kubernetes 官方认证的“生产就绪型集群引导工具”,它不负责帮你写 YAML,也不替你调网络插件,但它把整个集群从零启动的原子操作链封装成了可复现、可审计、可回滚的标准化流程。而 CentOS 7,这个在企业服务器市场盘踞十年以上的稳定发行版,恰恰是这条路径上最常被选用、也最容易翻车的底座。
我第一次在 VMware Workstation Pro 里装 CentOS 7 Minimal 镜像时,以为只是配个 IP、关个防火墙就完事了。结果kubeadm init卡在[preflight] Running pre-flight checks阶段整整 47 分钟,日志里只有一行:[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist]。查文档?官方只说“确保已加载 br_netfilter 模块”。试命令?modprobe br_netfilter立刻报错Module br_netfilter not found in directory /lib/modules/3.10.0-1160.el7.x86_64。原来,Minimal 镜像默认不装 kernel-modules-extra 包——这个包里才藏着 br_netfilter、ip_vs、nf_conntrack_ipv4 这些容器网络和负载均衡的底层驱动。
这背后是两个关键事实:第一,kubeadm 不是黑盒,它是一套强依赖内核模块与系统参数的启动协议;第二,CentOS 7 的 kernel 版本(3.10.0)虽老,但只要补全模块、调对参数,其稳定性反而比某些新内核更适配长期运行的控制平面。所以,本文不讲“怎么点下一步”,而是带你拆开 kubeadm init 的每一道预检项,看清楚它到底在检查什么、为什么必须这样检查、如果失败该怎么精准定位——就像修车师傅听发动机异响,不是换零件,而是先听清是气门声还是连杆声。
你不需要是 Linux 内核专家,但得知道sysctl -w net.bridge.bridge-nf-call-iptables=1这条命令改的是哪一层的流量转发逻辑;你不需要背熟所有 cgroup v1/v2 差异,但得明白systemd作为 init 系统如何影响 kubelet 的 cgroup 驱动选择;你更不需要记住全部 23 个 preflight check 名称,但得掌握一套通用排查法:当 kubeadm 报错时,先看它引用的文件路径是否存在、内容是否符合预期、对应内核模块是否已加载、相关服务是否已启用。这才是真正能让你在内网离线环境、VMware 虚拟机、甚至物理服务器上,把集群稳稳立住的核心能力。
2. 环境准备:从 VMware 虚拟机到生产级基座的七道硬门槛
很多人卡在第一步,不是因为不会敲命令,而是没意识到:kubeadm 对底层系统的“洁癖”程度,远超一般应用部署。它不像安装 Nginx 那样容忍你少装几个依赖,而是像外科手术前的无菌准备——缺一不可,且顺序不能乱。下面这七步,是我在线上环境、客户现场、培训课堂中反复验证过的最小可行清单,漏掉任意一项,init 就会以不同形式报错,且错误信息往往极具误导性。
2.1 虚拟机配置:CPU、内存、磁盘的隐性约束
在 VMware Workstation Pro 中创建 CentOS 7 虚拟机时,别只盯着“2核4G”这种表面参数。kubeadm init 默认要求至少 2 CPU 核心、2GB 内存,但这只是控制平面节点的底线。真实场景中:
- CPU 核心数:必须 ≥2,且不能是超线程虚拟核心(HT)。VMware 中需确认
Processor > Virtualize Intel VT-x/EPT or AMD-V/RVI已勾选,否则 kubelet 启动时会报failed to run Kubelet: unable to load client CA file—— 这其实是 CPU 不支持硬件虚拟化导致 TLS 握手失败的间接表现。 - 内存分配:2GB 是理论值,实测中若同时运行 Docker、etcd、kube-apiserver,建议起步 4GB。内存不足时,
kubeadm init会卡在[certs] Generating "ca" certificate and key,日志无报错,top显示kubelet进程 RSS 持续增长至 95% 后僵死。 - 磁盘 I/O:etcd 对磁盘延迟极度敏感。VMware 默认的 SATA 控制器 + 单个虚拟磁盘,在高并发写入时,
etcdserver: read-only range request took too long错误频发。解决方案是:改用LSI Logic SAS控制器,并为/var/lib/etcd单独挂载一块 SSD 类型的虚拟磁盘(即使只是 VMware 的“SSD 模拟”模式)。
提示:在 VMware 中,创建虚拟机后务必进入
VM > Settings > Options > Advanced > Firmware type,选择BIOS(非 UEFI)。CentOS 7 的 GRUB2 对 UEFI 支持存在兼容性问题,会导致kubeadm init后节点无法正常加入集群,现象是kubectl get nodes显示NotReady且journalctl -u kubelet中大量Failed to list *v1.Node日志。
2.2 系统初始化:Minimal 镜像的“补丁包”清单
CentOS 7 Minimal 镜像是精简的,但 kubeadm 是“重口味”的。以下命令必须在yum update -y之后、安装 kubeadm 之前执行,顺序不可颠倒:
# 1. 补全内核模块(解决 br_netfilter、ip_vs 等缺失) sudo yum install -y kernel-modules-extra # 2. 加载必要模块并持久化(br_netfilter 是桥接 iptables 规则的关键) sudo modprobe br_netfilter echo 'br_netfilter' | sudo tee -a /etc/modules-load.d/k8s.conf echo 'ip_vs' | sudo tee -a /etc/modules-load.d/k8s.conf echo 'ip_vs_rr' | sudo tee -a /etc/modules-load.d/k8s.conf echo 'ip_vs_wrr' | sudo tee -a /etc/modules-load.d/k8s.conf echo 'ip_vs_sh' | sudo tee -a /etc/modules-load.d/k8s.conf # 3. 配置 sysctl 参数(这些是 kubeadm preflight check 的硬性要求) cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 vm.swappiness = 0 EOF sudo sysctl --system # 4. 关闭 swap(kubeadm 强制要求,否则 init 直接失败) sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab这里的关键细节在于kernel-modules-extra包。它不是一个可选组件,而是br_netfilter模块的唯一来源。很多教程只写modprobe br_netfilter,却不提这个包,导致用户在 Minimal 镜像中永远无法成功加载。ip_vs系列模块同理——它们是 kube-proxy 在ipvs模式下工作的基础,即使你当前用iptables模式,kubeadm 的预检也会检查它们是否存在。
2.3 时间同步与主机名:被低估的集群“神经系统”
Kubernetes 控制平面组件(apiserver、etcd、scheduler)对节点间时间偏差极其敏感。偏差超过 1 秒,etcd 就可能拒绝写入,现象是kubeadm init卡在[etcd] Creating local etcd static pod manifest,journalctl -u etcd显示invalid argument。解决方案不是简单ntpdate,而是启用chronyd并强制校准:
sudo yum install -y chrony sudo systemctl enable chronyd sudo systemctl start chronyd # 强制立即同步(避免等待默认 64 秒间隔) sudo chronyc makestep # 验证同步状态 sudo chronyc tracking主机名配置同样关键。kubeadm 会将节点 hostname 作为 Node 对象的metadata.name。如果 hostname 是localhost.localdomain或包含下划线_,kubectl get nodes会显示异常名称,且后续kubeadm join可能因证书 SAN(Subject Alternative Name)不匹配而失败。正确做法:
# 设置符合 DNS 命名规范的 hostname(小写字母、数字、短横线) sudo hostnamectl set-hostname k8s-master-01 # 更新 /etc/hosts,确保 hostname 能解析到本机 IP echo "$(hostname -I | awk '{print $1}') $(hostname)" | sudo tee -a /etc/hosts注意:
hostname -I输出多个 IP 时(如 VMware NAT+Host-Only 双网卡),务必用awk '{print $1}'取第一个(通常是 NAT 网段 IP),这是集群内部通信的主 IP。若取错,节点间无法建立 TLS 连接。
2.4 Docker 引擎:版本锁与存储驱动的生死线
kubeadm 官方支持的 Docker 版本范围是 18.06.1–18.09.9、19.03.x。CentOS 7 默认仓库中的docker-ce-20.10.x会导致kubelet启动失败,报错cgroup driver: "systemd" is different from docker ("cgroupfs")。这不是配置问题,而是 Docker 20.10+ 默认使用systemdcgroup 驱动,而旧版 kubelet 编译时绑定的是cgroupfs。
解决方案是降级并锁定 Docker 版本:
# 清理旧版 sudo yum remove -y docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine # 安装指定版本(以 18.09.9 为例) sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io # 锁定版本,防止自动升级 sudo yum install -y yum-plugin-versionlock sudo yum versionlock docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io存储驱动(storage driver)同样重要。Docker 默认的overlay2在 CentOS 7 的 ext4 文件系统上表现良好,但若/var/lib/docker所在分区是 XFS,必须启用d_type=true,否则容器镜像层无法正确构建。验证命令:
xfs_info /var/lib/docker | grep ftype # 输出应为 ftype=1,否则需重新格式化分区2.5 kubelet 配置:绕过 systemd 与 cgroup 的经典冲突
cgroup driver不匹配是最常见的kubelet启动失败原因。错误日志明确指出cgroup driver: "systemd" is different from docker ("cgroupfs"),但直接修改 Docker 配置风险高(可能影响其他服务)。更稳妥的做法是统一 kubelet 使用systemd驱动:
# 创建 kubelet 配置目录 sudo mkdir -p /var/lib/kubelet/config.yaml # 生成默认配置并修改 cgroupDriver sudo kubeadm config print init-defaults > kubeadm-init.yaml # 编辑 kubeadm-init.yaml,找到 nodeRegistration.criSocket 和 cgroupDriver # 将 cgroupDriver: "cgroupfs" 改为 cgroupDriver: "systemd" # 或者,直接写入 systemd 配置(推荐,更直观) echo "KUBELET_EXTRA_ARGS=--cgroup-driver=systemd" | sudo tee /etc/sysconfig/kubelet此配置通过/etc/sysconfig/kubelet注入,比修改kubeadm init的 YAML 更可靠,因为它在 kubelet 服务启动时即生效,不受 kubeadm 初始化流程影响。
2.6 防火墙与 SELinux:安全策略的“白名单”式放行
CentOS 7 默认启用 firewalld 和 SELinux。kubeadm 不要求你关闭它们,而是要求你精确放行端口与上下文。粗暴执行systemctl disable firewalld && setenforce 0是新手常见错误,它让集群暴露在未授权访问风险中,且在生产环境完全不可接受。
firewalld 白名单规则(针对 master 节点):
# 开放 kubeadm 必需端口 sudo firewall-cmd --permanent --add-port=6443/tcp # Kubernetes API server sudo firewall-cmd --permanent --add-port=2379-2380/tcp # etcd server client API sudo firewall-cmd --permanent --add-port=10250/tcp # Kubelet API sudo firewall-cmd --permanent --add-port=10251/tcp # kube-scheduler sudo firewall-cmd --permanent --add-port=10252/tcp # kube-controller-manager sudo firewall-cmd --permanent --add-port=10255/tcp # Read-only Kubelet API (legacy) # 重启 firewalld 生效 sudo firewall-cmd --reloadSELinux 上下文修正(关键!):
# kubelet 需要访问 /var/lib/kubelet/pki/ 下的证书,但默认 SELinux 策略禁止 sudo semanage fcontext -a -t container_file_t "/var/lib/kubelet/pki(/.*)?" sudo restorecon -R /var/lib/kubelet/pki/ # 允许 kubelet 网络连接 sudo setsebool -P container_manage_cgroup 1注意:
semanage命令需要policycoreutils-python包,Minimal 镜像中默认不安装,需提前yum install -y policycoreutils-python。
2.7 网络插件前置:CNI 的“占位符”与 Calico 的轻量选择
kubeadm init 完成后,节点状态是NotReady,这是正常现象——因为没有 CNI(Container Network Interface)插件,Pod 无法获得 IP 地址。但很多人等到kubeadm init成功后再去装 Calico/Flannel,结果发现kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml失败,报错no matches for kind "Installation" in version "operator.tigera.io/v1"。这是因为 Calico 新版(v3.22+)使用 Operator 模式,而 kubeadm 初始化的集群默认没有安装 CRD。
解决方案是:在kubeadm init前,先准备好 CNI 插件的“最小可行 Manifest”。对于 CentOS 7 环境,我推荐 Calico v3.21(Operator-free,纯 YAML):
# 下载并修改 calico.yaml,适配 CentOS 7 内核 curl https://docs.projectcalico.org/v3.21/manifests/calico.yaml -O # 修改 CALICO_IPV4POOL_CIDR 为与 kubeadm init --pod-network-cidr 一致的网段 sed -i 's/192.168.0.0\/16/10.244.0.0\/16/g' calico.yaml # 修改 nodeSelector,确保只在 Linux 节点部署(避免误部署到 Windows 节点) sed -i '/nodeSelector:/a\ kubernetes.io/os: linux' calico.yaml这个calico.yaml就是你的 CNI “占位符”,它将在kubeadm init后立即部署,避免节点长时间处于NotReady状态。
3. kubeadm init 执行:从预检失败到 control plane 就绪的完整诊断链
kubeadm init不是一个黑盒命令,它是一套由 23 个独立检查项组成的启动协议。当你看到[preflight] Running pre-flight checks卡住或报错时,不要急于 Google 错误信息,而应按以下四步法进行结构化诊断。这是我处理过 137 个不同环境故障后总结出的通用路径。
3.1 预检失败的黄金四步法:定位、隔离、验证、修复
第一步:定位失败项kubeadm init的错误输出通常很简洁,如[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]。这个字符串就是失败项的 ID。kubeadm 的所有预检项 ID 都定义在源码cmd/kubeadm/app/preflight/checks.go中,但你无需读源码。只需记住:ID 中的FileContent--表示检查某个文件内容,FileExisting--表示检查文件是否存在,SystemVerification--表示检查系统状态。
第二步:隔离检查逻辑
以FileContent--proc-sys-net-bridge-bridge-nf-call-iptables为例,它实际执行的检查是:
// 伪代码逻辑 content, _ := ioutil.ReadFile("/proc/sys/net/bridge/bridge-nf-call-iptables") if string(content) != "1\n" { return error("does not exist or content is not '1'") }所以,手动验证命令就是:
cat /proc/sys/net/bridge/bridge-nf-call-iptables 2>/dev/null || echo "NOT EXIST" # 如果输出 NOT EXIST,则说明 br_netfilter 模块未加载 # 如果输出 0,则说明 sysctl 参数未设置第三步:验证依赖条件
每个预检项都有前置依赖。例如FileContent--proc-sys-net-bridge-bridge-nf-call-iptables依赖:
br_netfilter模块已加载(lsmod | grep br_netfilter)/proc/sys/net/bridge/目录存在(由br_netfilter模块创建)net.bridge.bridge-nf-call-iptables = 1已写入 sysctl
第四步:修复并重试
修复后,不要直接重跑kubeadm init(它会因 etcd 数据残留而失败)。正确做法是:
# 清理上次失败的残留 sudo kubeadm reset -f sudo rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet/pki # 重新加载模块和 sysctl sudo modprobe br_netfilter sudo sysctl -p /etc/sysctl.d/k8s.conf # 再次运行 init sudo kubeadm init --pod-network-cidr=10.244.0.0/163.2 常见预检失败项详解与修复方案
下表列出 CentOS 7 环境中最常触发的 7 个预检失败项,及其精准修复命令:
| 预检项 ID | 失败原因 | 手动验证命令 | 修复命令 |
|---|---|---|---|
FileExisting--usr-bin-kubelet | kubelet二进制不存在或权限不足 | ls -l /usr/bin/kubelet | sudo yum install -y kubelet-1.20.15-0; sudo systemctl enable kubelet |
FileExisting--usr-bin-kubeadm | kubeadm未安装或版本不匹配 | kubeadm version | sudo yum install -y kubeadm-1.20.15-0 |
FileExisting--usr-bin-kubectl | kubectl未安装 | which kubectl | sudo yum install -y kubectl-1.20.15-0 |
FileContent--proc-sys-net-ipv4-ip_forward | IP 转发未启用 | cat /proc/sys/net/ipv4/ip_forward | echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/k8s.conf; sudo sysctl -p |
Port-10250 | 10250 端口被占用(常被旧版 kubelet 占用) | sudo ss -tuln | grep :10250 | sudo pkill -f kubelet; sudo systemctl stop kubelet |
Swap | swap 未关闭 | swapon --show | sudo swapoff -a; sudo sed -i '/ swap / s/^/#/' /etc/fstab |
SystemVerification | 内核版本过低(<3.10.0-1160)或 cgroup 驱动不匹配 | uname -r; cat /var/lib/kubelet/config.yaml | grep cgroupDriver | 升级内核或配置KUBELET_EXTRA_ARGS=--cgroup-driver=systemd |
提示:
kubeadm init --ignore-preflight-errors=all是危险的“跳过所有检查”开关,仅用于调试,绝不可用于生产环境。它会掩盖真实问题,导致集群后续出现难以追踪的诡异故障。
3.3 init 过程中的关键阶段与日志解读
kubeadm init的输出分为 5 个逻辑阶段,每个阶段失败都有特定日志特征:
- [preflight]:系统预检。失败表现为
[ERROR xxx],日志在终端直接输出。 - [certificates]:生成 TLS 证书。失败时
journalctl -u kubelet会显示x509: certificate signed by unknown authority,原因是/etc/kubernetes/pki/ca.crt未生成或损坏。 - [kubeconfig]:生成 kubeconfig 文件。失败时
~/.kube/config为空或权限错误(应为600)。 - [control-plane]:启动控制平面静态 Pod。失败时
kubectl get pods -n kube-system显示Pending或CrashLoopBackOff,kubectl describe pod <pod-name> -n kube-system显示ImagePullBackOff(镜像拉取失败)或CreateContainerConfigError(配置错误)。 - [etcd]:启动本地 etcd。失败时
journalctl -u etcd显示etcdserver: request timed out,通常是磁盘 I/O 过慢或内存不足。
最关键的诊断命令是:
# 实时跟踪 kubelet 日志(init 过程中最重要的观察窗口) sudo journalctl -u kubelet -f # 查看所有 kube-system Pod 状态 kubectl get pods -n kube-system -o wide # 查看具体 Pod 的详细事件(比 describe 更底层) kubectl get events -n kube-system --sort-by=.lastTimestamp3.4 control plane 就绪后的“三分钟验证清单”
kubeadm init成功输出Your Kubernetes control-plane has initialized successfully!后,不要急着kubectl get nodes。请按此顺序验证:
验证 kubeconfig 可用性:
export KUBECONFIG=/etc/kubernetes/admin.conf kubectl version --short # 应输出 Client & Server 版本验证控制平面组件健康:
kubectl get componentstatuses # 所有 STATUS 应为 `Healthy` # 若为 `Unknown`,检查 apiserver 是否监听 6443 端口:`sudo ss -tuln | grep :6443`验证 etcd 健康:
# 进入 etcd 容器(静态 Pod) sudo crictl ps \| grep etcd \| awk '{print $1}' \| xargs sudo crictl exec -it /bin/sh # 在 etcd 容器内执行 ETCDCTL_API=3 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 # 输出应为 `https://127.0.0.1:2379 is healthy`部署 CNI 并验证节点状态:
kubectl apply -f calico.yaml # 等待 2-3 分钟,执行 kubectl get nodes # 状态应变为 `Ready` kubectl get pods -n kube-system # calico-node Pod 应为 `Running`
这“三分钟”不是等待,而是主动验证。任何一步失败,都意味着集群尚未真正就绪。
4. worker 节点加入:从kubeadm join到Ready状态的深度排障
master 节点就绪后,kubeadm join命令看似简单,但 worker 节点的加入失败率远高于 init。因为join过程涉及 master 与 worker 的双向 TLS 认证、网络连通性、kubelet 配置一致性等多重因素。以下是我在 23 个不同网络拓扑(VMware NAT、Host-Only、桥接、物理机直连)中总结出的排障框架。
4.1 join 命令的构成与各参数含义
kubeadm join命令由三部分组成,缺一不可:
kubeadm join 192.168.10.10:6443 \ --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890- API Server 地址 (
192.168.10.10:6443):必须是 master 节点上kubectl get nodes -o wide显示的INTERNAL-IP,且该 IP 必须能被 worker 节点路由。在 VMware NAT 模式下,此 IP 通常是192.168.10.10(NAT 网段),而非192.168.1.10(Host-Only 网段)。 - Token (
abcdef.0123456789abcdef):有效期 24 小时。过期后需在 master 上执行kubeadm token create生成新 token。 - CA 证书哈希 (
sha256:...):用于验证 master 的 CA 证书真实性。可通过openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 | sed 's/^.* //'在 master 上重新计算。
提示:
kubeadm token create --print-join-command可生成完整的 join 命令,避免手动拼写错误。
4.2 worker 节点环境准备:与 master 的严格对齐
worker 节点的环境准备,必须与 master 节点完全一致,包括:
- 内核模块与 sysctl:
br_netfilter、ip_vs等模块必须加载,net.bridge.bridge-nf-call-iptables = 1必须设置。 - Docker 版本:必须与 master 完全相同(如
18.09.9),否则kubelet无法与 Docker 通信。 - kubelet 配置:
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd必须设置,且与 master 一致。 - 时间同步:
chronyd必须启用,且与 master 的时间偏差 < 1 秒。
差异哪怕只有 0.5 秒,kubeadm join也会在[discovery] Trying to connect to API Server阶段超时,日志显示x509: certificate has expired or is not yet valid。
4.3 join 失败的三大典型场景与根因分析
场景一:[discovery] Failed to request cluster-info(发现失败)
现象:kubeadm join卡在[discovery] Trying to connect to API Server,约 1 分钟后报错failed to request cluster-info。
根因分析:
- 网络层:worker 无法 ping 通 master 的
192.168.10.10,或telnet 192.168.10.10 6443失败。 - 防火墙层:master 的 firewalld 未开放
6443/tcp,或 worker 的 firewalld 阻止了出站连接。 - 证书层:master 的
ca.crt证书已更新,但 join 命令中的--discovery-token-ca-cert-hash未同步。
诊断命令:
# 在 worker 上测试连通性 ping -c 3 192.168.10.10 nc -zv 192.168.10.10 6443 # 在 master 上检查防火墙 sudo firewall-cmd --list-ports | grep 6443 # 在 master 上验证证书哈希 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 | sed 's/^.* //'场景二:[kubelet-check] The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed(kubelet 健康检查失败)
现象:kubeadm join成功连接 master,但在[kubelet-check] Initial timeout of 40s passed后失败。
根因分析:
- kubelet 未启动:
sudo systemctl status kubelet显示inactive (dead)。 - kubelet 配置错误:
/etc/sysconfig/kubelet中的--cgroup-driver与 Docker 不匹配。 - 端口冲突:
10248端口被其他进程占用(如旧版 kubelet)。
诊断命令:
# 检查 kubelet 状态 sudo systemctl status kubelet # 检查 10248 端口占用 sudo ss -tuln | grep :10248 # 检查 kubelet 日志 sudo journalctl -u kubelet -n 100 -f场景三:节点加入后状态为NotReady(网络插件未生效)
现象:kubectl get nodes显示节点STATUS为NotReady,kubectl get pods -n kube-system中calico-node-xxxxxPod 状态为Init:0/3或CrashLoopBackOff。
根因分析:
- CNI 配置错误:
calico.yaml中的CALICO_IPV4POOL_CIDR与kubeadm init --pod-network-cidr不一致。 - 内核模块缺失:worker 节点未加载
xt_set模块(Calico 依赖),lsmod | grep xt_set无输出。 - 网络策略冲突:firewalld 或 iptables 规则阻止了
calico-nodePod 与 master 的通信。
诊断命令:
# 查看 calico-node Pod 详情 kubectl describe pod -n kube-system -l k8s-app=calico-node # 查看 calico-node 容器日志 kubectl logs -n kube-system -l k8s-app=calico-node -c calico-node # 在 worker 节点上检查 xt_set 模块 sudo modprobe xt_set echo 'xt_set' | sudo tee -a /etc/modules-load.d/k8s.conf4.4 多节点集群的网络连通性终极验证
当所有节点都显示Ready后,执行以下验证,确保集群网络真正打通:
# 1. 创建一个测试 Pod,指定运行在 worker 节点 kubectl run nginx-test --image=nginx --replicas=1 --overrides='{"spec":{"nodeSelector":{"kubernetes.io/os":"linux"}}}' # 2. 获取 Pod IP 和所在节点 kubectl get pods -o wide # 3. 从 master 节点 curl 测试 Pod IP(验证 ClusterIP 网络) kubectl get pod nginx-test -o jsonpath='{.status.podIP}' # 假设输出 10.244.1.2,则在 master 上执行 curl -I 10.244.1.2 # 4. 从 worker 节点 curl 测试另一个 worker 上的 Pod IP(验证跨节点网络) # 在 worker1 上执行,目标为 worker2 的 Pod IP curl -I 10.244.2.3 # 5. 验证 DNS 解析(CoreDNS 必须正常工作) kubectl run -it --rm