news 2026/10/23 8:16:41

kubeadm搭建Kubernetes集群:从环境准备到CNI网络插件选型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
kubeadm搭建Kubernetes集群:从环境准备到CNI网络插件选型

这几年经常有人问我:Kubernetes 集群到底怎么装才比较稳?我的回答始终是:老老实实走 kubeadm。市面上的安装方式很多,有二进制手工部署、有发行版自带的一键脚本、也有 Minikube 这类单机玩具,但 kubeadm 是 Kubernetes 官方维护的标准引导工具,它不替你包办一切,只帮你把控制平面拉起来、把证书和 token 生成好,剩下的网络插件、存储、监控全留给你自己决定。这种"半自动"的做法反而最值得推荐——既不会黑盒化到出了问题无从下手,也不会累到亲手一个个进程去部署。这篇文章就基于 kubeadm 完整走一遍集群安装流程,从环境准备、三件套安装、init 参数设计到网络插件选型和排障链路,适合刚接触 K8s 想搭一套可用集群的同学,也适合已经装过但老被各种报错卡住的人对照排查。

1. 为什么至今仍推荐 kubeadm:官方半自动方案的取舍逻辑

1.1 先看懂几条安装路径的区别

在动手之前,我建议你先花十分钟理解一下不同安装方式的定位差异,不然很容易装完就开始后悔。

二进制手动部署是最原始的方式,所有的组件、证书、kubeconfig、systemd 服务全部自己创建和配置。它的好处是让你把每个组件的作用、监听端口和配置关系彻底搞明白,坏处是步骤多、容易出错、升级困难,适合学习原理,不适合日常使用。

kubeadm 是官方工具,工作时它负责生成证书、生成 kubeconfig、把 apiserver、etcd、controller-manager、scheduler 以静态 Pod 的方式跑起来,然后等着你自己装 CNI 网络插件。对比二进制方案,它省去了大量机械重复的证书和配置工作,但又没把底层逻辑完全藏起来,所有生成的文件都在 /etc/kubernetes 下面可以查看。

Minikube 和 Kind 这类方案主要面向本地开发和 CI 场景,它们的价值是快速获得一个可用的单节点环境,但生产语义和真实集群有差距,网络、存储、多节点调度都做过简化。此外部分云厂商或发行版会提供一键脚本或托管集群方案,这类方式最省心,但如果你是想真正掌握 K8s 运维能力,我还是建议从 kubeadm 开始,它是最好的"教学与生产中间态"。

1.2 控制平面静态化的设计精髓

kubeadm 最核心的设计,是把控制平面组件全部声明为 kubelet 管理的静态 Pod。

具体来说,执行kubeadm init之后,kubeadm 会在/etc/kubernetes/manifests/目录下生成四个 manifest 文件,分别对应 kube-apiserver、kube-controller-manager、kube-scheduler 和 etcd。kubelet 会持续监听这个目录,只要发现里面有 manifest 文件,就用容器运行时把它们拉起来;如果某个组件进程意外退出,kubelet 会按 manifest 里的定义自动重新拉起。

这就带来了两个重要特性。一个是自愈能力:apiserver 挂了,kubelet 会自动重启它,而不是需要运维手动 systemctl restart。另一个是升级路径清晰:升级 Kubernetes 版本时,只需要替换 manifest 里的镜像版本,kubelet 检测到变更后就会滚动更新对应静态 Pod。理解了这一点,你排查控制平面问题时就会多一个思路——先看/etc/kubernetes/manifests里的文件是否正常。

1.3 从单集群到高可用,kubeadm 的成长空间

还有人担心 kubeadm 只能用于搭建实验环境。实际上 kubeadm 设计的升级路径很完整:单机实验集群可以用它,生产环境的多控制平面高可用集群同样可以用它。

