ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kubernetes 1.33.7集群部署实战:kubeadm踩坑与网络插件配置指南

Kubernetes 1.33.7集群部署实战:kubeadm踩坑与网络插件配置指南 上周帮项目组交付一套新的容器云底座目标版本就锁在 Kubernetes 1.33.7。整个部署从裸机配置、容器运行时安装到控制平面初始化、工作节点接入前后大约花了半天时间。网上关于 Kubernetes 安装部署的资料一直不少但版本一换参数和坑也跟着变。尤其 1.33.x 这套很多人还拿着 1.26 甚至更早的老教程硬套结果在 kubeadm init 阶段被各种 preflight 报错磨掉耐心。这篇文章不绕弯子直接按我这次实际部署的流程来写把每个关键参数为什么这么设、每个坑怎么踩的都讲明白适合刚上手 K8s、以及被 kubeadm 错误日志劝退的运维和开发同学参考。文章用的环境是三台 Linux 服务器一控两员生产小规模或实验环境都够用。1. 部署方案与版本选型思路1.1 为什么锁定 1.33.7 这个版本号先说选型。Kubernetes 的版本迭代节奏是三个月一个大版本1.33 属于 2025 年上半年发布的功能版本。但真正适合拿来落地建集群的一般不会是 .0因为首发的 .0 往往会有一些内核适配、组件兼容性上的打磨问题。1.33.7 是 v1.33 系列的第 7 个补丁版本意味着它已经吸收了 6 轮安全修复和稳定性回改像 kubelet 在节点状态上报、kube-proxy 在 ipvs 模式下的规则收敛、调度器在特定配额场景下的性能回退这类问题通常都会在补丁版本里得到处理。所以如果不想追新也不愿意用太旧的版本选一个维护窗口内的稳定补丁版是性价比最高的选择。这里要特别说明一点Kubernetes 官方对 minor 版本的支持窗口是最近三个版本1.33.x 在很长一段时间内都在安全更新覆盖范围内软件供应链角度也说得过去。如果你所在的公司有合规要求一般还会要求在锁定的版本区间内把镜像全部同步到内部仓库补丁版本恰好适合做这种资产盘点。1.2 kubeadm、二进制、发行版工具怎么选不后悔安装 K8s 集群的主流方式有几种官方 kubeadm、纯二进制手动部署、RKE2、以及云厂商托管。我的建议很直接除非你有强烈的离线交付需求或想彻底掌控每一个组件否则用纯二进制方式部署的成本远高于收益。它需要你自己处理 etcd 证书签发、apiserver 的 service account 密钥、controller-manager 与 scheduler 的配置拆分这套操作对排障能力要求非常高新手很容易在证书和启动参数上绕不出来。kubeadm 的优势在于它是官方维护的一等公民工具。证书、kubeconfig、静态 Pod manifest、引导 token 全部由它自动化生成而且生成的产物路径高度统一便于审计和后续升级。RKE2 这类发行版更偏向“开箱即用”但它把很多细节封装掉了出了问题反而更难定位。我的经验是先用 kubeadm 把官方原生集群跑明白你才能真正理解 K8s 控制平面的各个零件长什么样之后再看其他发行版会容易得多。1.3 三台机器的拓扑与端口规划这次部署用一个最小但不过度简化的拓扑一台 control-plane 节点两台 worker 节点。如果生产环境要求高可用把控制面扩展成三台并前置一个负载均衡器即可kubeadm 对多控制面的支持已经相当成熟原理和单控制面差别不大。机器规模方面控制面节点建议至少 2 核 4Gworker 节点建议 2 核 4G 起步磁盘控制在 50G 以上。做实验可以更小但 etcd 对磁盘 IO 比较敏感机械盘会拖慢 apiserver 的响应。安装前还需要把端口清单理清楚。控制面节点要放行 6443apiserver、2379/2380etcd 通信、10250kubelet、10259scheduler、10257controller-manager所有节点都要放行 10250、10256kube-proxy如果走 Calico 的 VXLAN 还要放行 4789/udp走 BGP 则要放行 179/tcp。不要一上来就关掉防火墙图省事理解端口比关防火墙更有用。2. 环境准备把裸机调成一个合格的 K8s 节点2.1 系统选型与 cgroup v2 问题我看到很多老教程还在用 CentOS 7.9 演示。CentOS 7.9 本身已经 EOL更麻烦的是它默认使用 cgroup v1内核停留在 3.10这在较新的 Kubernetes 版本上会带来不少兼容性问题。Kubernetes 在 v1.31 之后进一步收紧了 cgroup v1 的支持而像 kubelet 的内存管理、CPU 管理器这些功能在 v1.33 上基本都是以 cgroup v2 为基准设计和验证的。所以这次系统我选了 Rocky Linux 9.4内核 5.14 以上cgroup v2 直接就是默认状态省去很多折腾。装系统前先确认一下 cgroup 版本一条命令足够stat -fc %T /sys/fs/cgroup输出cgroup2fs就说明是 v2。如果输出的是 tmpfs那说明跑在 cgroup v1 下要么换系统要么在内核启动参数里加systemd.unified_cgroup_hierarchy1再重启。另外内核模块也要保证能加载 overlay 和 br_netfilter这是容器网络和镜像分层的基础。2.2 主机名、swap 与内核参数最容易被忽略的环节正式操作前我习惯先把主机名和 hosts 写好。三台机器分别命名为 k8s-m01、k8s-w01、k8s-w02然后在 /etc/hosts 里加上彼此的解析。K8s 集群的组件之间通过主机名互相通信如果只靠 IP后面 kubeadm 生成的证书里 SAN 可能对不上你会看到莫名其妙的证书校验失败。swap 必须关掉。swapoff -a之后还要把 /etc/fstab 里对应的 swap 行注释掉否则重启之后 swap 又回来了。kubelet 的资源管理基于 cgroup 和 Linux OOM 语义开着 swap 会让 Pod 的内存回收和 QoS 判断变得不可预期这是 K8s 的硬性要求不是建议。接着写入内核参数cat /etc/sysctl.d/k8s.conf EOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sysctl --system第一条参数解决的是容器流量经过 bridge 时也要被 iptables/netfilter 处理的问题否则 NodePort 和 ClusterIP 的 DNAT 规则可能对同一节点的 Pod 流量不生效第三条 ip_forward 则是保证容器网络包能在节点之间转发。这些参数两分钟内能配好但漏掉任何一个后续排障都够喝一壶。时间同步也可以顺手配上chrony 或者 systemd-timesyncd 都行控制面证书对时间偏移很敏感。2.3 containerd 配置里的两个坑Kubernetes 从 1.24 之后就完全移除了 dockershim所以现在的主流做法是直接使用 containerd 作为容器运行时没必要再套一层 docker。安装 containerd 建议直接装 1.7.x 或更新的稳定版因为老版本对 CRI 的兼容性和新内核的适配都会差一些。装好 containerd 后第一件要做的事是生成默认配置containerd config default | tee /etc/containerd/config.toml然后必须改两个地方。第一个是SystemdCgroup这个值默认是 false需要改成 true[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true不同 containerd 版本里配置块的细节略有出入总的原则是让 runc 使用 systemd cgroup 驱动和 kubelet 保持一致。第二个是sandbox_image默认的 pause 镜像地址在某些受网络限制的节点上拉取会很慢甚至失败。如果公司内部有镜像仓库建议把sandbox_image改成仓库里的 pause 镜像并提前同步过去。这个值不配好kubelet 启动时会一直报 failed to pull image节点迟迟变不成 Ready。配置改完后systemctl restart containerd。可以拉一个 busybox 镜像并用crictl pull验证 CRI 通路是否正常这一步虽然简单但能提前暴露仓库连通性和证书问题。2.4 安装 kubeadm、kubelet、kubectl 并锁定版本三件套的安装不算难关键是版本要和集群一致。这里有三点容易被忽略kubeadm、kubelet、kubectl 三个二进制必须锁同一个版本软件源要使用官方提供的 Kubernetes 仓库而不是发行版自带的过期版本安装时最好显式指定版本号不要直接yum install kubelet kubeadm kubectl装到最新否则初始化的时候版本不匹配就尴尬了。以 RPM 系为例cat /etc/yum.repos.d/kubernetes.repo EOF [kubernetes] nameKubernetes baseurlhttps://pkgs.k8s.io/core:/stable:/v1.33/rpm/ gpgcheck1 gpgkeyhttps://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key enabled1 EOF yum install -y kubelet-1.33.7 kubeadm-1.33.7 kubectl-1.33.7如果提示找不到 1.33.7 这个精确版本先yum list kubeadm --showduplicates看一看可用版本列表不同发行版的包版本号后面会带 build 后缀写法类似1.33.7-150500.0。Debian 系的同学把 yum 换成 apt仓库路径写在 sources.list 里原理一样。装完后执行systemctl enable --now kubelet。注意这时候 kubelet 还没拿到配置和 static pod 清单它会反复重启日志里全是等待和报错这是正常现象不用慌等 kubeadm init 完成后它自然就稳定了。很多新手在这一步被吓住以为装坏了。3. 控制平面初始化与集群装配全流程3.1 用 kubeadm 配置文件替代一堆命令行参数kubeadm init 支持大量命令行参数但生产环境我更推荐写一个配置文件把参数固化下来这样团队复查和后续扩容都有据可依。先跑一遍kubeadm config print init-defaults它会按当前版本打印一份标准模板你只需要在模板基础上改。apiVersion: kubeadm.k8s.io/v1beta4 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.10.41 bindPort: 6443 nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock --- apiVersion: kubeadm.k8s.io/v1beta4 kind: ClusterConfiguration kubernetesVersion: v1.33.7 controlPlaneEndpoint: 192.168.10.41:6443 imageRepository: registry.k8s.io networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: systemd如果kubeadm config print init-defaults生成的模板里 apiVersion 和上面不同以你本机生成的为准把对应字段改掉即可不要硬抄。advertiseAddress必须填当前节点在集群网络里可路由的 IPcontrolPlaneEndpoint也一样。podSubnet的选择要和后面的 CNI 插件对应我用的是 10.244.0.0/16这是 Flannel 默认网段如果准备用 Calico建议统一规划成 172.16.0.0/16 或者 192.168.0.0/16避免和现有办公网段冲突。然后直接在控制面节点上执行kubeadm init --config kubeadm-config.yaml这一步会持续一两分钟。看到类似[init] Using Kubernetes version: v1.33.7的输出就意味着正式进入安装流程。3.2 初始化输出背后到底发生了什么很多教程只贴命令不讲输出导致用户一看到[wait-control-plane]卡住就手足无措。其实 kubeadm init 的输出就是把控制面组件的每一步展开给你看先是 preflight 检查确认内核参数、端口、容器运行时、swap 都没问题然后是证书生成和 kubeconfig 生成接着把 etcd、kube-apiserver、kube-controller-manager、kube-scheduler 的 static Pod manifest 写到 /etc/kubernetes/manifests再之后是等待控制面健康检查通过最后生成 join token 并输出 kubeconfig 位置。如果 init 卡在 preflight 检查前面基础环境一定有遗漏如果卡在[wait-control-plane]多半是 kubelet 起不来重点去看 kubelet 日志如果顺利走完最后它会打印一串清晰的操作提示包括三件套kubectl 配置、join 命令、以及后续加入节点的 token 哈希。这部分内容建议存到临时文件里别关掉终端就找不到了。有一个经验初始化前先把/var/lib/kubelet、/etc/kubernetes和/var/lib/etcd这些目录备份或清空否则在同一个节点上重复 init 时会因为这些残留目录报 directory not empty。重装环境最常见的坑就是这一条。3.3 配好 kubectl 再装网络插件控制面初始化完成后用普通用户执行 kubectl 需要配置权限。官方输出里给的是 root 命令实际使用中我建议按普通用户来做mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config kubectl get nodes第一次kubectl get nodes会看到控制面节点处于 NotReady 状态这是完全正常的因为此时还没有安装 CNI 网络插件。这种状态下的控制面核心组件其实都在运行etcd、apiserver、controller-manager、scheduler 都应该是 Running。可以用kubectl get pods -A确认一下 kube-system 命名空间里的状态只要 coredns 等组件不是一直 Pending就不必太担心。3.4 Calico 还是 Flannel网络插件安装要点装网络插件这一步是很多同学最困惑的。Flannel 的好处是简单、轻量默认用 10.244.0.0/16适合快速跑通环境Calico 的好处是完整支持 NetworkPolicy性能在多层叠加场景下也更可控。我的建议是如果只是学 K8s 或者内部实验Flannel 足够如果有网络策略需求、或者集群规模要往上走直接上 Calico省得以后迁移。以 Calico 为例通常做法是下载官方 manifest 后创建。由于 manifest 里默认的 pod CIDR 是 192.168.0.0/16如果你的 podSubnet 不是这个值需要修改 ConfigMap 里的CALICO_IPV4POOL_CIDR或者下载后直接改环境变量curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/calico.yaml kubectl apply -f calico.yaml创建后观察kubectl get pods -n kube-system -w等 calico-node 和 calico-kube-controllers 都变成 Runningcoredns 也会从 Pending 落到正常状态。节点从 NotReady 变成 Ready 通常需要一分钟左右。如果等了五分钟还是 NotReady优先看 calico-node 的日志多半是网卡自动选择错误、MTU 不对、或者是防火墙没有放行 VXLAN 端口。3.5 工作节点加入与第一次跨节点验证现在去两台 worker 节点把之前保存的 join 命令粘进去执行。如果超过 24 小时 token 过期了就在控制面节点上重新生成kubeadm token create --print-join-command把生成的命令拿到 worker 节点执行即可。执行完回到控制面kubectl get nodes -o wide三台节点都变成 Ready 后我习惯第一时间跑一个真实的跨节点验证创建一个三副本的 nginx deployment然后用 NodePort 方式暴露从集群外访问任意一个节点 IP 对应的端口。如果三次请求都能成功说明 Service、kube-proxy、CNI 这条链路是通的这个集群才算是真正能交付的底座。4. 常见问题与排障技巧实录4.1 preflight 检查和 init 阶段翻车合集先整理一下最经典的 preflight 报错。第一种[preflight] running pre-flight checks之后提示[ERROR Swap]: running with swap on is not supported。原因和解决办法都很直接swapoff -a并把 fstab 里那行注释掉重启后依然生效才算根治。第二种提示 CRI 版本与 kubelet 不兼容通常是 containerd 版本太老升级到 1.7.x 以上基本能解决。第三种端口被占用常见于上一套集群没删干净可以用ss -lntp | grep 6443确认占用进程。如果 init 卡在[wait-control-plane]很长一段时间不动不要再盯着终端发呆直接打开另一个终端查 kubeletjournalctl -u kubelet -f日志里如果持续报 CRI 连接失败先确认 containerd 是否在运行如果报/var/run/containerd/containerd.sock不存在检查 criSocket 路径是否填对如果报 cgroup 驱动不一致去改 containerd 的 SystemdCgroup。这个阶段九成问题都集中在容器运行时和 kubelet 的衔接上跟 apiserver 关系不大。4.2 节点 NotReady 和 CoreDNS 悬而不决前面提到初始化完成后节点 NotReady 是正常的但如果装完 CNI 插件好几分钟还不变就要按顺序排查了。先kubectl get pods -A看 calico 相关 pod 是否正常再kubectl describe pod calico-node-xxx -n kube-system看事件。最常见的情况是 calico-node 一直报 Error getting MTU 或者 auto-detected IPv4 address is not suitable这是多网卡环境下的自动选择问题。解决方式是给 calico 配置网卡自动检测范围- name: IP_AUTODETECTION_METHOD value: cidr192.168.10.0/24CoreDNS 一直 Pending 还有一种典型情况没有安装 CNI它拿不到 Pod 网段的地址。有些教程把 flannel 安装步骤省略了新手就会看到 coredns 永远 Pending。记住一个规律只要 Pod 处在 ContainerCreating 或 Pending 状态超过几分钟第一反应不是去调 Pod 配置而是回头看 CNI 和容器运行时的日志。4.3 镜像、证书、token 问题速查表我把这次部署中遇到以及周围同事高频踩过的坑整理成一张速查表故障现象可能原因处理方式节点一直 NotReadykubelet 报 failed to pull image sandboxsandbox_image 指向的 pause 镜像拉不动修改 containerd 的 sandbox_image 为内部仓库地址重启 containerdworker 节点 join 时报 unknown CAtoken 过期或 ca cert hash 不匹配重新用kubeadm token create --print-join-command生成最新命令集群运行一段后 kubectl 报 x509 证书过期控制面证书到期kubeadm certs renew all后重启相关组件进程同一节点重复 init 报 directory not empty上个集群残留目录清空 /etc/kubernetes、/var/lib/kubelet、/var/lib/etcd 后重试CoreDNS CrashLoopBackOff缺少 CNI 或 Pod CIDR 与插件不一致安装对应 CNI核对 podSubnet 是否匹配另外补充一条容易忽略的细节kubeadm 生成的证书默认有效期是一年如果你只是搭个测试环境一年后证书过期会导致整个集群不可用。虽然kubeadm certs renew all可以续期但更好的是在部署时就考虑证书的审计和备份把 /etc/kubernetes 目录里的 CA 证书和私钥单独离线存一份。4.4 一套能救命的排障顺序被各种报错反复折磨之后我总结出一个排障顺序先从下往上查容器运行时 - kubelet - 控制面组件 - 网络插件 - 应用。具体操作是先确认systemctl status containerd kubelet都没问题然后journalctl -u kubelet -f和crictl ps看容器运行时层面是否有错误接着kubectl get pods -A和kubectl get events -A看资源层最后才看应用自身的日志。这套顺序看起来笨但能避免很多无效排查。比如 kubelet 起不来的时候去调网络插件配置就没有意义反过来如果网络插件正常而 Service 不通再去折腾 kubelet 也会白白浪费时间。排障时不要被某一个报错带偏先确认依赖链路的每一项基础组件是否健康再去追上层的问题。最后说点个人体会。每次装集群我都会在全部节点 Ready 之后先跑一个跨节点的 Nginx 访问测试确认 Service 和 kube-proxy 是通的再决定是否交付。Kubernetes 安装部署翻车的案例里十有八九不是 kubeadm 本身有多复杂而是基础环境和网络细节没有对齐。建议把这套流程沉淀成一条命令能跑完的脚本或者 Ansible 编排下次从零到可用能压缩在半小时内。遇到版本号对不上也不要慌先用官方默认模板当参照再逐项对照实际环境改比硬背命令行参数靠谱得多。
返回列表