资讯动态

CentOS 8 部署 Kubernetes 实战:从系统准备到集群跑通

发布时间:2026/10/13 10:15:38 来源:尧图企业网站定制
1. 为什么现在还有人要在 CentOS 8 上部署 KubernetesCentOS 8 这个系统版本挺有意思官方在 2021 年底就把维护模式给切了按道理说大家应该往 Rocky、Alma 或者 Ubuntu 上迁。但现实情况是大量企业内部的老业务、老硬件、老运维习惯还卡在 CentOS 8 上尤其是那些 2020 到 2022 年之间上的项目装机镜像就是 CentOS 8重新换系统意味着要重新做安全基线、重新过一遍内部流程成本太高。所以“在 CentOS 8 上把 Kubernetes 跑起来”这件事到今天依然有非常实际的需求。我自己前前后后在 CentOS 8 上部署过不下十套 K8s 集群有小到三台虚拟机的测试环境也有十几台物理机的中等规模生产环境。踩过的坑从 yum 源失效、内核模块没加载、cgroup 驱动不匹配到容器运行时和 kubelet 版本对不上基本都经历了一遍。这篇文章就是把这些经验完整地梳理出来从系统准备到集群跑通再到常见问题排查给你一套可以直接照着做的方案。这篇文章适合谁看如果你是运维工程师、后端开发或者正在做私有化交付的技术人员需要在 CentOS 8 上从零搭一套 K8s那这篇内容基本能覆盖你 90% 的场景。如果你只是想了解一下 K8s 部署的大致流程也可以看因为我会把每一步“为什么这么做”讲清楚而不是只丢一堆命令让你复制。需要提前说明的是CentOS 8 的官方 yum 源已经不可用了这是部署过程中第一个必须解决的问题。另外 K8s 从 1.24 版本开始移除了 dockershim容器运行时的选择也跟以前不一样了。这些变化都会直接影响你的部署方案我会在正文里逐一拆解。2. 部署方案的整体设计与选型思路2.1 版本组合怎么选才不踩坑在 CentOS 8 上部署 K8s版本组合是第一个要定下来的事情。我的建议是K8s 用 1.26 或 1.27容器运行时用 containerd网络插件用 Calico 或 Flannel。这套组合是我实测下来最稳的社区资料也最全。为什么不推荐 Docker 作为运行时因为 K8s 1.24 之后已经彻底移除了 dockershim虽然你可以额外装 cri-dockerd 来兼容但多一层适配就多一层故障点。containerd 本身就是 CRI 标准的实现kubelet 直接调它链路更短出问题也更好排查。至于 K8s 版本不建议追最新。1.28 之后的版本对内核和系统组件的要求更高CentOS 8 默认的 4.18 内核虽然能跑但某些特性会受限。1.26 和 1.27 在 CentOS 8 上的兼容性经过大量验证属于“闭眼选”的范围。组件推荐版本选择理由操作系统CentOS 8.5最后一个相对稳定的 CentOS 8 小版本容器运行时containerd 1.6.xCRI 原生支持无需额外适配层K8s1.26.x / 1.27.x与 CentOS 8 内核兼容性好社区资料丰富网络插件Calico 3.26支持 NetworkPolicy性能稳定内核4.18默认满足 K8s 最低要求无需升级2.2 集群架构的取舍单 Master 还是多 Master测试环境用单 Master 就够了但生产环境一定要上多 Master。K8s 的控制平面组件 kube-apiserver、etcd、kube-scheduler、kube-controller-manager 如果只跑在一个节点上那这个节点挂了整个集群就失控了。多 Master 架构下通常用 3 个 Master 节点加 N 个 Worker 节点。etcd 会以集群模式跑在这 3 个 Master 上kube-apiserver 前面挂一个负载均衡器可以用 HAProxy Keepalived也可以用云厂商的 LB。这样任意一个 Master 挂了集群还能正常工作。我自己的习惯是3 Master 3 Worker 起步Worker 节点根据业务负载再扩。Master 节点配置不用太高2C4G 就够但 etcd 对磁盘 IO 比较敏感建议用 SSD。Worker 节点就看你要跑什么业务了CPU 和内存按需配。2.3 网络方案的选择逻辑K8s 的网络模型有几个硬性要求每个 Pod 有独立 IP、Pod 之间能直接通信、Pod 和 Node 之间能通信。要满足这些要求必须装网络插件。Flannel 是最简单的配置少上手快但它不支持 NetworkPolicy也就是说你没法做 Pod 级别的网络访问控制。Calico 功能更全支持 NetworkPolicy性能也好但配置稍微复杂一点。如果你只是测试环境Flannel 够用如果是生产环境我强烈建议上 Calico。还有一个细节Calico 的默认模式是 IPIP 隧道跨节点通信会多一层封装性能有损耗。如果你的节点在同一个二层网络里可以改成 BGP 模式性能会好很多。这个后面实操部分我会详细说。3. 系统层面的准备工作3.1 解决 CentOS 8 yum 源失效的问题CentOS 8 官方源在 2021 年底就下线了你直接yum install会报 “Failed to download metadata for repo ‘AppStream’” 之类的错误。解决办法是把源指向 vault 归档地址。具体操作是先把/etc/yum.repos.d/下面的源文件备份一下然后替换成 vault 源。你可以手动改也可以用 sed 批量替换。我习惯用 sed一条命令搞定cd /etc/yum.repos.d/ sed -i s/mirrorlist/#mirrorlist/g /etc/yum.repos.d/CentOS-* sed -i s|#baseurlhttp://mirror.centos.org|baseurlhttp://vault.centos.org|g /etc/yum.repos.d/CentOS-* yum clean all yum makecache执行完之后yum repolist能看到仓库列表就说明源配好了。这一步看着简单但很多人卡在这里因为报错信息不太直观容易以为是网络问题。注意vault 源的下载速度可能比较慢如果内网有镜像站优先用内网镜像。另外替换源之后建议先yum update一次把系统补丁打全避免后续装 K8s 组件时出现依赖冲突。3.2 关闭 Swap 和 SELinuxK8s 要求关闭 Swap原因是 kubelet 在调度 Pod 时需要准确知道节点还剩多少内存如果开了 Swap内存统计就不准了可能导致 Pod 被调度到内存已经不够的节点上。关闭 Swap 的命令很简单swapoff -a sed -i /swap/s/^/#/ /etc/fstab第一行是临时关闭第二行是注释掉 fstab 里的 Swap 挂载项保证重启后也不会自动挂载。SELinux 也建议关掉虽然 K8s 理论上支持 SELinux但实际部署中它会带来各种权限问题尤其是容器挂载宿主机目录的时候。关闭方式setenforce 0 sed -i s/^SELINUXenforcing/SELINUXpermissive/ /etc/selinux/config这里改成 permissive 而不是 disabled是因为 disabled 需要重启才能生效而 permissive 是立即生效的只是记录警告不拦截。等集群跑稳定了你再决定要不要彻底 disabled。3.3 内核模块与系统参数调优K8s 的网络和存储功能依赖一些内核模块必须提前加载。主要是br_netfilter和overlay这两个。br_netfilter让 iptables 能过滤桥接流量overlay是 containerd 存储驱动需要的。modprobe br_netfilter modprobe overlay cat EOF /etc/modules-load.d/k8s.conf br_netfilter overlay EOF然后是 sysctl 参数。K8s 需要开启 IP 转发否则 Pod 之间的跨节点通信会失败。另外bridge-nf-call-iptables也要打开让桥接流量经过 iptables 处理。cat EOF /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 --system执行完sysctl --system后可以用sysctl net.ipv4.ip_forward确认一下返回 1 就对了。3.4 主机名与 hosts 解析每个节点的主机名必须唯一而且最好能通过主机名互相解析。我习惯在/etc/hosts里把集群所有节点的 IP 和主机名都写进去这样比依赖 DNS 更可靠。hostnamectl set-hostname k8s-master-01 cat EOF /etc/hosts 192.168.1.10 k8s-master-01 192.168.1.11 k8s-master-02 192.168.1.12 k8s-master-03 192.168.1.20 k8s-worker-01 192.168.1.21 k8s-worker-02 192.168.1.22 k8s-worker-03 EOF主机名不要用下划线K8s 对主机名有格式要求只允许字母、数字、连字符和点号。这个细节很多人不注意等到 kubelet 启动报错才发现。4. 容器运行时 containerd 的安装与配置4.1 安装 containerdcontainerd 的安装方式有好几种我推荐用官方二进制包因为可控性最强不依赖特定发行版的包管理。先从 GitHub Releases 下载对应版本的压缩包解压到/usr/local/下面。wget https://github.com/containerd/containerd/releases/download/v1.6.24/containerd-1.6.24-linux-amd64.tar.gz tar Cxzvf /usr/local containerd-1.6.24-linux-amd64.tar.gz然后配置 systemd 服务。containerd 官方提供了一个 service 文件模板下载后放到/usr/local/lib/systemd/system/下面然后systemctl daemon-reload并启动。wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -O /usr/local/lib/systemd/system/containerd.service systemctl daemon-reload systemctl enable --now containerd启动后用systemctl status containerd确认状态是 active 的。如果启动失败大概率是配置文件有问题可以看journalctl -u containerd的日志。4.2 配置 containerd 使用 systemd cgroup 驱动这是最关键的一步。K8s 在 CentOS 8 上默认用 systemd 作为 cgroup 驱动而 containerd 默认用的是 cgroupfs。两者不一致会导致 kubelet 报错Pod 起不来。需要修改/etc/containerd/config.toml找到SystemdCgroup这一项改成 true。如果你是用containerd config default生成的默认配置这一项默认是 false。containerd config default /etc/containerd/config.toml sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml systemctl restart containerd另外默认配置里的 pause 镜像地址是registry.k8s.io/pause:3.6国内环境可能拉不下来。可以换成你自己的镜像仓库地址或者提前把镜像导入到本地。实操心得改完 config.toml 之后一定要重启 containerd而且重启后最好用ctr version确认一下版本信息确保服务真的起来了。我有一次改完配置忘了重启后面 kubelet 一直报错排查了半天才发现是 containerd 还在用旧配置。4.3 安装 runc 和 CNI 插件containerd 需要 runc 来实际创建容器还需要 CNI 插件来配置 Pod 网络。runc 可以从 GitHub 下载二进制文件放到/usr/local/sbin/下面。wget https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64 install -m 755 runc.amd64 /usr/local/sbin/runcCNI 插件是一组二进制文件下载后解压到/opt/cni/bin/目录。wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz mkdir -p /opt/cni/bin tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.3.0.tgz这两个装完之后containerd 的基础环境就齐了。可以用runc --version和ls /opt/cni/bin/确认一下。5. K8s 组件的安装与集群初始化5.1 安装 kubelet、kubeadm、kubectl这三个组件是 K8s 的核心。kubelet 跑在每个节点上负责管理容器kubeadm 用来初始化集群和加入节点kubectl 是命令行工具。在 CentOS 8 上可以通过 K8s 官方 yum 源安装。先添加源cat EOF /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurlhttps://pkgs.k8s.io/core:/stable:/v1.27/rpm/ enabled1 gpgcheck1 gpgkeyhttps://pkgs.k8s.io/core:/stable:/v1.27/rpm/repodata/repomd.xml.key EOF然后安装指定版本yum install -y kubelet-1.27.8 kubeadm-1.27.8 kubectl-1.27.8 systemctl enable kubelet注意这里 kubelet 先不要启动因为还没初始化集群启动了也会报错。等 kubeadm init 跑完之后kubelet 会自动起来。5.2 初始化第一个 Master 节点初始化命令里需要指定几个关键参数Pod 网段、Service 网段、API Server 地址、容器运行时。Pod 网段和 Service 网段不能跟宿主机网段重叠否则会路由冲突。kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --image-repositoryregistry.aliyuncs.com/google_containers \ --kubernetes-versionv1.27.8 \ --service-cidr10.96.0.0/12 \ --pod-network-cidr10.244.0.0/16 \ --cri-socketunix:///var/run/containerd/containerd.sock--image-repository指定镜像仓库国内环境用阿里云的镜像源会快很多。--cri-socket指定 containerd 的 socket 路径因为现在默认不是 Docker 了必须显式指定。初始化成功后会输出一段 join 命令类似kubeadm join 192.168.1.10:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx。这段命令要保存好后面加 Worker 节点和 Master 节点都要用。然后配置 kubectl 的 kubeconfigmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config执行kubectl get nodes应该能看到 Master 节点状态是 NotReady因为还没装网络插件。5.3 安装 Calico 网络插件Calico 的安装很简单用 kubectl apply 一个 yaml 文件就行。但要注意 Pod 网段要跟 kubeadm init 时指定的--pod-network-cidr一致。kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml如果你改了 Pod 网段需要先下载 yaml 文件修改里面的CALICO_IPV4POOL_CIDR环境变量再 apply。等几分钟kubectl get pods -n kube-system看到 Calico 的 Pod 都 Running 了kubectl get nodes里 Master 节点变成 Ready就说明网络插件装好了。注意Calico 默认用 IPIP 模式如果你节点在同一个二层网络可以改成 BGP 模式提升性能。修改方式是编辑 Calico 的 DaemonSet把CALICO_IPV4POOL_IPIP改成Off。不过改之前要确认网络设备支持 BGP否则可能导致跨节点通信失败。5.4 加入 Worker 节点和 Master 节点Worker 节点的加入很简单在 Worker 节点上执行之前保存的 join 命令就行。但前提是 Worker 节点也装好了 containerd、kubelet、kubeadm并且做了系统层面的准备。kubeadm join 192.168.1.10:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx如果是加 Master 节点需要加--control-plane参数并且要先在第一个 Master 上生成证书 keykubeadm init phase upload-certs --upload-certs然后 join 命令里加上--control-plane --certificate-key xxx。所有节点加完之后在 Master 上执行kubectl get nodes应该能看到所有节点都是 Ready 状态。6. 常见问题排查与避坑指南6.1 kubelet 启动失败怎么查kubelet 启动失败是最常见的问题表现是systemctl status kubelet显示 failed。排查思路是先用journalctl -u kubelet -f看日志日志里通常会告诉你具体原因。常见的几个原因cgroup 驱动不匹配containerd 和 kubelet 用的驱动不一致、Swap 没关、SELinux 没关、配置文件路径不对。我遇到最多的是 cgroup 驱动问题报错信息类似 “failed to run Kubelet: misconfiguration: kubelet cgroup driver: ‘cgroupfs’ is different from docker cgroup driver: ‘systemd’”。解决办法就是改 containerd 的配置把 SystemdCgroup 改成 true。还有一个坑是 kubelet 的配置文件/var/lib/kubelet/config.yaml里 cgroupDriver 写的是 cgroupfs需要改成 systemd。这个文件是 kubeadm init 生成的如果 init 的时候没指定默认就是 cgroupfs。6.2 Pod 一直 Pending 或 CrashLoopBackOffPod 一直 Pending通常是资源不够或者没有可调度的节点。用kubectl describe pod pod-name -n namespace看 Events里面会写原因。如果是 “Insufficient cpu” 或 “Insufficient memory”那就是节点资源不够了。如果是 “node(s) had taint”那就是 Master 节点有污点不允许调度普通 Pod。CrashLoopBackOff 是容器启动后不断崩溃重启。常见原因是镜像里的启动命令有问题、配置文件挂载错了、依赖的服务没起来。也是用kubectl describe pod和kubectl logs排查。6.3 跨节点 Pod 通信失败跨节点 Pod 通信失败大概率是网络插件的问题。先确认 Calico 或 Flannel 的 Pod 是不是都 Running然后检查节点的 iptables 规则和路由表。如果是 Calico IPIP 模式检查ip tunnel show有没有 tunl0 接口。如果是 BGP 模式检查calicoctl node status看 BGP 邻居是不是 Established。还有一个容易忽略的点宿主机的防火墙规则可能把 Pod 网段的流量拦了。CentOS 8 默认用 firewalld建议在部署 K8s 之前就把 firewalld 关了或者放行 Pod 网段和 Service 网段。问题现象可能原因排查命令解决办法kubelet 启动失败cgroup 驱动不匹配journalctl -u kubelet改 containerd 配置为 systemdPod Pending资源不足或节点有污点kubectl describe pod扩容节点或去掉污点Pod CrashLoopBackOff容器启动命令错误kubectl logs检查镜像和启动参数跨节点通信失败网络插件异常kubectl get pods -n kube-system重装网络插件或检查防火墙镜像拉取失败镜像仓库不可达kubectl describe pod配置镜像加速或导入本地镜像6.4 证书过期导致集群不可用K8s 的证书默认有效期是一年到期后 kube-apiserver 会拒绝所有请求集群直接不可用。查看证书有效期kubeadm certs check-expiration续期命令kubeadm certs renew all systemctl restart kubelet续期之后要重启 kube-apiserver、kube-controller-manager、kube-scheduler 这些静态 Pod最简单的方式是重启 kubelet它会自动重建这些 Pod。另外续期后要更新 kubeconfig 文件否则 kubectl 还是用旧证书。实操心得建议在证书到期前一个月就做续期别等到过期了再处理。过期后 kube-apiserver 起不来kubectl 也用不了只能手动用 openssl 或者备份的证书恢复非常麻烦。我自己的做法是写一个定时任务每个月检查一次证书有效期提前告警。7. 集群跑通后的验证与日常维护7.1 部署一个测试应用验证集群集群搭好之后别急着上业务先跑一个简单的测试应用验证一下。我习惯用 nginx 或者一个简单的 echo 服务。kubectl create deployment nginx-test --imagenginx:alpine --replicas3 kubectl expose deployment nginx-test --port80 --typeNodePort然后kubectl get pods -o wide看 Pod 是不是分布在不同节点上kubectl get svc看 Service 的 NodePort 是多少。用 curl 访问任意节点的 NodePort能返回 nginx 欢迎页就说明集群基本功能正常。再测试一下 DNS 解析在 Pod 里 ping 一下kubernetes.default.svc能解析就说明 CoreDNS 工作正常。7.2 日常巡检要看哪些指标集群跑起来之后日常巡检主要看几个方面节点状态、Pod 状态、资源使用率、证书有效期、etcd 健康状态。节点状态用kubectl get nodesPod 状态用kubectl get pods --all-namespaces资源使用率需要装 metrics-server然后kubectl top nodes和kubectl top pods。etcd 健康状态用etcdctl endpoint health。我自己的习惯是每天上班第一件事就是跑一遍这些命令看看有没有异常。如果集群规模大建议上 Prometheus Grafana 做监控告警靠人工巡检不现实。7.3 节点扩容与缩容的操作要点扩容 Worker 节点很简单新节点做好系统准备、装好 containerd 和 kubelet然后执行 join 命令就行。缩容的话先kubectl drain node-name --ignore-daemonsets把 Pod 驱逐到其他节点然后kubectl delete node node-name从集群里删掉最后在节点上kubeadm reset清理环境。drain 的时候要注意如果有 Pod 用了 emptyDir 或者 local storage驱逐后数据会丢。另外 DaemonSet 的 Pod 默认不会被驱逐需要加--ignore-daemonsets参数。7.4 备份与恢复的基本策略etcd 是集群的大脑所有集群状态都存在 etcd 里所以 etcd 的备份至关重要。备份命令ETCDCTL_API3 etcdctl snapshot save /backup/etcd-snapshot.db \ --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key建议写个定时任务每天备份一次备份文件保留最近 7 天。恢复的时候用etcdctl snapshot restore然后修改 etcd 的静态 Pod 配置指向恢复后的数据目录。除了 etcd还要备份/etc/kubernetes/目录下的所有证书和配置文件。这些文件丢了集群就彻底起不来了。8. 一些零散但重要的经验补充CentOS 8 上部署 K8s还有一个容易被忽略的点是时间同步。K8s 的证书验证、Token 有效期都依赖准确的时间如果节点之间时间差太大会出现各种莫名其妙的认证失败。建议所有节点都配好 NTP 同步用chronyd或者ntpd都行。另外CentOS 8 的默认内核参数里net.ipv4.ip_forward是 0必须手动打开。这个前面提过了但值得再强调一次因为很多人会忘。关于镜像仓库如果你在内网环境建议搭一个 Harbor 或者 registry把 K8s 需要的镜像提前推上去。kubeadm init 的时候用--image-repository指向你的内网仓库这样初始化会快很多也不依赖外网。最后说一个我踩过的坑CentOS 8 的iptables默认是 nftables 后端而 K8s 的某些组件对 nftables 的支持还不完善。如果遇到网络规则不生效的问题可以试试把 iptables 切换成 legacy 模式update-alternatives --set iptables /usr/sbin/iptables-legacy update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy切换之后重启 containerd 和 kubelet网络问题大概率能解决。这个坑我在两套环境里都遇到过排查起来很费时间因为报错信息不会直接告诉你是 nftables 的问题。这套流程走下来一套 CentOS 8 上的 K8s 集群基本就能稳定运行了。后续的 Ingress、存储、监控、日志这些都是在这个基础之上叠加的基础打牢了后面的事情就顺了。

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

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

免费获取报价 →
↑