高可用与单机安装的核心差异只有两点:一是控制平面节点要配置一个负载均衡地址作为 controlPlaneEndpoint,让多个 apiserver 共享一个入口;二是 etcd 可以选择堆叠方式部署,也就是每个控制平面节点上各跑一个 etcd 实例,组成三节点集群。kubeadm join 时如果控制平面节点加入,需要额外传入--control-plane参数,并把证书文件拷贝到位。换句话说,从单节点练手到生产高可用,中间的知识增量是平滑的,这也是我推荐 kubeadm 的另一个原因。

2. 动手前必须敲定的三类事情:版本、节点规划与系统参数

2.1 版本与操作系统选型:稳定比新更重要

Kubernetes 的版本迭代非常快,每个小版本会持续收到约三个月的安全更新。我的建议是不要追新,选择最新的稳定小版本,并在实验环境里把目标版本固定下来,不要装完一周就想着升级。

目前我常用的版本是 1.28.x,它在 kubeadm、kubelet、containerd 的配合上已经非常成熟,踩坑资料也最多。对于操作系统,Debian/Ubuntu 系和兼容 RHEL 的发行版都能正常跑。需要注意内核版本,太老的内核在 iptables、网络命名空间方面会出问题,建议内核不低于 5.4。如果你用的是较老的发行版,先确认内核版本再动手。

容器运行时方面,从 Kubernetes 1.24 开始已经彻底移除了对 Docker 作为运行时(dockershim)的支持,现在主流方案是 containerd。你不需要再安装 Docker,直接装 containerd 即可,这也让整个安装链路更干净。

2.2 节点规划:单机实验与三机集群的推荐配置

建议在规划阶段把节点角色、IP、内存、磁盘列清楚。下面是两种常见规划的参考。

场景节点角色数量配置建议说明
实验环境单节点同时承担控制平面与工作负载14C8G,40GB 可用磁盘需注意默认控制平面节点带有污点,单节点需要去除污点才能调度业务 Pod
最小生产演练控制平面节点34C8G,80GB SSD3 个控制平面节点形成 etcd 高可用
最小生产演练工作节点28C16G,100GB SSD按业务需要扩容

IP 规划也要提前定好。控制平面节点之间、控制平面与工作节点之间需要二层互通。如果你要用 VLAN 或云网络,提前确认端口放通策略,特别是 6443、2379、2380、10250、10251、10252、10255 以及 NodePort 段。更好用的做法是先写好端口清单,再对照安全组或防火墙策略逐项放通,避免初始化到一半才发现 apiserver 端口不通。

还需要留意 Pod 网段和 Service 网段不要和现有物理网络冲突。比如你公司内网用的是 10.0.0.0/8,那 Pod 网段就不要再用 10.244.0.0/16,可以换成 172.20.0.0/16。这个网段一旦确定,后面装网络插件时必须保持一致,再想改就只能重置集群。

2.3 内核模块、sysctl 与 swap:最容易被忽略的前提

kubeadm 对系统环境有一定要求,其中三项配置如果漏掉,初始化必定失败或者集群跑起来非常不稳定。

第一项是关闭 swap。kubelet 默认要求禁用 swap,因为它要和 cgroup 的内存统计保持一致,如果系统还在使用 swap,kubelet 的内存 QoS 策略会失去意义,Pod 的内存限制也无法可靠执行。你可以用swapoff -a临时关闭,同时把/etc/fstab里的 swap 行注释掉,避免重启后重新挂载。

第二项是加载必要的内核模块。容器网络需要 bridge 和 overlay 相关模块,执行下面命令:

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

第三项是写入 sysctl 参数。注意每次重启后需要重新加载模块,所以 modules-load.d 和 sysctl.d 都要配置好:

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,需要确保 br_netfilter 模块已经加载成功,否则 sysctl 会报错。另一个容易忽略的点是:部分云主机的 iptables 后端是 nftables,Kubernetes 的 kube-proxy 会根据节点上的 iptables 版本自动选择模式,一般不用额外处理,但如果你临时改了默认 iptables 版本,需要注意保持一致。

