1. 为什么现在还有人用 CentOS 8 搭 K8s先把话说在前头CentOS 8 官方维护早就停了生产环境我强烈建议你换 Rocky Linux 或者 Ubuntu LTS。但现实是很多公司内网、离线机房、教学实验环境里还躺着一大批 CentOS 8 的机器重装系统成本极高运维团队又要求必须上容器编排。这时候在 CentOS 8 上把 K8s 跑起来就成了一项必须完成的硬任务。我自己最近就在一个内网实验集群里完整走了一遍 CentOS 8 K8s 的部署流程踩的坑比预想的多得多——从 yum 源失效、内核模块缺失到容器运行时选型、镜像拉取超时每一步都有讲究。这篇文章就把整套流程拆开讲透包括为什么这么选、参数怎么算、报错怎么查让你照着做就能复现一个可用的单 Master 集群。适合谁看有一定 Linux 基础、想入门 K8s 部署的运维或后端同学需要在离线或老旧环境里搭集群的工程师以及被CentOS 8 装 K8s折磨过、想找一份靠谱参考的人。下面所有操作我都实测过命令可以直接抄。2. 部署前的整体设计与选型思路2.1 为什么是 kubeadm 而不是二进制或 MinikubeK8s 的部署方式大致三类Minikube 这类单机玩具、kubeadm 这类官方半自动工具、以及纯二进制手工部署。Minikube 只能单节点学不到集群网络和证书体系二进制部署最灵活但组件多、证书要自己签新手极易翻车。kubeadm 是官方维护的集群引导工具它帮你做了三件最烦的事证书自动生成与轮换、控制平面组件的静态 Pod 编排、以及 join 令牌管理。代价是它对环境有硬性要求内核参数、容器运行时、swap 关闭但这些要求恰恰是生产集群必须满足的。所以我选 kubeadm既能学到真实集群结构又不用被证书细节淹没。2.2 容器运行时为什么选 containerd 而不是 Docker这是 CentOS 8 上最容易纠结的点。K8s 从 1.24 版本起移除了 dockershim也就是说不再直接支持 Docker 作为运行时。虽然你可以装 cri-dockerd 适配层继续用 Docker但多一层适配就多一层故障点。containerd 本身就是 Docker 的底层运行时Docker 只是它上面的一层 CLI 封装。直接用 containerd 更轻、更稳而且 kubelet 通过 CRI 接口原生对接没有中间商。实测下来 containerd 启动 Pod 的速度比走 dockershim 快一截内存占用也低。所以本文全程用 containerd命令用crictl而不是docker。2.3 网络插件为什么选 CalicoCNI 插件主流是 Flannel 和 Calico。Flannel 简单overlay 网络够用但不支持网络策略NetworkPolicyCalico 支持 BGP 路由和完整的网络策略性能也更好是生产环境的事实标准。在 CentOS 8 上 Calico 有个坑默认的 IPIP 模式需要内核支持而某些精简版内核没编译相关模块。所以我推荐用VXLAN 模式兼容性更好。下面配置里我会明确指定。2.4 集群规划与参数计算单 Master 实验集群的规划如下你可以按自己机器调整角色主机名IP 示例配置Masterk8s-master192.168.1.102C4GNode1k8s-node1192.168.1.112C2GNode2k8s-node2192.168.1.122C2GPod 网段我选10.244.0.0/16Service 网段选10.96.0.0/12。这两个网段绝对不能和你的物理网络重叠否则路由会乱。判断方法很简单ip route看一下你内网用的网段避开就行。比如你内网是 192.168.x.x那 Pod 用 10.244 完全没冲突。注意Master 至少 2 核 2G但 2G 跑控制平面会非常紧张建议 4G。低于 2 核 kubeadm 会直接报错拒绝初始化。3. 系统层准备CentOS 8 的坑一个都别漏3.1 换源CentOS 8 停维后的第一道坎CentOS 8 的官方 mirror 已经下线直接yum install会报Failed to download metadata for repo AppStream。解决办法是把源指向归档地址。三台机器都要做cd /etc/yum.repos.d/ mkdir backup mv *.repo backup/ cat /etc/yum.repos.d/CentOS-Base.repo EOF [BaseOS] nameCentOS-8-BaseOS baseurlhttps://mirrors.aliyun.com/centos-vault/8.5.2111/BaseOS/$basearch/os/ gpgcheck0 enabled1 [AppStream] nameCentOS-8-AppStream baseurlhttps://mirrors.aliyun.com/centos-vault/8.5.2111/AppStream/$basearch/os/ gpgcheck0 enabled1 EOF yum clean all yum makecache这里用centos-vault归档路径版本号8.5.2111是 CentOS 8 最后一个稳定版。gpgcheck0是为了省去导入密钥的麻烦实验环境够用生产环境建议开启并导入正确密钥。3.2 关闭 swap、SELinux 和防火墙kubelet 默认要求关闭 swap否则会拒绝启动。这不是随便定的规矩——K8s 的内存管理假设它独占内存资源swap 会导致调度器对内存的判断失准。swapoff -a sed -i /swap/s/^/#/ /etc/fstab # 永久关闭 setenforce 0 sed -i s/^SELINUXenforcing/SELINUXpermissive/ /etc/selinux/config systemctl stop firewalld systemctl disable firewalld提示生产环境不建议直接关防火墙而是精确放行 K8s 需要的端口6443、10250、2379-2380 等。实验环境图省事关掉即可但你要知道这是图省事。3.3 加载内核模块与网络参数这是 CentOS 8 上最容易漏的一步。K8s 的网络和存储依赖overlay、br_netfilter等模块不加载的话 Calico 起不来、Pod 网络不通。cat /etc/modules-load.d/k8s.conf EOF overlay br_netfilter EOF modprobe overlay modprobe br_netfilter 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 --systemnet.ipv4.ip_forward1是让主机能转发 Pod 之间的流量bridge-nf-call-iptables1是让 iptables 规则能作用于网桥流量否则 Service 的负载均衡会失效。这两个参数不理解也没关系记住不设就一定出问题。3.4 时间同步集群节点时间差超过一定阈值证书校验和 etcd 选举都会出问题。CentOS 8 自带 chronysystemctl enable --now chronyd chronyc sources -v # 确认已同步4. 安装 containerd 与 kubeadm 三件套4.1 安装并配置 containerdyum install -y containerd mkdir -p /etc/containerd containerd config default /etc/containerd/config.toml生成的默认配置里有个关键项必须改——cgroup 驱动。K8s 从 1.22 起默认用 systemd 作为 cgroup 驱动而 containerd 默认是 cgroupfs两者不一致会导致 kubelet 报failed to create pod sandbox之类的错。sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml同时把 pause 镜像地址改成国内可访问的否则初始化时卡在拉取 sandbox 镜像sed -i s#sandbox_image .*#sandbox_image registry.aliyuncs.com/google_containers/pause:3.9# /etc/containerd/config.toml systemctl restart containerd systemctl enable containerd验证一下ctr version crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps4.2 配置 K8s 的 yum 源并安装组件cat /etc/yum.repos.d/kubernetes.repo EOF [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/ enabled1 gpgcheck0 EOF yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0 systemctl enable kubelet这里我锁定了1.28.0这个版本。为什么不装最新因为 CentOS 8 的内核版本较老默认 4.18太新的 K8s 可能用到新内核特性。1.28 是长期支持版本稳定性和兼容性都经过大量验证。systemctl enable kubelet只是设置开机自启此时它还没配置启动会失败这是正常的初始化后就好了。注意三台机器装的版本必须完全一致否则 join 时会报版本不匹配。装完用kubeadm version核对。5. 初始化 Master 节点5.1 拉取镜像并执行 init先预拉镜像避免初始化时超时kubeadm config images pull \ --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version v1.28.0然后执行初始化。这里我把 Pod 网段设成 Calico 要求的10.244.0.0/16kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version v1.28.0 \ --service-cidr10.96.0.0/12 \ --pod-network-cidr10.244.0.0/16--apiserver-advertise-address必须填 Master 的真实内网 IP不能填 127.0.0.1否则其他节点连不上。初始化成功后终端会打印一段kubeadm join命令务必复制保存这是 Node 加入集群的凭证。5.2 配置 kubectl 并验证mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config kubectl get nodes kubectl get pods -n kube-system此时 Master 状态是NotReady因为还没装 CNI。这是预期内的。5.3 安装 Calico 网络插件kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml如果内网拉不到就先把 yaml 下载下来改里面的镜像地址为国内源再 apply。装完等一两分钟kubectl get pods -n kube-system -w看到calico-node-xxxx和calico-kube-controllers都 Running 后kubectl get nodes里 Master 会变成Ready。实操心得Calico 的calico-node是 DaemonSet每个节点一个。如果某个节点上它一直 CrashLoopBackOff九成是内核模块没加载或 IP 自动检测选错了网卡。可以在 calico.yaml 里显式指定IP_AUTODETECTION_METHOD和网卡名。6. Node 节点加入与集群验证6.1 执行 join在 node1、node2 上执行 Master 初始化时打印的那条命令形如kubeadm join 192.168.1.10:6443 --token xxxxx.xxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxx如果令牌过期了默认 24 小时在 Master 上重新生成kubeadm token create --print-join-command6.2 验证集群健康回到 Masterkubectl get nodes -o wide kubectl get pods -A kubectl cluster-info三个节点都 Ready 就成功了。再跑个测试 Pod 验证网络kubectl run test --imagenginx --restartNever kubectl get pod test -o wide kubectl exec -it test -- curl -s localhost能返回 nginx 欢迎页说明 Pod 网络和调度都正常。6.3 部署一个真实工作负载光跑单个 Pod 不够用 Deployment Service 验证完整链路kubectl create deployment web --imagenginx --replicas3 kubectl expose deployment web --port80 --typeNodePort kubectl get svc web拿到 NodePort 后用任意节点 IP 端口访问能轮询到三个副本就说明 Service 负载均衡生效了。7. 常见问题与排查技巧实录CentOS 8 上装 K8s报错五花八门我把踩过的坑整理成速查表现象根因解决yum 报 metadata 下载失败CentOS 8 源失效换 centos-vault 归档源kubelet 起不来报 swapswap 未关swapoff 改 fstabinit 卡在拉镜像镜像源不可达用阿里云 image-repositoryPod 一直 Pending没装 CNI装 Calico/Flannelcalico-node CrashLoop内核模块缺失加载 br_netfilter、overlayjoin 报证书错误token 过期重新生成 join 命令Pod 间 ping 不通ip_forward 未开sysctl 设置并生效cgroup 相关报错驱动不一致containerd 改 SystemdCgroup几个排查命令必须记牢journalctl -u kubelet -f # 看 kubelet 日志 crictl logs container-id # 看容器日志 kubectl describe pod name # 看 Pod 事件 kubectl get events -A --sort-by.lastTimestamp避坑技巧kubectl describe pod的 Events 区域是排查第一现场90% 的问题镜像拉不到、调度失败、挂载失败都能从这里看出端倪。养成先看 Events 的习惯比盲目翻日志快得多。还有一个 CentOS 8 特有的坑默认的nftables和 Calico 的 iptables 规则可能冲突。如果网络策略不生效检查一下iptables-legacy和iptables-nft的切换必要时update-alternatives --set iptables /usr/sbin/iptables-legacy。8. 收尾与后续可扩展方向集群跑起来只是起点。如果你想让这套环境更接近生产可以继续做几件事把单 Master 扩成三 Master 高可用加 keepalived haproxy 做 VIP、给 etcd 做定期备份、接入 Prometheus 监控、用 Helm 管理应用发布。这些都是在当前基础上叠加不用推倒重来。我个人在 CentOS 8 上折腾这套流程最大的体会是版本锁定比追新重要得多。K8s、containerd、Calico 三者的版本兼容矩阵一定要提前查我见过太多人因为随手装了最新版导致 CNI 和 kubelet 对不上排查半天。另外所有 yaml 和命令最好整理成一个部署脚本下次重装直接跑比手敲靠谱。最后提醒一句CentOS 8 终究是过渡方案有条件还是尽早迁移到还在维护的发行版别让技术债越滚越大。