openEuler上部署Rancher 2.9:cgroupv2与iptables实战指南
2026/9/16 14:25:03 网站建设 项目流程

1. 项目背景与问题全景

1.1 环境构成与关键版本

先说我这边的实际环境,这样下面的步骤你才好对照。我用的操作系统是 openEuler 24.03 SP4,内核版本 6.6.x,设备是一台 4 核 16G 内存的物理服务器,磁盘留了 200G 给系统分区。Rancher 版本是 2.9.x,容器运行时底层是 containerd 1.7.x,兼容 Docker 镜像。集群形态是"单节点全角色",也就是同一个节点同时承担 etcd、controlplane、worker 三种角色,适合验证环境和小规模生产。

OpenEuler 24.03 SP4 作为国产化场景里很常见的发行版,基础包管理用的是 dnf,默认防火墙是 firewalld,安全模块也比较完整。单看这些配置本身不复杂,但真正部署 Rancher 的时候,问题全集中在两个底层细节上:cgroupv2 和 iptables。尤其是 cgroupv2,内核默认开启了 v2,而容器运行时、Kubelet、kube-proxy 这些组件对 cgroup 驱动的要求各不相同。驱动一旦不一致,节点要么直接注册不上,要么注册上之后状态反复漂移。

1.2 两个"看不见"的底层机制

先把概念说清楚,后面的排查才有方向。

cgroupv2 是内核把进程资源控制的接口升级成了统一版本,最大的变化是所有 controller 统一挂在/sys/fs/cgroup下,并且只支持进程粒度。Kubernetes 场景里,容器运行时和 Kubelet 都需要指定 cgroup 驱动,通常只有两个选项:cgroupfs 和 systemd。如果系统采用了 systemd 作为 init 进程,那么推荐驱动就是 systemd,否则可能出现资源统计异常,甚至 kubelet 直接拒绝启动。openEuler 主流的部署方式肯定是用 systemd,所以这里绝大多数问题都出在"运行时还在用 cgroupfs,Kubelet 却想用 systemd"这种错位状态。

iptables 的问题更隐蔽。openEuler 24.03 SP4 默认的防火墙体系已经逐渐转向 nftables 后端,但 Kubernetes 的 kube-proxy 在 iptables 模式下操作的仍然是老的natfilter表。如果系统里没有完整加载 iptables 相关内核模块,或者/usr/sbin/iptables实际只是 nft 的兼容命令,那么给 Service 创建映射规则时会静默失败:规则看着没报错,但流量就是不通。

2. 部署前必须搞懂的两个底层机制

2.1 cgroupv2 对容器运行时的硬性要求

我在安装过程中第一次看到kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"的时候,第一反应是检查 Docker 配置。因为 Rancher 2.9 在单机场景下仍然可以基于 Docker 启动 Server,而节点侧的容器运行时如果用的是 Docker,那 docker 的exec-opts就必须加上native.cgroupdriver=systemd

具体修改方式是在/etc/docker/daemon.json里追加:

