news 2026/10/14 15:47:23

CentOS 8 上从零部署 Kubernetes 集群实战指南:containerd 与 kubeadm 完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CentOS 8 上从零部署 Kubernetes 集群实战指南:containerd 与 kubeadm 完整流程

1. 为什么在 CentOS 8 上部署 Kubernetes 值得单独拿出来讲

CentOS 8 这个系统版本在容器圈子里一直有点尴尬。它比 CentOS 7 新,内核版本更高,默认的包管理工具换成了 dnf,网络组件也升级到了 nmcli 统一管理,但它的生命周期又比很多人预期的短。这就导致一个很现实的问题:你手头有一批 CentOS 8 的机器,业务要求在上面跑 Kubernetes,而网上大部分教程要么是 CentOS 7 的老路子,要么是 Ubuntu 的玩法,直接照搬总会卡在某个环节。

我自己前前后后在 CentOS 8 上部署过不下十套 Kubernetes 集群,从单节点测试环境到多节点生产集群都折腾过。踩过的坑包括但不限于:容器运行时选 Docker 还是 containerd 的纠结、防火墙规则和 kube-proxy 打架、SELinux 导致的挂载失败、镜像拉取超时、kubelet 反复重启等等。这些问题在 CentOS 7 上可能不会遇到,或者表现方式完全不同。

这篇文章面向的是有一定 Linux 基础、准备在 CentOS 8 上从零搭建 Kubernetes 集群的运维或开发人员。我会把整个部署过程拆成几个关键阶段,每个阶段不仅告诉你命令怎么写,更重要的是解释为什么这么写、不这么写会出什么问题。文章里涉及的 IP 地址、主机名都是示例,你替换成自己环境的即可。整个方案基于 kubeadm 这个官方推荐的部署工具,容器运行时我会重点讲 containerd,同时也会说明如果你坚持用 Docker 该怎么处理。

需要提前说明的是,Kubernetes 的版本迭代很快,我下面用的版本号是一个经过验证的稳定组合,你在实际操作时可以去官方仓库确认当前的最新稳定版,但核心逻辑和步骤是通用的。另外,所有操作都假设你有 root 权限或者可以通过 sudo 提权,这是部署集群的基本前提。

2. 部署前的系统底座准备:别急着装 kubeadm

2.1 主机名与 hosts 解析的规范化设置

很多人拿到机器第一件事就是直接开始装 Docker 和 kubeadm,结果集群初始化时各种超时和证书错误。我建议你先把最基础的三件事做扎实:主机名、hosts 文件、时间同步。

主机名不是随便起的,Kubernetes 的节点注册、证书签发、服务发现都和它绑定。如果你后期想改主机名,那基本等于重新部署一遍。所以一开始就要规划好,比如用k8s-master、k8s-node01、k8s-node02这种命名方式,一看就知道角色。

# 在每台机器上分别执行,替换成你自己的主机名 hostnamectl set-hostname k8s-master

然后编辑每台机器的/etc/hosts,把所有节点的 IP 和主机名对应关系写进去。这一步看起来简单,但它是集群内部通信的基础。kubelet 向 API Server 注册时用的就是主机名,如果你没配 hosts,就得依赖 DNS,而内网 DNS 的稳定性往往不如本地 hosts 文件可靠。

# 在每台机器上执行 cat >> /etc/hosts <<EOF 192.168.1.10 k8s-master 192.168.1.11 k8s-node01 192.168.1.12 k8s-node02 EOF

时间同步同样关键。Kubernetes 的证书有效期校验、事件时间戳、日志排序都依赖系统时间。如果节点之间时间差超过几分钟,你可能会遇到证书报错或者节点状态异常。CentOS 8 默认可能没装 chrony,先确认一下:

# 安装并启动时间同步服务 dnf install -y chrony systemctl enable --now chronyd # 检查同步状态 chronyc sources -v

2.2 防火墙、SELinux 与 swap 的取舍逻辑

这三个东西是 CentOS 8 上部署 Kubernetes 最容易出问题的点,我一个个说。

防火墙:Kubernetes 的组件之间需要大量端口通信,kubelet、API Server、etcd、Pod 网络等等。你可以选择精细地开放每个端口,也可以直接关掉 firewalld。我的建议是,如果是内网测试环境,直接关掉最省事;如果是生产环境,那就要认真规划端口规则。但即便关掉 firewalld,也要注意 iptables 的规则,因为 Docker 或 containerd 会往 iptables 里写规则,有时候会和 firewalld 残留规则冲突。

