博客主页:https://tomcat.blog.csdn.net
博主昵称:农民工老王
主要领域:Java、Linux、K8S
期待大家的关注💖点赞👍收藏⭐留言💬
目录
- [📌 前言](#📌 前言)
- [🛠 环境信息](#🛠 环境信息)
- [💣 踩坑一:Calico 启动失败与 YAML 修改的"蝴蝶效应"](#💣 踩坑一:Calico 启动失败与 YAML 修改的“蝴蝶效应”)
- [💣 踩坑二:Kubelet 报错 "Nameserver limits exceeded"](#💣 踩坑二:Kubelet 报错 "Nameserver limits exceeded")
- [💣 踩坑三:私有仓库信任问题 (ImagePullBackOff)](#💣 踩坑三:私有仓库信任问题 (ImagePullBackOff))
- [💣 踩坑四:网络卡顿与网段冲突的"隐形杀手"](#💣 踩坑四:网络卡顿与网段冲突的“隐形杀手”)
- [💣 踩坑五:NFS Provisioner 卡在 ContainerCreating](#💣 踩坑五:NFS Provisioner 卡在 ContainerCreating)
- [💡 常用技巧与总结](#💡 常用技巧与总结)
-
- [1. 节点角色显示 `<none>`](#1. 节点角色显示
<none>) - [2. 推荐工具](#2. 推荐工具)
- [3. 最终的部署脚本逻辑](#3. 最终的部署脚本逻辑)
- [1. 节点角色显示 `<none>`](#1. 节点角色显示
📌 前言
最近在 VMware 虚拟机环境(Ubuntu 24.04)上部署 Kubernetes v1.31 集群。由于是内网环境,且使用了私有的镜像仓库(Registry),在编写自动化部署脚本的过程中遇到了不少"坑"。
本文不贴长篇大论的脚本代码,而是重点记录在 Master 初始化、Calico 网络插件配置、NFS 存储挂载 过程中遇到的真实报错及其解决思路。希望能帮到同样在折腾 K8s 私有化部署的朋友。
🛠 环境信息
- OS: Ubuntu 24.04 LTS
- K8s Version: v1.31.14
- CNI: Calico v3.28.1 (使用本地 YAML + 私有镜像仓库)
- Storage: NFS Subdir External Provisioner (v4.0.2)
- 网络环境 : 物理网段
192.168.130.x,存在网关限制。
💣 踩坑一:Calico 启动失败与 YAML 修改的"蝴蝶效应"
现象
Master 初始化成功后,Calico Pod 一直处于 CrashLoopBackOff 状态,导致节点无法 Ready。
查看日志发现报错:
text
ERROR: Invalid IP autodetection method: k8s,bgp
原因分析
为了适配多网卡环境,我在自动化脚本中用 sed 命令向 Calico 的 YAML 中插入 IP_AUTODETECTION_METHOD 环境变量。
由于 sed 插入位置不当(插到了 CLUSTER_TYPE 的 value 前面),导致 YAML 结构错乱,环境变量的值发生了"错位"。
✅ 解决方案
- 临时修复 :无需重装,直接使用
kubectl在线修正环境变量:
bash
# 修正 IP 自动发现策略 (匹配 ens 或 eth 开头的网卡)
kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=interface=ens.*|eth.*
# 修正被顶掉的配置
kubectl set env daemonset/calico-node -n kube-system CLUSTER_TYPE=k8s,bgp
# 重启 Pod
kubectl delete pods -n kube-system -l k8s-app=calico-node
- 脚本优化 :在自动化脚本中,改为先
kubectl apply原版 YAML,再通过kubectl set env命令注入配置,避免直接修改文本文件导致的格式风险。
💣 踩坑二:Kubelet 报错 "Nameserver limits exceeded"
现象
Calico 已经 Running 了,但 Node 状态依然是 NotReady。
查看 Kubelet 日志 (journalctl -u kubelet -e),发现大量刷屏报错:
text
Nameserver limits exceeded err="Nameserver limits were exceeded, some nameservers dropped"
原因分析
Linux 的 /etc/resolv.conf 最多只支持配置 3 个 DNS 服务器。我的虚拟机网络自动配置了多个 DNS,加上 Systemd 自动生成的,超过了限制。这导致 Kubelet 处理 DNS 时出现异常,且干扰了其上报节点状态。
✅ 解决方案
在初始化脚本中强制重写 /etc/resolv.conf,只保留最核心的 DNS:
bash
rm -f /etc/resolv.conf
cat > /etc/resolv.conf <<EOF
nameserver 114.114.114.114
nameserver 223.5.5.5
EOF
修复后重启 kubelet,节点立即变为 Ready。
💣 踩坑三:私有仓库信任问题 (ImagePullBackOff)
现象
Worker 节点加入集群后,无法拉取 Calico 和 NFS 的镜像,Pod 卡在 ImagePullBackOff。
原因分析
使用的私有仓库 registry.geoscene-dev.cn 可能是 HTTP 协议或使用了自签名证书,而 Containerd 默认要求 HTTPS 且证书合法。
✅ 解决方案
在 所有节点 的 /etc/containerd/config.toml 中注入镜像仓库的信任配置:
toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.geoscene-dev.cn"]
endpoint = ["https://registry.geoscene-dev.cn", "http://registry.geoscene-dev.cn"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."registry.geoscene-dev.cn".tls]
insecure_skip_verify = true
重启 Containerd 后镜像拉取正常。
💣 踩坑四:网络卡顿与网段冲突的"隐形杀手"
现象
- 在 Worker 节点执行
apt-get update极慢,经常超时。 ping外网丢包严重。
原因分析
这是最隐蔽的一个坑。
- 网关缺失:虚拟机启动后没有自动获取到默认路由,导致无法通往外网。
- 网段冲突:
- 物理网段 :
192.168.130.x - 原 Pod 网段 :
192.168.0.0/16 - 冲突点 : Kubernetes 的 Pod 网段 (
192.168.0.0/16) 包含 了物理网段。这导致主机将物理网络的流量误判为集群内部流量,路由逻辑完全乱套。
✅ 解决方案
- 补全网关 :
ip route add default via 192.168.130.60(并写入 Netplan 持久化)。 - 修改 Pod CIDR :将 K8s Pod 网段修改为
10.244.0.0/16,彻底避开物理网段。
kubeadm init参数修改:--pod-network-cidr=10.244.0.0/16- Calico YAML 修改:将
CALICO_IPV4POOL_CIDR的值改为10.244.0.0/16。
💣 踩坑五:NFS Provisioner 卡在 ContainerCreating
现象
部署 NFS 存储类后,Provisioner Pod 长时间(6分钟+)卡在 ContainerCreating。
kubectl describe 显示镜像已拉取,无明显报错。
原因分析
在 Master 节点手动测试挂载:
bash
mount -t nfs 192.168.130.96:/nfs/k8s /tmp/test
报错:mount: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper program.
原因 :Ubuntu 默认未安装 NFS 客户端工具包。Kubelet 调用宿主机 mount 命令失败。
✅ 解决方案
在 所有节点(Master + Worker) 安装 nfs-common:
bash
apt-get update && apt-get install -y nfs-common
安装后无需重启,Pod 自动恢复 Running。
注:已将此步骤加入自动化部署脚本的 apt 列表中。
💡 常用技巧与总结
1. 节点角色显示 <none>
kubeadm 默认不给 Worker 打 Role 标签。为了美观和管理方便,可以在 Join 后手动设置:
bash
# 给所有节点打上 worker 标签
kubectl label nodes k8s171 k8s172 node-role.kubernetes.io/worker=worker
2. 推荐工具
在命令行运维 K8s 时,强烈推荐安装 k9s。它比 Dashboard 更快、更符合运维直觉,且不依赖集群内的 Pod 组件,非常适合排查这种底层部署问题。
3. 最终的部署脚本逻辑
经过上述排坑,最终的自动化脚本逻辑总结如下:
- 网络预检:自动检查并添加默认网关。
- 基础软件 :安装
conntrack,socat,nfs-common。 - 系统配置:
- 锁定
/etc/resolv.conf为两个 DNS。 - 关闭 Swap。
- K8s 安装 :使用
kubeadm init,指定 Pod CIDR 为10.244.0.0/16。 - CNI 配置 :使用本地 Calico YAML,替换私有镜像地址,通过
kubectl set env动态配置网卡发现策略。 - 信任配置 :修改
containerd配置信任私有 Registry。
这次部署让我深刻体会到:私有化部署不仅仅是跑通脚本,更是对网络路由、Linux 基础服务(DNS/NFS)以及组件配置细节的综合考验。
如需转载,请注明本文的出处:农民工老王的CSDN博客https://blog.csdn.net/monarch91 。
