☰
kubeadm 1.33.7集群部署实战:初始化、网络与节点加入
2026/10/2 9:13:43 网站建设 项目流程

最近搭了一套全新的测试环境,从裸机到 Kubernetes 1.33.7 集群的完整安装部署,全程走 kubeadm 路线。1.33.7 算目前比较新的补丁版本,网上很多教程还停留在 v1.26、v1.28 的旧节奏里,直接照抄容易在版本兼容性上报一堆错。这篇文章把整个过程拆开写清楚:先讲选型和规划,再给出可复制的初始化配置、网络插件安装、Worker 节点加入方法,最后梳理几个我实际踩过的坑。适合第一次用 kubeadm 搭集群的新手,也适合从旧版本迁移过来、想快速验证新版本行为的运维老手。

1. 部署前的思路与方案选型

1.1 为什么我仍然选择 kubeadm

接触过集群部署的人都知道,业界能选的工具确实不少。二进制部署要手动生成证书、手写 systemd unit、自己组 etcd 集群,一套流程非常容易出错;kubespray、kops 这类项目适合批量交付场景,但对使用者要求高,遇到问题不好定位;Rancher 则引入了产品层依赖,反而把简单问题复杂化。

kubeadm 是官方维护的项目,最大的优势是“可预期”:证书自动生成、etcd 以 static pod 方式托管、控制面组件全部编排到 manifest 里,升级路径经过官方校验。生产集群能跑,测试环境更是标配。很多人的顾虑是担心 kubeadm 不够“底层”,实际用下来,它的日志和配置都足够透明,出问题能看到是哪一个组件在报错,排障效率比黑盒脚本高得多。

1.2 环境规划与版本组合

我这次准备了三台 Ubuntu 22.04 LTS 虚拟机,网络互通,规格如下:

角色主机名配置IP
Mastermaster012C4G / 50G192.168.1.11
Workernode014C8G / 100G192.168.1.12
Workernode024C8G / 100G192.168.1.13

版本组合是整套部署的灵魂。装之前先列清楚:

组件版本说明
Kubernetesv1.33.7kubeadm / kubelet / kubectl 三者严格同版本
containerd2.0.xK8s 1.33 不再内置 Docker 支持,统一走 CRI
Calicov3.32.xCNI 插件,需要查对 1.33 的兼容矩阵
etcd3.5.x由 kubeadm 自动部署,不需要单独手动装

Kubernetes 1.33 版本里,CRI 只认 containerd 这类标准实现,Docker 本身已经被踢出主流程。如果还停留在“K8s 装 Docker”的老观念里,第一关就过不去。CNI 插件的版本也要注意,不能随手选个最新版,得先看官方 support matrix。

1.3 提前定好的三个网络决策

网络规划一定要在初始化之前确定,因为podSubnet和serviceSubnet一旦初始化完成,后期再改只能重新建集群,非常痛苦。我的选择:

  • Pod 网段:10.244.0.0/16,和 Calico 的默认配置对齐
  • Service 网段:10.96.0.0/12
  • kube-proxy 模式:IPVS,而不是默认的 iptables

选择 IPVS 的原因很简单:当集群里 Service 数量变多、规则条目膨胀时,iptables 的链式遍历性能会肉眼可见地下降,IPVS 基于哈希表转发,规则再多也能保持稳定。这个选择对后续的维护收益很大,值得在初始化前就写好。

2. 基础环境准备

2.1 三台机器的统一初始化

无论 Master 还是 Worker,前三步完全一致:改主机名、配 hosts、关 swap。

改主机名比较简单:

sudo hostnamectl set-hostname master01 # worker 节点改成 node01/node02

hosts 解析也顺手加上:

cat <<EOF | sudo tee -a /etc/hosts 192.168.1.11 master01 192.168.1.12 node01 192.168.1.13 node02 EOF

然后关 swap。虽然 K8s 新版本里已经提供了 NodeSwap 特性,但默认行为仍然是禁用,与其去折腾特性开关,不如直接关掉:

sudo swapoff -a sudo sed -i '/swap/s/^/#/' /etc/fstab

注意:swapoff -a只对当前会话生效,不改/etc/fstab的话重启后又会挂载回来,所以两行必须一起执行。

时间同步容易被忽略,但它直接影响证书校验和 etcd 选主。我在这三台机器上都装了 chrony:

sudo apt install -y chrony sudo systemctl enable --now chrony

测试环境的防火墙我直接关了,生产环境只需要放行必要端口,包括 6443、10250、2379/2380 等,不需要全开。

2.2 内核模块与网络栈参数

K8s 的 Pod 网络依赖 Linux 内核的网络桥接功能,两个模块必须加载:

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF

然后是 sysctl 参数:

cat <<EOF | sudo 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 sudo sysctl --system

这两个配置背后的原理值得说一下。net.bridge.bridge-nf-call-iptables=1的意思是:经过 Linux 网桥的流量也要经过 iptables 规则过滤。如果没有这一项,Pod 之间的流量在跨节点通信时会出现 DNS 解析超时、Service 访问不通等诡异问题。net.ipv4.ip_forward=1则是让数据包能在节点之间转发,相当于给集群流量打开了路由开关。

2.3 containerd 安装与两处关键配置

containerd 的安装直接用 apt 就好:

sudo apt install -y containerd

装完先不要急着启动,配置需要调整两个关键点。生成默认配置:

sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml

第一处,SystemdCgroup改成true:

sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

这个改动怎么强调都不为过。kubelet 默认的 cgroup 驱动是systemd,而 containerd 生成的默认配置是cgroupfs,两者不一致会导致 kubelet 启动时报failed to validate kubelet flags,节点永远进不了 Ready 状态。

第二处,是sandbox_image。先用下面的命令确认当前版本的 pause 镜像具体是哪个版本:

kubeadm config images list --kubernetes-version v1.33.7

里面会有一行形如registry.k8s.io/pause:3.x的镜像地址。如果你的网络访问registry.k8s.io偏慢或受限,就把config.toml里的sandbox_image改成可访问的镜像仓库地址,仓库路径保持到pause:3.x。改完记得:

sudo systemctl restart containerd

我用crictl info验证过一次配置是否生效,比直接开跑 kubeadm init 更稳妥。

2.4 安装 kubeadm、kubelet、kubectl 并锁版本

三个二进制必须同版本,这是整篇文章里最重要的经验之一。用官方pkgs.k8s.io源安装:

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt update

先看源里有哪几个精确版本:

sudo apt-cache madison kubeadm

然后手动指定 1.33.7 那个版本号安装,不要用apt install kubeadm默认拉最新:

sudo apt install -y kubelet=1.33.7-* kubeadm=1.33.7-* kubectl=1.33.7-* sudo systemctl enable kubelet

注意:kubelet 装完只需要enable,不需要start。集群还没初始化时,kubelet 启动会因为没有 kubeconfig 而反复报错,这是正常的,等 init 之后它自然会被拉起来。

3. 使用 kubeadm 初始化 Master 节点

3.1 初始化配置文件解析

我不太推荐直接敲一长串 kubeadm init 参数,写一份配置文件可以保留存档,后续维护和升级都比命令行清楚。新建kubeadm-config.yaml:

apiVersion: kubeadm.k8s.io/v1beta4 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.11 bindPort: 6443 --- apiVersion: kubeadm.k8s.io/v1beta4 kind: ClusterConfiguration kubernetesVersion: v1.33.7 imageRepository: registry.k8s.io # 网络受限环境改成可用镜像仓库 networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs

每个字段都说一下。advertiseAddress填的是本机在集群内网里的地址,千万别填公网 IP;podSubnet必须和 CNI 插件期望的网段一致,我这里选 10.244.0.0/16 就是 Calico 默认值;serviceSubnet保持默认 10.96.0.0/12 即可。kubeadm.k8s.io/v1beta4是当前 1.33 支持的 API 版本,老博客里的v1beta2、v1beta3在旧版本里能用,新版会直接拒绝。

3.2 预拉镜像与正式 init

配置写好后,先把镜像拉全,这一步能提前暴露网络问题,不用等到 init 中途才发现:

kubeadm config images pull --config kubeadm-config.yaml -v=3

拉到镜像后,执行初始化:

sudo kubeadm init --config kubeadm-config.yaml

如果只需要单控制面,这里不用加--upload-certs。只有打算后续扩容多个控制面时才需要,它会额外生成一份证书加密密钥。

初始化成功的标志是终端打印出这段:

Your Kubernetes control-plane has been initialized successfully!

同时会输出两段关键信息:为普通用户配置 kubectl 的命令,以及给 Worker 节点用的kubeadm join命令。这两段内容建议复制保存,后面一定会用到。

3.3 当前用户配置 kubectl

初始化过程会生成/etc/kubernetes/admin.conf,这是集群的管理员 kubeconfig 文件。普通用户要操作集群,需要把它放到用户目录:

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

这时候 Master 节点会出现,但状态大概率是NotReady,别慌,不是集群坏了,是 CNI 还没装。admin.conf这个文件就是集群的钥匙,丢了或者证书过期,都要通过kubeadm certs renew all重新生成。