3. 三件套安装与 containerd 调优:第二道门槛是版本对齐

3.1 用软件源安装并固定 kubeadm、kubelet、kubectl 版本

kubeadm、kubelet、kubectl 这三个组件是配套的,版本必须严格对齐。kubeadm 版本不能比 kubelet 版本新太多,否则初始化时会报版本不匹配的错误。

以 Debian/Ubuntu 系为例,先添加 Kubernetes 官方软件源。不同小版本需要进入对应的源路径,下面的示例使用 v1.28:

sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/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.28/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update apt-cache madison kubeadm

apt-cache madison会列出所有可用的版本号,然后我们需要手动指定一个完全相同的版本号安装,比如:

sudo apt-get install -y kubelet=1.28.2-00 kubeadm=1.28.2-00 kubectl=1.28.2-00

安装完成后立刻做标记,防止之后其他依赖安装把版本带偏:

sudo apt-mark hold kubelet kubeadm kubectl

为什么这么强调版本对齐?因为 kubelet 是节点上的代理,kubectl 是客户端,kubeadm 是引导工具。三者如果跨了多个小版本,API 协议协商时可能因为特性门控不一致而出现诡异报错,比如 kubelet 无法和 apiserver 通信、字段被丢弃、初始化过程中出现 Unimplemented 等。与其花时间排查,不如一开始就锁死版本。

3.2 containerd 安装与 cgroup driver 一致性

容器运行时这边,我推荐直接安装 containerd。安装方式和系统包管理有关,安装完成后需要做两个改动。

第一步,生成默认配置:

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

第二步,修改/etc/containerd/config.toml。重点有两个地方:

[plugins."io.containerd.grpc.v1.cri"] sandbox_image = "pause镜像地址" systemd_cgroup = true

sandbox_image是每个 Pod 启动时用于创建网络命名空间的 pause 容器镜像。默认值指向 Kubernetes 官方镜像仓库,这个仓库在我的网络环境里不一定能直接拉取。你需要先确认自己环境能访问哪些镜像仓库,把这里的地址替换成可用的 pause 镜像地址。版本要和 Kubernetes 小版本匹配,比如 1.28 集群一般用 pause 3.9 系列镜像。

systemd_cgroup = true对应 cgroup 驱动采用 systemd。这里有一个关键点:kubelet 默认使用的 cgroup driver 是 systemd,而 containerd 的默认配置有可能是 cgroupfs。如果两边不一致,kubelet 在启动后会报类似 "failed to run kubelet" 的错误。所以容器运行时的 cgroup 驱动必须和 kubelet 保持一致,统一用 systemd 在目前主流发行版上是兼容性最好的选择。

改完配置后重启 containerd:

sudo systemctl restart containerd sudo systemctl enable containerd

3.3 装完三件套后如何快速自检

不要急着跑 kubeadm init,先把基础状态确认一遍。

systemctl status kubelet containerd

此时 kubelet 可能处于没配置好的状态,因为它还没有/etc/kubernetes/kubelet.conf等文件,这是正常的。接着检查 kubelet 日志,确认没有因为系统参数或运行时问题反复崩溃:

journalctl -u kubelet --since "5 minutes ago"

如果日志里出现权限、cgroup、swap 相关的错误,说明前面的系统准备没做完,先回头处理。另外用kubectl version --client验证 kubectl 版本是否正常,这时不需要集群也可以直接看客户端版本输出。

4. kubeadm init 配置详解:从初始化到 worker 节点加入

4.1 我更推荐用配置文件而不是一长串命令行参数

很多教程把kubeadm init写成一行带一堆参数,比如--apiserver-advertise-address=1.2.3.4 --pod-network-cidr=10.244.0.0/16。这种写法不是不行,但参数一多就容易漏,而且不方便复用、不方便记录。

我更推荐写一份 kubeadm 配置文件,单控制平面实验环境的参考如下:

apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.10 --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: "v1.28.2" networking: podSubnet: "10.244.0.0/16" serviceSubnet: "10.96.0.0/12"

这里有两个惯用点需要说明。podSubnet要和 CNI 插件保持一致,我这里的 10.244.0.0/16 是 Flannel 默认使用的网段;如果你后面选择 Calico 作为网络插件,可以把 podSubnet 换成 Calico 对应的默认网段。advertiseAddress要填写当前节点真实可达的 IP,千万不要填回环地址或云主机内网 IP 段里不可达的地址,否则 worker 节点连不上 apiserver。

如果规划的是多控制平面高可用集群,配置里需要额外增加controlPlaneEndpoint,也就是负载均衡的虚拟 IP 或域名。这个值会写进生成的证书 SAN 里,所以一定要提前规划好。

4.2 init 输出里的关键信息:kubeconfig、token、join 命令

执行初始化:

sudo kubeadm init --config kubeadm-config.yaml

这一步会做全套预检,包括系统参数、端口占用、镜像拉取、证书生成。如果一切正常,最后会输出一段类似这样的信息:

Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.1.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx

注意这里有两段信息不能丢。第一段是 admin.conf 的拷配置方法,很多新手直接用小写的 config 去测试 kubectl,结果权限对不上。第二段是 join 命令,worker 节点加入集群就靠它。强烈建议把 join 命令完整保存到一个文件里,别等 token 过期后再到处找。

对于单节点实验环境,控制平面节点默认是不调度业务 Pod 的,因为节点上有污点。如果你就是想在一台机器上做实验,执行下面命令允许 Pod 调度:

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

4.3 worker 节点加入与 token 过期后的处理

在 worker 节点上,同样需要先完成系统参数配置、三件套安装和 containerd 配置,然后再执行 master 输出的 join 命令。如果 join 命令已经丢失或者 token 过期,可以回到控制平面节点执行:

kubeadm token create --print-join-command

这是我最常用的命令,它会生成一条新的带有效期的 join 命令,默认 token 有效期 24 小时。如果需要更长时效,可以加--ttl=0表示永久有效,但生产环境不建议这样做。加入完成后等待片刻,在控制平面节点运行:

kubectl get nodes

如果 worker 节点状态是 NotReady,大概率是网络插件还没安装。这就进入了下一个关键章节——CNI 插件。

5. CNI 网络插件:为什么节点 NotReady 和它有关

5.1 kubeadm 为什么默认不装网络插件

很多第一次装集群的人都会遇到这个困惑:三个节点都成功 join 了,但 kubectl get nodes 全都是 NotReady。原因几乎都是同一个——集群里没有任何 CNI 网络插件。

kubeadm 刻意不预装网络插件,因为 Kubernetes 的容器网络模型允许有多种实现,比如 Flannel、Calico、Cilium、Weave Net 等。它们解决的都是同一件事:让集群里任意一个 Pod 都能通过自己的 IP 与其他 Pod 互通,并且实现 Service 的负载均衡。如果没有 CNI 插件,kubelet 无法给 Pod 配置网络命名空间,节点健康检查就会失败,节点自然显示 NotReady。

选择网络插件时,优先考虑三个因素:是否支持 NetworkPolicy、封装方式带来的性能损耗、部署和运维的复杂度。下面单独拆两个最常见的方案。

5.2 Flannel 实施细节

Flannel 的优点是简单、依赖少、适合快速上手。它默认使用 VXLAN 封装,Pod 之间通过隧道通信,因此对底层网络要求不高,跨主机也能跑通。

实施时,先下载 Flannel 的 manifest 文件,一般是一个kube-flannel.yml。这个文件默认使用的网络是 10.244.0.0/16,它必须和你 init 时配置的podSubnet一致。如果我用的是这个默认网段,直接 apply 即可:

kubectl apply -f kube-flannel.yml

