浅谈Kubernetes在systemd cgroup模式下的Slice/Scope组织结构

在 Kubernetes 生产环境中,容器资源隔离是否可靠 ,并不取决于我们写了多少 resources.limits,而取决于:

kubelet、container runtime(containerd / runc)和 systemd 是否使用了同一套 cgroup 管理体系

本文通过实际运行的 K8S 节点,结合 systemd-cgls实际输出,从工程角度讲解:

  • systemd 下的 slice / scope 是什么
  • Kubernetes 的 Pod / QoS / Container 是如何映射到 cgroup 的
  • 每一层 是谁创建的、管什么资源
  • 以及 如何在机器上验证集群是否处在"正确状态"

一、背景:为什么要关心 systemd cgroup?

在现代 Linux 发行版(Ubuntu / RHEL / 麒麟 / 欧拉等)中:

  • systemd 是默认的进程管理器
  • cgroup(尤其是 cgroup v2)通常由 systemd 统一管理

Kubernetes 在这些系统上,如果配置正确,会形成一棵结构清晰、可观测且可预测的 cgroup 树,其中:

  • kubelet 负责 声明资源模型
  • containerd / runc 负责 创建容器进程
  • systemd 负责 真正落地 cgroup 层级

如果这三者 cgroup 管理方式不一致,则会出现:

  • Pod 启动失败
  • CPU / 内存 的 requests / limits 不生效
  • OOM 行为异常
  • 资源统计混乱

二、slice / scope 到底是什么?

在 systemd 的世界里,所有进程都被放进 cgroup,其中有两种核心cgroup单元:

(1)Slice(.slice

  • 本质是 cgroup目录
  • 用于分组
  • 资源限制可以向下继承

例如:

  • kubepods.slice
  • kubepods-burstable.slice

可以理解为:"一组进程的父目录"


(2)Scope(.scope

  • 用于承载一个具体的进程树
  • 生命周期通常由外部程序(如runc)触发

例如:

  • cri-containerd-xxx.scope

可以理解为:"某一个容器实例"

slice = 分组(目录)scope = 具体对象(容器 / 进程)


三、Kubernetes 在 systemd 下的标准 cgroup 树结构

当满足以下条件时:

  • kubelet 使用 --cgroup-driver=systemd
  • containerd / runc 设置 SystemdCgroup = true

Kubernetes 会在 systemd 中形成如下结构:

text 复制代码
systemd
  └── kubepods.slice
        ├── kubepods-burstable.slice
        │     └── kubepods-burstable-pod<uid>.slice
        │           └── cri-containerd-<cid>.scope
        │                 └── container process
        ├── kubepods-besteffort.slice
        │     └── ...
        └── kubepods-pod<uid>.slice   (Guaranteed Pod)

四、systemd-cgls 输出解析

systemd-cgls 是 Linux 系统中用于以树状结构显示 systemd 控制组(cgroups)层级 的命令行工具。它帮助用户直观地查看当前系统中由 systemd 管理的 cgroup 层级结构,包括服务、用户会话、容器等资源分组情况。

当在K8S节点上执行:

bash 复制代码
systemd-cgls

得到(节选):

text 复制代码
kubepods.slice
├─kubepods-podxxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx.slice
│ └─cri-containerd-xxxxxxxxxxx....scope
│   ├─362594 ./bin/xxxxservice_daemon
│   ├─663693 xxx_backend
│   └─664542 xxx_backend
├─kubepods-burstable.slice
│ └─kubepods-burstable-podxxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx.slice
│   └─cri-containerd-xxxxxxxxxx....scope
│     └─xxx_backend
└─kubepods-besteffort.slice
  └─kubepods-besteffort-podxxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx.slice
    └─cri-containerd-xxxxxxxxxx....scope
      └─node_exporter

关键点

  • 一 Pod 一个 slice
  • 一容器一个 scope
  • QoS(Guaranteed / Burstable / BestEffort)体现在 slice 层级

五、逐层拆解:每一层是谁创建的?管什么?

(1)kubepods.slice ------ Kubernetes 的 cgroup 总入口

  • 创建者:kubelet(通过 systemd D-Bus 接口)

  • 含义

    "这个节点上,所有 Kubernetes Pod 的 cgroup,都必须在这里"

  • 作用

    • 统一统计节点 Pod 资源
    • systemd 层面的集中管理

一般不建议在这一层施加资源限制。


(2)kubepods-burstable / besteffort.slice ------ QoS 分组层

Kubernetes 会根据 Pod 的资源配置自动分类:

QoS 判定条件
Guaranteed requests == limits(CPU/内存)
Burstable requests < limits
BestEffort 没有 requests / limits

对应的 systemd 分组:

  • kubepods-guaranteed.slice(有些版本直接显示在根下)
  • kubepods-burstable.slice
  • kubepods-besteffort.slice

这一步是 K8S QoS 策略真正落地的地方,OOM 优先级、资源竞争顺序,都与此有关。


(3)kubepods-pod<uid>.slice ------ 单个 Pod 的 cgroup

  • 一 Pod 一 slice
  • <uid> 是 Pod UID(systemd 中 - 被转义成 _
  • 这是 Pod 级资源控制的核心层

作用包括:

  • Pod 级 CPU / memory 限制
  • Pod 级资源统计
  • Pod 内多个容器的"共同父 cgroup"

Pod 本质是一组容器,所以必须有这一层。


(4)cri-containerd-xxx.scope ------ 单个容器实例

  • 创建者:containerd / runc(通过 systemd)
  • 一容器一 scope
  • scope 里包含:
    • 容器主进程
    • 容器内 fork 出来的所有子进程

例如,服务容器中:

text 复制代码
cri-containerd-xxx.scope
├─xxxservice_daemon
├─xxx_backend
├─xxx_backend

多进程并不意味着多个容器,而是同一容器内的进程树。


六、Guaranteed Pod 的验证

在 systemd 中,这个 Pod 直接挂在 kubepods.slice 下:

text 复制代码
kubepods-podxxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx.slice

我们进一步通过 Kubernetes API 验证:

bash 复制代码
kubectl get pod -A \
  -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,UID:.metadata.uid,QOS:.status.qosClass \
  --no-headers \
| grep xxxxxxxx(注:对应pod编号的前八位)

输出:

text 复制代码
xxx-inference  xxx-deployment-...  xxxxxxxx(注:对应pod编号的前八位)-...  Guaranteed

说明:这是一个 Guaranteed Pod ,同时也解释了为什么它不在 burstable / besteffort 分组下。


七、如何在任何节点上验证集群是否"健康"

1️⃣ 查看 cgroup 树是否是 slice / scope 结构

bash 复制代码
systemd-cgls | grep kubepods -n

2️⃣ 确认 runtime 是否启用 systemd cgroup

bash 复制代码
containerd config dump | grep SystemdCgroup

应为:

text 复制代码
SystemdCgroup = true

3️⃣ 确认 kubelet 使用 systemd

bash 复制代码
ps -ef | grep kubelet

我们会看到类似:

bash 复制代码
/usr/bin/kubelet \
  --config=/var/lib/kubelet/config.yaml

然后,

bash 复制代码
cat /var/lib/kubelet/config.yaml | grep -i cgroup

看到 cgroupDriver: systemd


八、结论

Kubernetes 的资源模型从根本上讲是 systemd + cgroup 真正跑出来的

如果我们在 systemd-cgls 中看到:

  • 清晰的 kubepods.slice
  • QoS 分组 slice
  • Pod slice
  • Container scope

那么我们可以确定:

✅ 资源隔离可信

✅ QoS 生效

✅ OOM / throttling 行为可预期

相关推荐
王九思2 小时前
Podman 介绍
docker·云原生·kubernetes·podman
Serverless社区3 小时前
进阶指南:BrowserUse + Agentrun Sandbox 最佳实践指南
运维·阿里云·云原生·serverless·函数计算
运维螺丝钉5 小时前
docker安装应用
运维·docker·容器
optimistic_chen5 小时前
【Docker入门】cgroups 资源控制
linux·运维·ubuntu·docker·容器·cgroup
芥子沫6 小时前
书签管理工具使用:Readeck-Docker部署和使用技巧
运维·docker·容器·书签管理
ba_pi6 小时前
每天写点什么2026-01-19-docker如何使用GPU
运维·docker·容器
Gold Steps.7 小时前
K8S基于 Argo Rollouts 的高级版本发布实践
云原生·容器·kubernetes
七七powerful7 小时前
docker 部署dirsearch并进行目录遍历扫描
运维·docker·容器
王九思7 小时前
Docker访问权限问题
docker·云原生·容器