3.4 单控制面与高可用之间的选择

我这次为了演示,先用了单控制面。生产环境里至少需要 3 个控制面节点,配合外部负载均衡器做流量入口。单控制面重启 Master 会导致整个集群不可用,测试环境无所谓,生产这样干就是事故。

真正要扩容控制面时,集群初始化阶段就需要在ClusterConfiguration里指定controlPlaneEndpoint,也就是负载均衡器的虚拟 IP,然后额外部署外部负载均衡器。这一步不建议新手一上来就做,先把单控制面的网络、证书、调度逻辑弄明白,再上 HA 会更顺。

4. 部署 CNI 网络插件

4.1 不装网络插件时你是看不到 Ready 的

很多人第一次装集群,卡在 Master 和 Worker 都是NotReady的状态,第一反应是 kubelet 出了问题。其实这一步大概率只是缺了 CNI 插件。K8s 本身不会负责 Pod 网络互通,它把网络能力交给了第三方插件。没有 CNI,节点上的 Pod 网络根本建不起来,自然也就无法上报 Ready。

你可以看到kube-system空间里的 CoreDNS 一直Pending,这也是同一个原因:Pod 没有网络,调度器把它放在那里却起不来。

4.2 选型对比与 Calico 安装

CNI 的选择会影响集群的网络策略和安全模型。常见的有三种:

插件性能NetworkPolicy典型场景
Calico中高完整支持通用部署,资料多,兼容性好
Cilium高完整支持偏云原生网络与可观测性场景
Flannel中低不支持只要求全连通的最小集群

我选了 Calico,因为它对 iptables 和 BGP 的方式支持成熟,部署资料多,遇到问题容易找到答案。K8s 1.33 下建议选 Calico v3.32.x,装之前先到官方兼容矩阵确认。

部署 Calico 我习惯用 Operator 方式:

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.0/manifests/tigera-operator.yaml

然后准备custom-resources.yaml,把里面的cidr改成我们规划好的 Pod 网段:

apiVersion: operator.tigera.io/v1 kind: Installation metadata: name: default spec: calicoNetwork: ipPools: - name: default-ipv4-ippool blockSize: 26 cidr: 10.244.0.0/16 encapsulation: VXLAN natOutgoing: true

执行:

kubectl apply -f custom-resources.yaml

4.3 验证网络

安装后观察 Calico 组件状态:

kubectl get pods -n calico-system

等calico-node都变成Running,再回头看节点:

kubectl get nodes

Master 应该已经是Ready状态了,CoreDNS 也会从Pending变成Running。为了确认 DNS 解析真的可用,我放了个测试 Pod:

kubectl run test-dns --image=busybox --rm -it --restart=Never -- nslookup kubernetes.default

能正确解析出10.96.0.1这个 Service 地址,说明集群网络全链路通了。

5. 扩容 Worker 节点

5.1 Worker 节点上的重复准备工作

Worker 和 Master 在基础环境上没有任何区别,把第 2 章的操作原样跑一遍:改主机名、关 swap、加载内核参数、装 containerd、装 kubeadm/kubelet/kubectl。唯一不需要做的是kubeadm init。

如果你希望 Worker 也提前把镜像准备好,可以执行kubeadm config images pull,但是 Worker 节点真正需要的镜像会在 join 时自动拉取,这里不是必须操作。

5.2 生成并执行 join

在 Master 上生成一条带 token 的 join 命令:

kubeadm token create --print-join-command --ttl 24h

输出会类似这样:

kubeadm join 192.168.1.11:6443 --token xxxxxx --discovery-token-ca-cert-hash sha256:xxxxx

把整条命令复制到 node01、node02 上执行。这个 token 默认 24 小时过期,过期后再生成一次就行。

join 成功后,在 Master 上看节点状态:

kubectl get nodes -o wide

新节点在部署并启动好 CNI 插件后,会从NotReady自动转成Ready。这里有个细节:Worker 节点不需要单独装 Calico,因为 CNI 插件会以 DaemonSet 方式自动调度到所有节点上。

5.3 用 nginx 做一次端到端验证

节点加进来了,不代表调度链路完全没问题。我通常会用 Deployment 验证一下跨节点调度和 Service 转发:

apiVersion: apps/v1 kind: Deployment metadata: name: nginx-test spec: replicas: 2 selector: matchLabels: app: nginx-test template: metadata: labels: app: nginx-test spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-test spec: type: NodePort selector: app: nginx-test ports: - port: 80 targetPort: 80 nodePort: 30080

应用后确认两个副本落在不同节点上:

kubectl get pods -o wide

再用任意一台节点的 IP 加 NodePort 访问:

curl http://192.168.1.12:30080

能返回 nginx 欢迎页,说明从 Pod 创建、跨节点调度、kube-proxy 转发到 NodePort 端口映射,整条链路都通了。

6. 常见问题与排查技巧实录

6.1 kubelet 起不来,journalctl 刷屏

初始化过程中最常见的问题就是 kubelet 起不来。遇到这种情况,先看日志:

sudo journalctl -u kubelet -f --no-pager

最常出现的几类错误我整理了一张速查表:

报错关键字原因处理
failed to load kubeconfigkubelet 还没被 init/join 初始化确认是否执行过 kubeadm init/join
unknown service runtime.v1alpha2kubelet 找错 CRI socket确认 containerd 已启动,socket 路径正确
cgroup driver is not set to systemdcontainerd 的 SystemdCgroup 没改成 true检查 config.toml 并重启 containerd
version of kubelet is not equal to kubeadmkubelet 和 kubeadm 版本不一致用kubeadm version/kubelet --version对比后重新装

版本不一致这个坑我踩过一次:apt 安装时没锁版本,kubelet 被拉到了更新补丁版,kubeadm 还是旧的,kubeadm init时直接报版本校验错误,只能卸载重装对齐版本。

6.2 kubeadm init 卡在拉镜像

kubeadm init卡在downloading images这一步,基本就是网络访问registry.k8s.io太慢或被限了。两个解法:

  • 提前执行kubeadm config images pull --config kubeadm-config.yaml,看它卡在哪一步
  • 把imageRepository换成可用的镜像仓库地址,同步修改 containerd 的sandbox_image

有一点要留意:拉镜像问题不会影响已有配置,但如果你改了 containerd 的sandbox_image,改完必须重启 containerd,否则新的 pause 镜像不会生效。

6.3 CoreDNS 一直 Pending

CoreDNS 一直 Pending,绝大多数情况是 CNI 没装或者装错了。按这个顺序排查:

kubectl get pods -n kube-system | grep coredns kubectl describe pod -n kube-system coredns-xxxxx

如果事件里全是FailedScheduling,去看节点上的 CNI 配置目录:

ls /etc/cni/net.d/

目录为空,说明网络插件没装成功,回到第 4 章重新部署。如果 CNI 装了但 CoreDNS 还是起不来,看日志:

kubectl logs -n kube-system coredns-xxxxx

常见报错是 IP 池不匹配,也就是 Calico 的cidr和初始化时的podSubnet不一致。这个只能重装 Calico 并保证配置一致。

6.4 节点反复 NotReady

节点状态在 Ready 和 NotReady 之间反复横跳,通常是下面几种情况。用kubectl describe node <name>看 Conditions 一栏,能直接看到是哪条告警。

Condition 类型常见原因处理
MemoryPressure节点内存不足清理无用 Pod 或扩容
DiskPressure镜像占满根分区用crictl rmi --prune-all清理 /var/lib/containerd
PIDPressure进程数超限检查异常进程
Ready反复切换kubelet 心跳上报失败排查网络,检查 chronyd 时间同步

时间偏移这个问题容易被人忽略。节点时钟和 apiserver 偏差太大时,kubelet 上报的证书验证会失败,节点直接被标记为 NotReady。装好 chrony 是最省事的预防手段。

6.5 kubeadm reset 的正确打开方式

初始化搞砸了不要急着重装系统,kubeadm reset可以把环境恢复到一个相对干净的状态:

sudo kubeadm reset --force sudo rm -rf /etc/cni/net.d ~/.kube sudo iptables -F sudo iptables -t nat -F

rm -rf /etc/cni/net.d是为了清掉 CNI 插件的残留配置,iptables清空是为了防止旧规则影响下一次初始化。如果只执行kubeadm reset不清 iptables,第二次 init 之后可能会出现 Service IP 不通的诡异问题,排查半天才发现是残留规则在作怪。

我个人在整套环境搭下来后最大的体会是:版本一致、网段一致、镜像源一致,这三个“一致”做到了,kubeadm 基本能一次过。版本一致是指 kubeadm/kubelet/kubectl 严格同码同版本;网段一致是指初始化配置和 CNI 配置里的 Pod 网段完全匹配;镜像源一致是指 containerd 拉取镜像的仓库地址在 Master 和 Worker 上保持统一。这三点里任何一点没对齐,后面就是各种看起来毫不相关的玄学故障。

另外建议把kubeadm-config.yaml这种初始化配置纳入版本管理,别放在 root 目录下吃灰。集群出了问题时,你手里有一份可追溯的初始配置,排障会轻松很多。希望这份部署记录能让你少熬几个夜。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询