{ "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }, "storage-driver": "overlay2", "iptables": true, "ip-masq": false }

改完之后依次重启 Docker 和所有相关容器,再检查:

docker info --format '{{.CgroupDriver}}'

输出必须是systemd。如果输出还是 cgroupfs,说明 daemon.json 没生效,或者 Docker 版本太老不支持这个字段。

如果不用 Docker Runtime,而是像 RKE2 那样直接用 containerd,那么需要检查/etc/rancher/rke2/config.yaml。RKE2 默认会给 Kubelet 传递 systemd 驱动,但如果你自己装了 containerd,再让 Rancher 的 agent 容器去调用,就要确认 containerd 的/etc/containerd/config.tomlSystemdCgroup是否打开。推荐的配置是:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true

这里有个容易忽略的细节:即使 containerd 配了 SystemdCgroup,底层仍然需要 cgroupv2 的 mount 存在。你可以用mount | grep cgroup检查,如果发现只有 cgroup 没有 cgroup2,那就要确认内核启动参数是否把 v2 禁用掉了。openEuler 24.03 默认启用了 cgroupv2,正常不需要额外操作,但如果你做过内核参数调整,还是看一眼稳妥。

2.2 iptables 与 nftables 的关系,Kube-proxy 为什么容易踩坑

openEuler 24.03 SP4 默认加载的是 nftables 框架,但 Kubernetes 的 kube-proxy 服务依赖仍然沿用老一套 iptables 规则。换句话说,操作系统本身没有"iptables"这个内核组件,它提供的是兼容层;兼容层主要做的是把 iptables 语法的规则翻译成 nftables 规则。理论上是可行的,但兼容性总是会晚一步。

我在实际操作中发现,如果 Rancher Server 容器通过 Docker 方式启动,Docker 会自动创建一堆DOCKERBRIDGE链。此时再打开 kube-proxy,它会尝试在nat表里追加 KUBE-SERVICE 链。一旦系统检测不到标准 iptables 模块,或者xtables-nftxtables-legacy的选择不对,规则会注入到错误的后端,表现出来就是 kube-proxy 日志没有报错,但 Service 的 ClusterIP 始终 ping 不通。

确认当前系统实际使用的 iptables 后端,可以用这个命令:

iptables --version

如果输出里带(nf_tables),说明现在是 nft 兼容后端。如果输出带(legacy),就是老的 iptables 后端。两种后端可以并存,但同一时刻只有一种能生效。想让 Kubernetes 稳定工作,建议统一使用 legacy 后端。可以通过 update-alternatives 切换:

update-alternatives --set iptables /usr/sbin/iptables-legacy

切换后立刻验证:

iptables -t nat -L -n ip6tables -t nat -L -n

如果能正常列出链列表,那 kube-proxy 大概率能正常工作了。这一步看起来简单,但我当时的系统里根本没有iptables-legacy这个文件,最后是靠dnf install iptables-legacy -y装上的。

3. 安装 Rancher 并创建集群的核心步骤

3.1 单容器方式启动 Rancher Server

我用的是 Rancher 官方给的快速启动方式,直接把 Server 跑在 Docker 里。前提是 Docker 已经装好并且 cgroup 驱动改成了 systemd。启动命令:

docker run -d --name rancher-server \ --restart=unless-stopped \ -p 80:80 -p 443:443 \ --privileged \ rancher/rancher:v2.9.4

加上--privileged是因为 Rancher Server 容器内部需要操作 iptables 规则来管理端口和代理,普通容器权限不够。启动后等待一两分钟,用docker logs -f rancher-server观察日志,看到Listening on :443之后就说明 Server 起来了。

这里有个地方我踩过坑:如果你系统防火墙没关,80 和 443 端口不一定通。所以启动容器之前,先明确自己的策略。我这边是测试环境,直接把 firewalld 关了:

systemctl stop firewalld systemctl disable firewalld

生产环境不建议这样操作,后面我会单独讲怎么按最小端口放行。

3.2 把节点加入集群时的 cgroup 驱动匹配设置

Rancher Server 起来之后,通过https://<服务器IP>/访问 Web 界面。首次登录会让你设置 admin 密码,然后添加集群。如果选择全新集群并自定义节点,Rancher 会生成一段注册命令,类似:

curl --insecure -fL https://<服务器IP>/system-agent-install.sh | sudo sh -s - \ --server https://<服务器IP> \ --label 'cattle.io/os=linux' \ --etcd --controlplane --worker

在单节点环境里,这条命令执行完,Rancher 的 agent 会自动部署 kubelet、containerd 和网络插件。但如果你没做前面的 cgroup 驱动对齐,执行完这条命令后,Web 界面上节点状态会卡在 Waiting,一分钟后大概率看到标题里那个经典错误:kubelet stopped posting node status。

原因是 kubelet 启动后会向 API Server 注册节点,但如果它自身的 cgroup 驱动和运行时不一致,它根本无法通过健康检查,自然也就不会主动上报状态。解决办法就是回到第 2.1 节,把运行时的 cgroup driver 改成 systemd,然后重启节点侧相关服务。如果不确定是哪个组件报错,直接在节点上:

journalctl -u kubelet -f journalctl -u containerd -f

日志里往往直接给出cgroup driver相关的关键字。

3.3 手动补 iptables 链的兜底方案

在我的环境里,即便 cgroup 驱动对齐了,kube-proxy 运行一段时间后还是会出现 Service 无法访问的情况。我最后排查到FORWARD链默认策略是 DROP。只要是双网卡或开启了转发,Docker 和 Kubernetes 的流量都依赖 FORWARD 链,默认 DROP 会导致东西向流量被静默丢弃。

临时处理方式很简单:

iptables -P FORWARD ACCEPT

但重启后就失效了。为了持久化,我安装了 iptables-services:

dnf install -y iptables-services systemctl enable iptables systemctl start iptables

此时/etc/sysconfig/iptables文件会被生成,你可以把 FORWARD 链的策略改成 ACCEPT 并保存:

iptables-save > /etc/sysconfig/iptables

再确认 kube-proxy 的核心链都存在:

iptables -t nat -L KUBE-SERVICES -n iptables -t nat -L KUBE-NODEPORTS -n

如果这两个链不存在,一般是 kube-proxy 没启动或者启动失败。检查 kube-proxy 的 Pod:

kubectl get pods -n kube-system -o wide | grep kube-proxy kubectl logs -n kube-system <kube-proxy-pod> --tail=100

日志里如果出现Failed to ensure that the pod: cbr0 ... has the correct IP,多半还是网络插件和 iptables 后端不匹配导致的,重新确认一遍 legacy 后端即可。

4. 常见问题与排查实践

4.1 kubelet stopped posting node status 的完整排查路线

这个错误在 Rancher 社区里出现频率很高,尤其是在国产系统上。我这里整理了一个固定的排查顺序,遇到就直接照做。

第一步,确认节点侧核心进程是否存活:

systemctl status kubelet systemctl status containerd systemctl status rke2-server

第二步,看日志中的关键字,常见的有cgroup driverfailed to get container infonode not found等。如果 cgroup 驱动不匹配,日志会直接写明。确认后修改 daemon.json 或 containerd 配置。

第三步,检查 Rancher agent 容器日志:

docker logs --tail 100 <rancher-agent容器名>

第四步,检查节点上的 CRI 命令能不能正常列出容器:

crictl ps

如果 crictl 报连接不上,说明 containerd 的 socket 路径配置不对。openEuler 下 containerd 默认 socket 在/run/containerd/containerd.sock,但 RKE2 的 socket 在/run/k3s/containerd/containerd.sock,两者不能混用。

把上面四步走完,大部分 kubelet 失联问题都能定位到根因,剩下的就是改配置重启的事。

4.2 iptables 规则不生效、服务无法访问的检查清单

规则看起来在,但访问还是不通,这种情况最容易让人崩溃。我遇到过的几种根因如下。

第一种,规则注入到了 nft 后端,真正给网络路径用的还是 legacy 后端。表现是iptables -L能看到规则,但 ping ClusterIP 不通,访问 NodePort 也不通。解决办法就是统一后端,切到 legacy。

第二种,br_netfilter内核模块没加载。Kubernetes 的 Service 流量经过 bridge 设备时,需要bridge-nf-call-iptables开启,否则桥接流量不受 iptables 规则控制。检查命令:

cat /proc/sys/net/bridge/bridge-nf-call-iptables

如果返回 0,加载模块并启用:

modprobe br_netfilter sysctl -w net.bridge.bridge-nf-call-iptables=1

第三种,ip_forward没有开启。K8s 的 Pod 之间以及 Service 流量都依赖内核转发,没开启的话 Pod 能启动但互访不了。检查:

sysctl net.ipv4.ip_forward

建议在/etc/sysctl.d/99-kubernetes.conf里写好:

net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1

执行sysctl --system生效。

4.3 组件状态速查表

我把这次部署涉及的组件状态整理成一张速查表,方便你和以后排查时对照。

组件关键命令异常表现常见处理
Dockerdocker infoCgroupDriver 不是 systemd修改 /etc/docker/daemon.json
containerdcrictl ps无法连接 socket检查 socket 路径是否匹配
kubeletsystemctl status kubeletcgroup driver 不匹配对齐运行时驱动后重启
kube-proxykubectl logs -n kube-system无法创建 KUBE-SERVICE 链切换 iptables 到 legacy
Rancher agentdocker logs rancher-agent无法连接 Server检查 443 端口与证书
firewalldsystemctl status firewalld端口不通放行常用端口或临时关闭

4.4 顺带说下 Rancher Desktop 与 npipe 报错的区分

有朋友在 Windows 上安装 Rancher Desktop 时,报了failed to connect to the docker api at npipe:////./pipe/docker_engine这个错。这个和 openEuler 部署 Rancher Server 完全是两件事。Rancher Desktop 是本地开发工具,通过 Windows 命名管道连接 Docker 引擎。报错原因通常是 Docker Desktop 没启动,或者命名管道权限被限制。

解决思路和 Linux 容器平台不冲突:先确认 Windows 侧 Docker 服务状态,再确认当前用户是否在 docker-users 用户组里。如果只是命令行工具想连远程 Rancher Server,不要用 Rancher Desktop,直接用 kubectl 配置 kubeconfig 即可。我也是在折腾过程中意识到,这两类问题名字相近,但处理路径完全不同,所以单独提出来帮大家避个坑。

5. 安全加固与后续运维建议

5.1 恢复防火墙并放行最小端口

前面为了快速部署把 firewalld 关了,但真正用于生产或内网测试时,我建议把防火墙重新打开,只放行必要端口。Rancher Server 本身要开 80 和 443;如果节点要接入集群,还需要开 6443(API Server)、10250(kubelet)、2379 和 2380(etcd),以及 UDP 8472(VXLAN)等。以我单节点全角色为例,最小集合是:

firewall-cmd --permanent --add-port=80/tcp firewall-cmd --permanent --add-port=443/tcp firewall-cmd --permanent --add-port=6443/tcp firewall-cmd --permanent --add-port=10250/tcp firewall-cmd --permanent --add-port=2379/tcp firewall-cmd --permanent --add-port=2380/tcp firewall-cmd --permanent --add-port=8472/udp firewall-cmd --reload

这里有个注意点:防火墙启动之后,iptables 的 FORWARD 链策略可能会随 firewalld 规则重置。如果你之前手动iptables -P FORWARD ACCEPT了,重载防火墙后记得再确认一次,必要时用firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD ACCEPT固定住。

5.2 iptables 安全基线

经历过这次折腾之后,我对 iptables 的认知不只是"K8s 必需组件",它同时也是安全防护的关键位置。等集群跑起来之后,可以针对管理端口做来源限制。比如只允许办公网段访问 Rancher Web 界面:

iptables -A INPUT -p tcp --dport 443 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j DROP

同理,SSH、API Server 这些端口也可以按同样的思路做来源白名单。要注意的是,在 kube-proxy 和 Docker 同时存在的场景下,规则写入顺序很重要,别在INPUT链上直接DROP ALL,否则节点之间 VXLAN 或 Calico 流量会被拦掉。如果你需要更细粒度的策略,建议使用支持 nftables 的防火墙管理工具,而不是层层叠加 iptables 命令,否则规则多了之后维护成本很高。

5.3 监控与日志

Rancher 部署完成后,节点侧的核心服务日志建议集中收集。系统里至少要做三块监控:容器运行时日志(journalctl -u containerd)、Kubernetes 核心组件指标、Rancher Server 容器本身的状态。Rancher UI 自带监控插件,但对资源占用比较大,测试环境可以不装。常用替代方案是 node_exporter 加 Prometheus,跑起来之后重点盯kubelet_volume_metriccontainer_cpu_usage_seconds_total这些指标。

日志方面,至少保证 fluent-bit 或 filebeat 能收集/var/log/containers下的标准输出日志。排错的时候如果所有状态都正常但服务访问异常,第一步永远是去翻组件日志,而不是反复重启服务。这次经历给我最深的感受是:cgroup 和 iptables 问题看起来是环境问题,其实根子在于组件对内核和系统配置的前置假设没有满足。只要在安装前把内核模块、sysctl、cgroup 驱动、iptables 后端这四件事对齐,Rancher 在 OpenEuler 24.03 SP4 上完全可以稳定跑起来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询