# 测试环境直接关闭 systemctl stop firewalld systemctl disable firewalld # 确认 iptables 规则清空 iptables -F && iptables -X

SELinux:CentOS 8 默认是 enforcing 模式。SELinux 本身是个好东西,但 Kubernetes 的很多操作,比如挂载卷、访问容器文件系统,在 enforcing 模式下会被拦截。你可以选择配置 SELinux 策略,但那工作量很大。更实际的做法是把它设为 permissive 模式,这样它只记录警告不拦截,方便排查问题。如果设为 disabled,需要重启系统。

# 临时设为 permissive setenforce 0 # 永久生效,编辑 /etc/selinux/config,把 SELINUX=enforcing 改为 SELINUX=permissive sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config

Swap:kubelet 默认要求关闭 swap,否则启动时会报错。这是因为 Kubernetes 的调度器需要精确掌握节点的内存资源,而 swap 会让内存统计变得不准确。虽然新版本有实验性的 swap 支持,但生产环境不建议开启。

# 临时关闭 swapoff -a # 永久关闭,注释掉 /etc/fstab 中的 swap 行 sed -i '/swap/s/^/#/' /etc/fstab

2.3 内核参数与模块的预配置

Kubernetes 的网络和存储功能依赖一些内核模块和参数。比如br_netfilter模块用于网桥流量过滤,overlay模块用于 OverlayFS 存储驱动。这些在 CentOS 8 上默认可能没加载。

# 加载内核模块 modprobe br_netfilter modprobe overlay # 设置开机自动加载 cat > /etc/modules-load.d/k8s.conf <<EOF br_netfilter overlay EOF

然后配置网络参数,让 iptables 能正确转发网桥流量:

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 --system

这几个参数不配置的话,Pod 之间跨节点通信会出问题,表现就是 ping 不通或者服务访问超时。我遇到过好几次因为漏了net.ipv4.ip_forward导致 Pod 网络不通的情况,排查半天才发现是这里的问题。

3. 容器运行时选型:containerd 与 Docker 的真实对比

3.1 为什么 containerd 成了默认推荐

Kubernetes 从 1.24 版本开始正式移除了对 Docker 的直接支持,也就是去掉了 dockershim 这个适配层。这意味着如果你还用 Docker 作为容器运行时,需要额外安装 cri-dockerd 这个组件来桥接。而 containerd 本身就是 CRI(容器运行时接口)兼容的,kubelet 可以直接和它对话,少了一层转换,性能和稳定性都更好。

containerd 的架构比 Docker 简洁很多。Docker 包含了镜像构建、容器运行、网络管理、CLI 工具等一大堆功能,而 Kubernetes 只需要其中的容器运行部分。containerd 就是从这个需求出发,把不必要的部分砍掉,专注于容器生命周期管理。它的配置文件在/etc/containerd/config.toml,通过ctr命令行工具或者crictl来操作。

我实测下来,containerd 启动容器更快,资源占用更低,日志也更清晰。如果你是新部署集群,我强烈建议直接用 containerd。Docker 更适合开发者在本地构建和测试镜像,在集群节点上它有点太重了。

3.2 containerd 的安装与关键配置项

CentOS 8 的默认仓库里没有 containerd,需要先添加 Docker 的官方仓库(containerd 也是 Docker 团队维护的):

# 添加仓库 dnf install -y dnf-utils dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装 containerd dnf install -y containerd.io

安装完成后,先生成默认配置:

mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml

然后需要修改两个关键配置。第一个是SystemdCgroup,默认是 false,要改成 true。因为 CentOS 8 用 systemd 管理 cgroup,如果这里不匹配,kubelet 启动 Pod 时会报 cgroup 相关的错误。

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

第二个是镜像仓库地址。默认配置里用的是registry.k8s.io或者k8s.gcr.io,国内访问可能不稳定。你可以替换成国内可访问的镜像源,或者配置私有仓库。这个后面在初始化集群时还会讲到。

# 启动 containerd systemctl enable --now containerd # 验证状态 systemctl status containerd

3.3 如果你坚持用 Docker 该怎么处理

