K8s 1.31 私有化部署实战:从 Calico 崩溃到 NFS 挂载失败的排坑全记录

博客主页: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. 最终的部署脚本逻辑)

📌 前言

最近在 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 结构错乱,环境变量的值发生了"错位"。

✅ 解决方案

  1. 临时修复 :无需重装,直接使用 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
  1. 脚本优化 :在自动化脚本中,改为先 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 后镜像拉取正常。


💣 踩坑四:网络卡顿与网段冲突的"隐形杀手"

现象

  1. 在 Worker 节点执行 apt-get update 极慢,经常超时。
  2. ping 外网丢包严重。

原因分析

这是最隐蔽的一个坑。

  1. 网关缺失:虚拟机启动后没有自动获取到默认路由,导致无法通往外网。
  2. 网段冲突
  • 物理网段 : 192.168.130.x
  • 原 Pod 网段 : 192.168.0.0/16
  • 冲突点 : Kubernetes 的 Pod 网段 (192.168.0.0/16) 包含 了物理网段。这导致主机将物理网络的流量误判为集群内部流量,路由逻辑完全乱套。

✅ 解决方案

  1. 补全网关ip route add default via 192.168.130.60(并写入 Netplan 持久化)。
  2. 修改 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. 最终的部署脚本逻辑

经过上述排坑,最终的自动化脚本逻辑总结如下:

  1. 网络预检:自动检查并添加默认网关。
  2. 基础软件 :安装 conntrack, socat, nfs-common
  3. 系统配置
  • 锁定 /etc/resolv.conf 为两个 DNS。
  • 关闭 Swap。
  1. K8s 安装 :使用 kubeadm init,指定 Pod CIDR 为 10.244.0.0/16
  2. CNI 配置 :使用本地 Calico YAML,替换私有镜像地址,通过 kubectl set env 动态配置网卡发现策略。
  3. 信任配置 :修改 containerd 配置信任私有 Registry。

这次部署让我深刻体会到:私有化部署不仅仅是跑通脚本,更是对网络路由、Linux 基础服务(DNS/NFS)以及组件配置细节的综合考验。


如需转载,请注明本文的出处:农民工老王的CSDN博客https://blog.csdn.net/monarch91

相关推荐
灰子学技术2 小时前
istio从0到1:如何解决分布式配置同步问题
分布式·云原生·istio
广州中轴线2 小时前
OpenStack on Kubernetes 生产部署实战(十四)
kubernetes·智能路由器·openstack
小马爱打代码2 小时前
ZooKeeper:入门实战
分布式·zookeeper·云原生
logocode_li4 小时前
OCI/CRI 双标准下:从 dockerd 到 containerd 的 K8s 运行时迭代史
docker·云原生·容器·k8s
天才奇男子13 小时前
HAProxy高级功能全解析
linux·运维·服务器·微服务·云原生
人间打气筒(Ada)19 小时前
k8s:CNI网络插件flannel与calico
linux·云原生·容器·kubernetes·云计算·k8s
江畔何人初20 小时前
pod的内部结构
linux·运维·云原生·容器·kubernetes
苦逼IT运维1 天前
从 0 到 1 理解 Kubernetes:一次“破坏式”学习实践(一)
linux·学习·docker·容器·kubernetes
腾讯云开发者1 天前
言出法随 -- Chaterm如何通过ASR精准操作K8S
云原生·容器·kubernetes