资讯动态

Kubernetes集群安装:kubeadm、containerd与CNI配置

发布时间:2026/10/21 16:09:31 来源:尧图企业网站定制
做运维这行绕不开 Kubernetes学 Kubernetes绕不开从零装集群。网上关于 K8s Cluster 详细安装步骤的文章非常多可真正照着装的时候很多人会栽在同一个地方版本没对齐、镜像拉不下来、CNI 网段冲突、节点加入后一直 NotReady。这篇文章我就按实际动手的顺序从版本规划一直写到排障把每一步为什么要这么做的原因也一并说清楚。内容会比较多但跟着走完你应该能获得一套可用的 Kubernetes 集群。适合想用 kubeadm 搭建测试环境或小型生产集群的读者。1. 动手前先做的三件事版本规划、节点规划与运行时选型1.1 版本规划小版本一致比追新更重要Kubernetes 的版本号是 x.y.z比如 1.28.3。x 是主版本y 是次版本z 是补丁版。kubeadm 对组件版本有兼容性要求master 和 worker 上的 kubelet 大版本允许差一个小版本但最好保持一致。我见过的翻车场面多半是 master 用 1.28某个 worker 用 1.25节点加入时 apiserver 直接拒绝证书或版本相关请求。所以动手前先定一个版本比如 1.28.x所有节点都装 1.28 对应的版本。怎么挑选具体版本不建议盲目追最新。选择一个当前仍在维护期内的稳定版本即可比如 1.28 或 1.29 这样的小版本。选好后把 kubeadm、kubelet、kubectl 三个组件锁在同一个版本上比如用 apt 安装时指定版本号而不是直接install kubeadm kubelet kubectl。不然系统源一更新你会无脑升到最新版本测试环境问题不大生产环境可能引入不必要的变化。1.2 节点规划与硬件最低要求如果你只是搭测试环境用三台虚拟机就够了一台控制面节点master两台工作节点worker。如果讲究高可用控制面至少三个节点起步但这里先按单控制面讲。控制面节点建议不低于 2C4Gworker 节点建议 2C4G 起。磁盘方面控制面节点的/var/lib/etcd尽量使用 SSDetcd 对磁盘 IO 延迟比较敏感。网络方面需要给控制面节点一个固定 IP后面 kubeadm join 会用这个 IP 或域名作为 API Server 地址。还要提前规划两段不会与其他网段冲突的虚拟网段Pod 网段和 Service 网段。kubeadm 默认的 Service 网段是 10.96.0.0/12Pod 网段初始化时不指定由 CNI 插件决定比如 Calico 默认 192.168.0.0/16。这两段网段必须避开你的物理内网网段否则后面路由会非常混乱。节点角色CPU 最低内存最低磁盘要求网络要求控制面 master2C4G系统盘 etcd 数据盘建议 SSD固定 IP6443 端口可达工作节点 worker2C4G系统盘容器镜像存储空间与 master 网络互通内网互通测试环境2C2G可凑合但不建议生产单机或虚拟机均可1.3 容器运行时选型为什么我推荐 containerdKubernetes 自己不直接启动容器它通过容器运行时去拉镜像、启停容器、管理挂载。早期版本流行 Docker cri-dockerd 的方式但 Docker 并不原生实现 CRIContainer Runtime Interface需要多一层适配。现在 kubeadm 默认推荐 containerd它把 CRI 插件直接内置了组件更少部署更轻踩坑的概率反而更低。containerd 也不是唯一选择CRI-O 也可以但 containerd 是 kubeadm 默认集成、绝大多数 Kubernetes 发行版默认使用的运行时相关文档和排障案例最多。对于自建集群我建议优先 containerd。后面所有步骤也按 containerd 来写。2. 基础环境配置内核参数、主机名和 DNS 是翻车重灾区2.1 关闭 Swap不是玄学是 kubelet 的硬性要求Kubernetes 的 kubelet 默认拒绝在开启 Swap 的节点上工作。K8s 希望节点内存资源按容器的 requests/limits 管理如果依赖 Swap容器会使用远超 limits 的内存影响调度和 QoS 判断。所以开节点后第一件事就是把 swap 关掉。临时关闭命令是swapoff -a但这只是临时的重启后/etc/fstab里的 swap 配置会重新激活它。你需要注释掉/etc/fstab中 swap 那一行。部分发行版上Swapon 由 systemd 管理最好顺手执行systemctl mask swap.target如果存在避免开机时被激活。注意这些操作要在所有节点上做不只是 master。2.2 加载内核模块和设置 sysctl 参数为了让 iptables 能看到桥接流量、让容器能够转发流量需要调整几个内核参数。大多数容器方案都依赖 overlay 文件系统所以先加载两个模块cat EOF | tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF modprobe overlay modprobe br_netfilter然后写入 sysctl 配置cat EOF | 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 sysctl --systemnet.bridge.bridge-nf-call-iptables让 bridge 设备上的流量经过 iptables 规则处理K8s 的 Service 转发依赖它net.ipv4.ip_forward打开内核 IP 转发Pod 跨节点通信和 Service 代理都依赖它。这几行配置在多数 Linux 发行版上比如 CentOS、Ubuntu都可以直接用但轻量级系统可能默认没有启用务必配置后确认已生效。2.3 主机名、hosts 解析与时间同步Kubeadm 初始化时会用主机名生成证书证书里的节点名会和 kubelet 注册名对应所以主机名必须全局唯一不能用 localhost.localdomain 之类的默认值。建议统一小写hostnamectl set-hostname k8s-master然后修改每台节点的/etc/hosts把所有节点 IP 和主机名都写进去192.168.1.10 k8s-master 192.168.1.11 k8s-worker-1 192.168.1.12 k8s-worker-2时间同步看起来不起眼但集群证书签发和 kubelet 心跳都依赖时间。如果节点时钟偏差过大初始化时生成证书、验证身份可能直接报错。简单起见用 chrony 或 systemd-timesyncd 即可apt install chrony -y systemctl enable --now chrony检查时间同步状态可以用chronyc tracking或timedatectl。生产环境最好统一时间源不走这一步后面证书相关错误会很难查。3. 安装 containerd这一步没配好后面全是泪3.1 安装 containerd 与基础验证containerd 的安装包一般来自容器运行时软件源也可以用发行版仓库自带的 containerd不过版本可能偏旧。建议使用较新的稳定包安装后启动服务apt install containerd -y systemctl enable --now containerd大多数系统安装后不会生成/etc/containerd/config.toml需要手动生成默认配置mkdir -p /etc/containerd containerd config default /etc/containerd/config.toml用ctr version可以确认安装成功。但 ctr 命令走的是 containerd 原生接口和 CRI 插件还不完全等价后续最好用 crictl 验证 CRI 接口。3.2 关键配置项Cgroup Driver、镜像加速和 Pause 镜像拿到默认 config.toml 后我们主要改三处。第一处是 Cgroup Driver。为了和 kubelet 保持一致通常将SystemdCgroup设为true。找到[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options]把SystemdCgroup false改成SystemdCgroup true也可以直接替换sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml第二处是 sandbox_image也就是 pause 镜像地址。默认值指向社区维护的仓库如果你的网络访问不到就会在 kubeadm init 拉取镜像阶段卡死。你可以把 sandbox_image 改成你所在网络环境可访问的仓库地址例如sandbox_image registry.example.com/pause:3.9第三处是镜像加速配置。可以在[plugins.io.containerd.grpc.v1.cri.registry.mirrors]下给 docker.io 配置一个可用的镜像源具体写法由你的镜像仓库决定。配置完成后重启 containerdsystemctl restart containerd3.3 修改后验证为什么用 crictl 而不是 docker如果你没有安装 Dockercrictl 才是 CRI 的标准客户端。安装 crictl 后先设置 endpointcrictl config runtime-endpoint unix:///run/containerd/containerd.sock crictl config image-endpoint unix:///run/containerd/containerd.sock然后拉一个测试镜像crictl pull busybox:1.28 crictl images如果这一步能成功说明 containerd 的 CRI 接口和镜像仓库都正常。很多人会跳过验证等到 kubeadm init 才发现 image pull 报错回头再改 containerd白白多等一轮。建议这里多花两分钟。4. kubeadm 初始化控制面一条命令背后的参数逻辑4.1 安装 kubeadm、kubelet、kubectl在所有节点上安装 Kubernetes 组件安装方式取决于发行版。一般流程是添加 Kubernetes 软件源然后指定版本安装apt-cache madison kubeadm | head -10 apt install -y kubeadm1.28.x-0 kubelet1.28.x-0 kubectl1.28.x-0安装完成后为了让 kubectl 好用可以加自动补全echo source (kubectl completion bash) ~/.bashrc source ~/.bashrc注意kubelet 安装后不要立刻启动。kubelet 在加入集群之前会因为找不到集群配置而不断报错这很正常。等 kubeadm init 或 join 后再让 systemd 管理它。4.2 生成初始化配置文件别只记一条长命令网上最常见的做法是直接kubeadm init --apiserver-advertise-address... --pod-network-cidr...但我建议先生成一份配置再初始化便于后续维护和排查。执行kubeadm config print init-defaults --component-configs KubeletConfiguration kubeadm-init.yaml打开文件重点修改这几块localAPIEndpoint.advertiseAddress改为控制面节点的固定 IP。nodeName改为当前控制面节点的主机名。imageRepository如果你的环境需要镜像加速改成可访问的仓库前缀。kubernetesVersion改成你安装的版本如 1.28.x。networking.podSubnet设置成和后续 CNI 匹配的网段比如 192.168.0.0/16 或 10.244.0.0/16。如果希望用域名访问 API Server还要在apiServer下的certSANs里添加域名和备用 IPapiServer: certSANs: - k8s-api.example.com - 192.168.1.10为什么搞成文件因为 kubeadm init 执行后生成的各种证书和配置都基于这份输入。后续如果证书要续期或重建控制面还能照着原始配置来。直接敲长命令也能跑但配置不会备份等出问题再想当时填了什么只能抓瞎。4.3 执行初始化输出里藏着三块重要信息初始化命令很简单kubeadm init --config kubeadm-init.yaml执行时会先检查环境然后拉取所需镜像最后生成证书、配置、kubeconfig并启动控制面组件。如果卡在拉镜像步骤回头检查第 3 节的 containerd 配置。成功的输出末尾会包含几块信息kubeconfig 文件路径通常让你拷贝/etc/kubernetes/admin.conf。一个kubeadm join命令里面有--token和--discovery-token-ca-cert-hash。提示你是否需要部署网络插件。我强烈建议把这段输出复制保存到本地文件后面 Worker 加集群和排障都要用。输出的 Token 默认有效期 24 小时过期也不用重新初始化用kubeadm token create --print-join-command重新生成即可这点在第 6 节再讲。4.4 配置 kubectl 访问集群初始化完成后需要用管理员证书配置 kubectlmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config然后执行kubectl get nodes你会看到控制面节点处于 NotReady 状态这是正常的因为还没装网络插件这时先别着急排查。kubectl get pods -n kube-system里coredns 也会处于 Pending 状态原因一样。下一步就是装网络插件。5. 安装 CNI 网络插件Pod 网段和 Service 网段别重叠5.1 CNI 插件选型Flannel、Calico、Cilium 怎么选Kubernetes 集群内部的 Pod 需要互相通信Pod 和宿主机之间也有通信要管理这要靠 CNI 插件。Flannel最简单只提供 Overlay 网络不包含 NetworkPolicy 支持适合测试或简单网络环境。Calico提供 BGP 路由模式和 Overlay 模式支持 NetworkPolicy生产环境用得多配置适中。Cilium基于 eBPF功能强性能好但对内核版本有要求组件也更多新手容易被一堆概念劝退。插件NetworkPolicy性能复杂度推荐场景Flannel不支持一般低测试环境、内网互通简单、学习优先Calico支持较高中生产环境、需要网络策略Cilium支持高高内核较新、需要高性能网络如果你不想折腾测试环境我建议 Calico它能修正很多网络问题对后续排障也有帮助。生产环境也大有人用。下面以 Calico 展开Flannel 的安装方式类似但少一些策略功能。5.2 以 Calico 为例的安装步骤Calico 安装推荐用 operator 或 manifest 两种方式。这里用 manifest 方式更容易理解它创建的组件。下载安装文件后找到CALICO_IPV4POOL_CIDR变量把它改成和 kubeadm-init.yaml 中podSubnet一致# 在 calico.yaml 中找到 - name: CALICO_IPV4POOL_CIDR value: 192.168.0.0/16配置文件准备好之后在 master 上执行kubectl apply -f calico.yamlCalico 会创建一组 DaemonSet每台节点跑一个calico-nodepod通过 BGP 或 Overlay 把节点间的 Pod 网段路由起来。同时还会部署calico-kube-controllers等控制组件。等待状态kubectl get pods -n kube-system -l k8s-appcalico-node -w当每个节点上的calico-node达到 Ready再回去kubectl get nodes所有节点通常就会变成 Ready。如果一直没变看下面的细节。5.3 三个最容易忽略的细节第一podSubnet不要和集群所在局域网网段重叠。Calico 默认的 192.168.0.0/16 和很多家庭、办公网络冲突。如果你宿主机网段正好是 192.168.1.0/24Pod 网段就不能再用 192.168.0.0/16否则路由会乱。建议用 10.244.0.0/16 之类较独立的网段。第二多网卡节点要指定 Calico 使用的网卡。如果你的节点存在多个网卡Calico 默认自动检测可能选错 IP。需要在 manifest 里设置- name: IP_AUTODETECTION_METHOD value: interfaceeth.*第三防火墙要放行 BGP 端口。Calico 用 BGP 默认端口 179iptables、firewalld、安全组都需要放行。如果是全 Overlay 模式不一定需要放行 179但做了 BGP 就必须。在云环境里安全组规则也要同步放行。这三个坑不看节点状态经常卡在 NotReady。6. Worker 节点加入集群Token、证书 Hash 与重复操作6.1 节点预检与运行时对齐Worker 节点在加入前并不是只执行一条kubeadm join就可以的。第 2、3 节的所有基础配置包括关闭 Swap、加载内核模块、配置 containerd、安装 kubeadm/kubelet/kubectl都需要在每台 Worker 上重新做一遍。尤其是 containerd 配置必须与 master 完全一致否则加入后 Pod 很可能起不来。版本对齐也很关键。Worker 上的 kubelet 版本最好和 master 完全一致。如果 master 用 1.28.xWorker 就别装 1.29 或 1.27版本偏差会带来兼容问题。顺手把主机名设为唯一并更新 /etc/hosts让 Worker 能通过域名或 IP 访问 master 的 API Server。6.2 获取加入命令如果你还记得kubeadm init输出里的 join 命令直接复制到 Worker 执行即可。如果 Token 过期或命令丢了在 master 上重新生成kubeadm token create --print-join-command这会输出一行类似kubeadm join 192.168.1.10:6443 --token token --discovery-token-ca-cert-hash sha256:hash为什么要带 hash它用于验证 API Server 的证书是否可信避免节点加入到一个伪装的服务端。你可以手动用 openssl 计算但一般直接用--print-join-command最可靠。在 Worker 上执行加入命令前先确认 master 可以直接访问检查端口 6443 通不通nc -vz 192.168.1.10 6443不通的话先解决网络否则 join 会超时。6.3 加入后验证执行 join 后Worker 的 kubelet 会带着证书向 API Server 注册控制面会创建该节点的 Node 对象。在 master 上运行kubectl get nodes通常节点从 NotReady 到 Ready 需要几秒到几十秒。如果一直 NotReady优先看 kubelet 日志journalctl -u kubelet -f --no-pager常见的报错有 CNI 配置未生效、容器运行时连接不上、节点 IP 被识别成旧地址。加入后验证 Pod 跨节点通信kubectl run test --imagebusybox --restartNever -- sleep 300进入 Pod 去 ping 其他节点的 Pod IP确认 Overlay 网络能通。验证完就可以删除测试 Pod。7. 安装完后的健康检查与故障排查7.1 集群健康从 componentstatuses 到 healthz很多人装完集群后习惯用kubectl get componentstatuses看健康状态但这个命令在较新版本已经不能准确反映控制面状态因为它检查的是本地 static Pod 端口很多组件已经不暴露那些端口。更好的做法是直接访问 API Server 的 healthzkubectl get --raw/healthz返回ok说明控制面可用。再看各组件 Podkubectl get pods -n kube-system -o wide包括 etcd、kube-apiserver、kube-controller-manager、kube-scheduler、coredns、calico-node 等。如果某个 Pod 一直 CrashLoop用kubectl logs -n kube-system pod查看日志而不是先去改配置。7.2 翻车日志排查流程先看容器运行时再看 kubeletK8s 排障有个基本顺序先在节点上看容器运行时再用 kubelet 日志最后才去控制面找原因。用 crictl 列出所有容器crictl ps -a如果发现某些 Pod 处于 Exited执行crictl logs container-id看到 OOM、sandbox 镜像拉取失败、CNI 配置找不到等关键信息后再对症处理。kubelet 日志通常反映调度和注册问题journalctl -u kubelet -f如果 Node 注册不上日志里会出现连接 API Server 失败或无权限。这种时候先检查 kubelet 证书是否过期、Token 是否有效。排查时不要一股脑重启节点很多问题只要调整 containerd 配置或 CNI 配置就能解决重启反而让现象被掩盖。7.3 两个我建议提前做好的备份动作第一备份/etc/kubernetes/pki目录和/etc/kubernetes/admin.conf。这个目录里保存了集群的 CA 证书、服务端证书、etcd 证书等。一旦节点损坏或证书丢失没有备份会非常被动。第二把kubeadm-init.yaml和 join 命令保存到集群外部。初始化配置是重建集群、续期证书、升级版本的依据别只放在 /root 下。证书默认有效期是 1 年到期前可以用kubeadm certs renew all续期但前提是 pki 目录仍然完整。这个动作没人愿意做但一旦遇到你会发现提前保存的配置胜过一切临场发挥。最后我个人在安装集群时有个习惯每装完一个环节先用命令确认这一步干净了再继续比如 containerd 装完先 crictl pull 一下master 初始化完先 kubectl get nodesCNI 装完再等一下 pods。这个过程看似多花了几分钟实际上能省掉后续一大轮的“瞎猜”。K8s 安装不像编译一个大项目它的坑是线性的前面错了后面必然错所以一步步验证远比一口气跑完更高效。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