有些团队因为历史原因或者习惯问题,还是想用 Docker。这没问题,但你需要额外安装cri-dockerd。这个组件是 Docker 官方维护的 CRI 适配器,让 kubelet 能通过它来调用 Docker。

安装 cri-dockerd 的步骤稍微多一点,需要从源码编译或者下载预编译的二进制包。安装完成后,它会监听一个 Unix socket,kubelet 通过这个 socket 和 Docker 通信。然后在 kubeadm 初始化时,需要指定--cri-socket参数指向 cri-dockerd 的 socket 地址。

不过我要提醒一句,cri-dockerd 的维护活跃度不如 containerd,而且多了一层调用,出问题时排查链路更长。除非你有明确的理由必须用 Docker,否则还是建议用 containerd。

4. kubeadm、kubelet、kubectl 三件套的安装与版本锁定

4.1 仓库配置与版本选择策略

kubeadm、kubelet、kubectl 这三个组件需要安装在同一版本,版本不一致会导致各种兼容性问题。kubeadm 负责初始化集群,kubelet 是每个节点上的代理,kubectl 是命令行客户端。

CentOS 8 的默认仓库里没有这些,需要添加 Kubernetes 的官方仓库。这里有个细节:官方仓库的地址是pkgs.k8s.io,你需要根据想要的版本选择对应的仓库路径。比如要装 1.28 版本,就添加 1.28 的仓库。