如果不是这个网段,需要先修改 manifest 里的 Network 字段,或者 init 时就直接把 podSubnet 改掉,两者必须统一。Flannel 装完后,coredns 处于 Pending 状态是正常的,因为还没有可用节点;等 Flannel 在节点上的 Pod 启动成功,节点会很快变为 Ready,DNS 也会被调度起来。

Flannel 的局限也比较明显:它默认不提供 NetworkPolicy 能力,也没有 Ingress Controller 相关的支持。如果你的场景只是内部服务互通、不涉及跨命名空间访问控制,它完全够用。

5.3 Calico 实施细节与模式取舍

Calico 是另一个非常流行的方案,功能比 Flannel 完整得多,支持 BGP、NetworkPolicy、IPIP 封装等。在节点数量较多、生产环境有多租户隔离需求时,Calico 是更实际的选择。

安装 Calico 通常从项目发布页获取一个包含 operator 或完整 manifest 的文件。使用 manifest 方式的话,需要检查文件里默认的 CALICO_IPV4POOL_CIDR 是否与集群podSubnet一致,不一致就改掉:

env: - name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16"

Calico 支持 IPIP 和 BGP 两种模式,IPIP 模式将 Pod 流量封装后走宿主机网络,BGP 模式让节点之间直接通过三层交换路由信息。BGP 模式网络性能更好,但对底层网络有要求:节点和交换机需要支持并允许 BGP 协议交互。如果你在云环境下部署,默认 IPIP 模式通常更省心。

我还遇到过一个细节:Calico Pod 如果因为镜像拉取失败启动不了,节点会一直 NotReady。这时候先排查镜像是否能访问,优先在本地提前把 Calico 镜像 pull 过来,再 apply manifest,可以避免很多时间浪费。

5.4 网络插件切换的正确姿势

如果你已经用 Flannel 跑了一段时间,想换成 Calico,或者反过来,不要直接在集群里 apply 新插件的 manifest。CNI 插件的残留配置会导致 node 上存在多套 CNI 配置,kubelet 不知道该用哪一套。

正确操作是:先把旧的插件资源清理掉,然后在每个节点上删除/etc/cni/net.d/下的旧配置文件,重启 kubelet,最后再 apply 新的 CNI。如果切换后异常复杂,最干净的办法是kubeadm reset后重新 init。我的经验是,在一开始就定好网络插件并且不要频繁切换,比事后折腾省心得多。

6. 装完不算完:验证清单与初始化失败的排查链路

6.1 初始化后的黄金验证流程

集群初始化完成、CNI 安装成功之后,不要急着部署业务,先把下面这套验证流程跑一遍,确认核心组件真的健康。

第一,节点状态:

kubectl get nodes -o wide

所有节点都 Ready 后,查看组件状态。注意kubectl get cs在老版本里已经废弃,更可靠的检查方式是看静态 Pod:

kubectl get pods -n kube-system -o wide

重点看 coredns、etcd、kube-apiserver、kube-controller-manager、kube-scheduler 是否 Running。如果 coredns 一直 CrashLoopBackOff,先确认网络插件是否正常,多数情况是 CNI 没生效。

第二,DNS 和网络功能测试。运行一个临时 Pod 测试 DNS 解析:

kubectl run -it --rm test-curl --image=curl --restart=Never -- nslookup kubernetes.default.svc.cluster.local

第三,验证 Pod 跨节点通信。你可以部署两个测试 Pod,分别调度到不同节点,用 ping 或 wget 测试对端 Pod IP。这一步能确认 CNI 的实际数据链路是通的,而不只是节点状态显示 Ready。

6.2 高频报错的排查链路

我把实际使用中最常见的几类问题按排查链路列出来,遇到报错时不要慌,按顺序看。

第一类:kubeadm init 卡在 "Waiting for the kubelet to boot"。这种情况通常是 kubelet 拉起静态 Pod 失败了。先看 kubelet 日志:

journalctl -u kubelet -f

如果日志里有 "container runtime is down" 相关字样,说明 containerd 没起来或者配置有问题。检查 containerd 状态和服务日志:

systemctl status containerd journalctl -u containerd -f

还要确认 crictl 能连上 containerd:

crictl config --set runtime-endpoint=unix:///run/containerd/containerd.sock crictl ps -a

通常到这里就能发现问题,比如 cgroup driver 不一致、pause 镜像拉不动、socket 路径不对。

第二类:节点显示 NotReady。先看节点上的 Pod 情况:

kubectl describe node <node-name> kubectl get pods -n kube-system -o wide | grep <node-name>

大概率是 CNI 没有就绪,或者 kube-proxy 异常。查看对应 Pod 日志,多半会看到网络插件初始化失败。如果 kube-proxy 报错,也可能是节点上的 IP 规则冲突,清理后重启 kubelet 即可。

第三类:join 时提示 token 无效或证书校验失败。重新生成 join 命令:

kubeadm token create --print-join-command

如果多次 join 失败,建议先kubeadm reset清理这个节点,再重新 join。reset 不会影响其他节点,只是清空当前节点的 kubelet 配置和 CNI 残留,是一个相当安全的操作。

6.3 避免重复踩坑的几个习惯

最后分享几个我吃过的亏换来的习惯,能让后续安装顺利很多。

建议把每次安装的版本号和改动记在一个笔记文件里。很多环境问题都是因为不同机器上的内核版本、containerd 版本、kubeadm 版本不一致引起的,把版本固定下来能极大减少不确定性。

用脚本保存你完整的安装命令。我现在会在每台机器上先跑一段初始化脚本,把 sysctl、模块、软件源、三件套版本全部搞定,然后再手动执行 kubeadm init。这样重建环境的时候非常快,也避免人工操作遗漏。

不要忽略预检。kubeadm init 的预检其实已经覆盖了很多常见问题,但它不会替你检查 CNI 网段冲突、不会检查镜像仓库连通性。所以动手前先kubeadm config images list看一下需要哪些镜像,在你当前环境里手动拉一遍,确认都能拿到,再开始 init,这是节省时间的最有效手段。

装完集群只是第一步,但它是最重要的一步。把 kubeadm 这套流程吃透之后,后面不管是加节点、升级版本、还是迁移到高可用架构,都会顺手很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 8:10:55

高精度AI解析+Ragflow:复杂PDF知识库搭建实战方案

做知识库的项目我做过几轮&#xff0c;越来越确认一件事&#xff1a;多数RAG翻车不是大模型不够聪明&#xff0c;而是入口处喂进去的内容质量太差。原始PDF丢字、表格挤成一坨、扫描件压根扫不出字&#xff0c;这些内容进了RAG流水线&#xff0c;后面检索和生成再努力也是事倍功…

作者头像 李华
网站建设 2026/10/23 8:10:12

AI Agent幻觉治理:Harness工程实战与低幻觉框架设计

作为一个在AI Agent工程领域摸爬滚打多年的开发者&#xff0c;我几乎每天都要面对同一个让人头疼的问题&#xff1a;模型一本正经地胡说八道。你可以把完美的提示词、精心搭建的知识库、层层防护的工具调用协议都准备妥当&#xff0c;然后Agent依然会在某个不起眼的环节&#x…

作者头像 李华
网站建设 2026/10/23 8:08:53

AI写作助手助力文科论文:从文献筛选到答辩的全流程实操

如果此刻你正坐在电脑前&#xff0c;面前是十几篇PDF&#xff0c;手机里还有一堆没读完的论文&#xff0c;脑海里盘旋着两个问题&#xff1a;这些文献到底哪些该细读&#xff1f;这个理论到底在说什么&#xff1f;那么这篇内容应该能帮上忙。文科论文写作最难熬的部分&#xff…

作者头像 李华