cat > /etc/yum.repos.d/kubernetes.repo <<EOF [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/repodata/repomd.xml.key EOF

版本选择上,我建议不要追最新版,而是选一个已经发布几个月、社区反馈稳定的版本。新版本刚出来时往往有一些未发现的 bug,而且很多周边工具(比如网络插件、存储插件)还没跟上适配。我用的比较多的是 1.26 到 1.28 这几个版本,稳定性都不错。

4.2 安装过程中的依赖处理与版本锁定

安装命令本身很简单:

dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

但这里有个坑:--disableexcludes=kubernetes这个参数是为了防止其他仓库的版本覆盖 Kubernetes 仓库的版本。如果你不加这个参数,可能会装到系统仓库里的旧版本。

安装完成后,要立即锁定版本,防止后续dnf update时被意外升级:

dnf versionlock add kubelet kubeadm kubectl

如果没有versionlock命令,先安装dnf-plugin-versionlock插件。这个操作在生产环境特别重要,因为 kubelet 的小版本升级可能导致节点 NotReady,而集群升级是需要按特定流程走的,不能随便升级。

然后设置 kubelet 开机自启,但先不要启动:

systemctl enable kubelet

kubelet 现在启动会失败,因为它还在等 kubeadm 的初始化配置。这是正常的,等集群初始化完成后它就会正常运行。

4.3 镜像预拉取:解决初始化时的等待焦虑

kubeadm 初始化时会去拉取一堆控制平面组件的镜像,比如 API Server、etcd、CoreDNS 等。这些镜像默认从registry.k8s.io拉取,国内网络环境下可能会很慢甚至超时。

你可以先用kubeadm config images list看看需要哪些镜像:

kubeadm config images list

然后有两种处理方式。一种是手动拉取并重新打标签,另一种是配置 kubelet 使用镜像加速。我一般用第一种,更可控:

# 拉取镜像并重新打标签的脚本示例 for image in $(kubeadm config images list); do # 这里替换成你实际可访问的镜像源地址 new_image=$(echo $image | sed 's|registry.k8s.io|your-mirror.example.com|') ctr -n k8s.io images pull $new_image ctr -n k8s.io images tag $new_image $image done

注意ctr命令要指定-n k8s.io这个命名空间,因为 kubelet 用的是这个命名空间,不指定的话拉取的镜像 kubelet 看不到。

5. 集群初始化的完整流程与网络插件选型

5.1 kubeadm init 的参数拆解与执行

到了最关键的一步。kubeadm init 这个命令有很多参数,我挑几个最常用的解释一下。

kubeadm init \ --apiserver-advertise-address=192.168.1.10 \ --control-plane-endpoint=k8s-master \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --image-repository=registry.aliyuncs.com/google_containers \ --kubernetes-version=v1.28.0

--apiserver-advertise-address是 API Server 对外通告的地址,多网卡机器上一定要指定,不然可能选错网卡。--control-plane-endpoint是控制平面入口,单节点可以写主机名,多节点高可用时要写 VIP 或者负载均衡地址。--pod-network-cidr是 Pod 网络的地址段,这个必须和后面要装的网络插件匹配,比如 Flannel 默认用10.244.0.0/16,Calico 默认用192.168.0.0/16。--image-repository指定镜像仓库,国内环境建议换成可访问的源。

执行成功后,终端会输出一段很长的信息,包括如何配置 kubectl 的 kubeconfig,以及节点加入集群的 token 命令。一定要把 join 命令保存下来,后面加节点全靠它。如果忘了,可以用kubeadm token create --print-join-command重新生成。

# 配置 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

这时候节点状态是 NotReady,因为还没装网络插件。

5.2 Flannel 与 Calico 的选择依据

网络插件是 Kubernetes 集群的血管,没有它 Pod 之间无法通信。主流的选择有 Flannel、Calico、Cilium 等。

Flannel 是最简单的,配置少,资源占用低,适合中小规模集群。它用 VXLAN 或者 host-gw 模式实现跨节点通信。缺点是功能单一,没有网络策略(NetworkPolicy)支持。

Calico 功能更丰富,支持网络策略、BGP 路由、IP 池管理,适合对网络有精细控制需求的生产环境。它的架构比 Flannel 复杂,排查问题需要更多网络知识。

Cilium 基于 eBPF 技术,性能最好,可观测性也强,但对内核版本有要求,CentOS 8 的内核版本(4.18)勉强支持,但可能有些高级特性用不了。

我的建议是:测试环境或者小规模集群用 Flannel,省心;生产环境用 Calico,功能全。下面以 Flannel 为例:

kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

如果网络受限,可以先把 yaml 文件下载下来再 apply。安装完成后等一两分钟,再查看节点状态:

kubectl get nodes kubectl get pods -n kube-flannel

节点变成 Ready 就说明网络插件生效了。

5.3 工作节点加入与状态验证

在工作节点上执行之前保存的 join 命令,格式大概是:

kubeadm join k8s-master:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx

如果 token 过期了,在 master 节点重新生成一个。加入完成后,在 master 上查看节点列表,应该能看到新节点,状态先是 NotReady,等一会变成 Ready。

验证集群健康状态可以用几个命令:

# 查看所有节点 kubectl get nodes -o wide # 查看所有 Pod kubectl get pods --all-namespaces # 查看集群信息 kubectl cluster-info # 查看组件状态 kubectl get componentstatuses

如果某个节点一直 NotReady,先用kubectl describe node <节点名>看事件,再到该节点上用journalctl -u kubelet -f看 kubelet 日志。常见原因包括网络插件没装好、容器运行时没启动、证书过期等。

6. 部署后必做的几项验证与常见故障排查

6.1 用测试 Pod 验证跨节点通信

节点 Ready 不代表网络就通了。我习惯部署一个测试用的 Deployment,副本数设为节点数,看看 Pod 能不能分散到不同节点并且互相通信。

kubectl create deployment test-net --image=nginx --replicas=3 kubectl get pods -o wide

等 Pod 都 Running 后,进入其中一个 Pod,去 ping 另外两个 Pod 的 IP。如果 ping 不通,说明跨节点网络有问题,大概率是网络插件配置或者防火墙规则的问题。

还可以测试 Service 的访问:

kubectl expose deployment test-net --port=80 --type=ClusterIP kubectl get svc # 在 Pod 内 curl Service 的 ClusterIP

6.2 证书过期与 kubelet 反复重启的处理

Kubernetes 的证书默认有效期是一年。如果你部署完集群后放了几个月没用,再启动时可能会遇到证书过期的问题。kubeadm 提供了证书续期命令:

kubeadm certs check-expiration kubeadm certs renew all

续期后需要重启控制平面组件,也就是重启 kubelet 或者直接重启机器。

kubelet 反复重启是另一个常见问题。先用systemctl status kubelet看状态,再用journalctl -u kubelet -n 100看最近日志。常见原因有:swap 没关、cgroup 驱动不匹配、容器运行时 socket 路径不对、配置文件缺失等。我遇到最多的是 cgroup 驱动问题,containerd 配置里的SystemdCgroup没改成 true,导致 kubelet 和 containerd 用的 cgroup 驱动不一致。

6.3 镜像拉取失败与 DNS 解析异常的排查

Pod 一直处于 ImagePullBackOff 状态,说明镜像拉不下来。先用kubectl describe pod看事件,确认是网络问题还是镜像名写错了。如果是网络问题,可以尝试在节点上手动拉取镜像,确认节点能否访问镜像仓库。

DNS 解析异常表现为 Pod 内无法解析 Service 名称。先检查 CoreDNS 的 Pod 是否正常运行:

kubectl get pods -n kube-system -l k8s-app=kube-dns

如果 CoreDNS 正常但解析失败,检查 Pod 的/etc/resolv.conf内容,以及 kubelet 的--resolv-conf参数指向的文件是否正确。CentOS 8 上 systemd-resolved 可能会和 kubelet 的 DNS 配置冲突,需要确认/etc/resolv.conf没有被 systemd-resolved 接管。

7. 我在多次部署中攒下的几条实战经验

第一,先规划再动手。IP 地址、主机名、Pod 网段、Service 网段这些一旦定了,后期修改成本极高。我见过有人部署完才发现 Pod 网段和公司内网冲突,只能推倒重来。

第二,版本组合要验证。Kubernetes 版本、容器运行时版本、网络插件版本、操作系统内核版本,这四个之间的兼容性一定要提前确认。官方文档的兼容性矩阵要认真看,不要凭感觉选最新版。

第三,日志是第一手资料。出问题时不要瞎猜,先看日志。kubelet 的日志、containerd 的日志、网络插件的日志,大部分问题都能从日志里找到线索。kubectl describe和kubectl logs是最常用的两个排查命令。

第四,做好节点隔离。生产环境不要让 Master 节点跑业务 Pod,通过 taint 把 Master 标记为不可调度。测试环境为了省资源可以去掉 taint,但心里要清楚这是测试环境。

# 生产环境去掉 Master 的调度 kubectl taint nodes k8s-master node-role.kubernetes.io/control-plane:NoSchedule

第五,备份 etcd。etcd 存着整个集群的状态,它挂了集群就没了。定期备份 etcd 数据,并且要实际演练过恢复流程,不然真出事时手忙脚乱。

# etcd 备份示例 ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \ --endpoints=https://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

这套流程走下来,一个可用的 CentOS 8 Kubernetes 集群就成型了。后续的 Ingress 控制器、存储插件、监控组件、日志收集这些,都是在这个基础之上叠加的。基础打牢了,上面加什么都不会太费劲。

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

用etcd-operator在Kubernetes中管理高可用etcd集群的实践

这段时间在给某个基础服务团队搭独立的高可用 etcd&#xff0c;先说结论&#xff1a;如果还在手工初始化 etcd 三节点&#xff0c;再用一堆脚本去扩容和备份&#xff0c;在 Kubernetes 里真的有点浪费调度能力。我最后用的是 etcd-operator 这套方案&#xff0c;把 etcd 集群当…

作者头像 李华
网站建设 2026/10/14 15:44:22

python的机器人基础原理工业场景模拟第二十一篇:点位搬运任务,采用三次多项式完成关节空间插值,生成关节角度随时间变化序列。

《Python机器人基础原理》第二十一篇&#xff1a;机械臂仿真——点位搬运任务&#xff0c;采用三次多项式完成关节空间插值&#xff0c;生成关节角度随时间变化序列1. 实际工业应用场景周五上午&#xff0c;某3C电子装配车间的上下料工位。一台3-DOF垂直关节机械臂&#xff08;…

作者头像 李华
网站建设 2026/10/14 15:44:17

8700客户端操作文档:从环境基线到业务闭环的交付链路解析

简介&#xff1a;这份资源是海康威视iVMS-8700客户端的操作说明文档&#xff0c;面向智能楼宇安防运维人员、视频监控系统集成与实施工程师&#xff0c;以及需要快速上手该平台的初、中级操作者。内容围绕iVMS-8700基于SOA架构的模块化设计展开&#xff0c;重点讲解电视墙操作平…

作者头像 李华
网站建设 2026/10/14 15:44:02

Oracle生产实战避坑指南:建表规范、DML安全与查询性能三原则

1. 这不是教科书&#xff0c;是我在产线踩了三年坑后整理的Oracle实操手记“Oracle基本用法全教程&#xff08;一&#xff09;”——看到这个标题&#xff0c;你可能下意识想点开又划走&#xff1a;又是那种从CREATE TABLE开始、讲完SELECT就收工的“基础入门”&#xff1f;我懂…

作者头像 李华