containerd 下 cgroupns
先给你一个确定结论(不绕):
在 Kubernetes + kubelet + containerd 架构里,没有一个官方 kubelet 配置可以“全局强制 Pod cgroupns=host”。
cgroupns-mode 是 CRI → runtime(containerd)→ runc → kernel 决定的,而不是 kubelet feature gate 或 Pod 统一开关。
但——可以做到 host 的条件是“runtime + OCI spec + kernel 行为”满足特定路径。
下面按你要求的方式讲清楚:怎么才能让 kubelet + containerd 出现 cgroupns=host(真实可行路径)+ syscall + 对比。
🧠 1️⃣ 关键现实:containerd 下 cgroupns 谁决定?
kubelet↓ (CRI)
containerd↓ (generate OCI spec)
runc↓
kernel (cgroup namespace)
👉 最终决定点:runc(OCI spec)
🧠 2️⃣ cgroupns=host 的真实含义(不是 Kubernetes 概念)
host cgroupns =
容器 NOT 创建 cgroup namespace
→ 直接继承 host cgroup namespace
private cgroupns =
容器创建 new cgroup namespace
→ 只看到 subtree
🧠 3️⃣ containerd 下“能不能 host”的真实条件
✔ 必须同时满足:
条件 A:kernel 支持
CONFIG_CGROUP_NS=y
条件 B:runc OCI spec 不创建 ns
OCI spec 里:
"linux": {"namespaces": [{"type": "cgroup", "path": ""}]
}
👉 或者 完全不写 cgroup namespace
条件 C:containerd 不强制 override
containerd v1.6+ 默认:
cgroupns = private(默认)
🧠 4️⃣ kubelet / containerd 如何影响 cgroupns
kubelet ❌ 不控制
--cgroupns-mode ❌ 不存在
featureGate ❌ 不存在
containerd(关键控制点)
config.toml:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]SystemdCgroup = true
⚠️ 这个不是 cgroupns,是 cgroup driver
真正相关配置(containerd)
[plugins."io.containerd.grpc.v1.cri"]disable_cgroup = false
👉 但 仍然没有 cgroupns=host 开关
🧠 5️⃣ 想要 host cgroupns 的唯一“可行路径”
✔ 方法1:使用 runc OCI hook 强制 host ns
(containerd 支持 OCI hooks)
"hooks": {"prestart": [{"path": "/usr/local/bin/set-host-cgroupns"}]
}
hook 内 syscall:
setns(open("/proc/1/ns/cgroup"))
✔ 方法2(唯一稳定方法):让 runc 不创建 namespace
OCI spec:
"linux": {"namespaces": [{"type": "pid"},{"type": "net"},{"type": "mount"}// ❌ 不写 cgroup]
}
✔ 方法3(最现实):让 containerd 不创建 cgroup ns(patch)
containerd 默认逻辑:
if LinuxCgroupNamespace enabled → private
关闭路径(源码级):
opts.WithLinuxNamespace(types.LinuxNamespace{Type: "cgroup",
})
👉 改掉这一段 = host
🧠 6️⃣ syscall 级对比(最关键)
🟢 host cgroupns
clone()
(no CLONE_NEWCGROUP)
👉 kernel:
进程加入 host cgroup namespace
🔵 private cgroupns
clone(CLONE_NEWCGROUP)
👉 kernel:
创建 new cgroup namespace
只挂载 subtree
🧠 7️⃣ 现象级对比(你最关心)
🟢 host
容器内:/sys/fs/cgroup/├── system.slice├── kubepods.slice├── user.slice
👉 能看到:
✔ 所有 Pod
✔ systemd service
✔ node level cgroup
🔵 private(containerd默认)
/sys/fs/cgroup/└── kubepods/podxxx/
👉 只能看到:
✔ 当前 Pod
❌ system.slice
❌ 其他 Pod
🧠 8️⃣ kubelet + containerd 结论(重要)
| 层级 | 是否控制 cgroupns |
|---|---|
| kubelet | ❌ 不控制 |
| containerd | ⚠️ 默认 private |
| runc | ✔ 最终决定 |
| kernel | ✔ 执行 |
🚨 9️⃣ 最关键事实(避免误区)
❗ Kubernetes 没有“让 Pod cgroupns=host”的官方 API
❗ containerd 也没有稳定配置项
❗ 真正控制点是 OCI spec(runc)
🧠 🔟 一句话总结
kubelet + containerd 想实现 cgroupns=host,本质不是“配置问题”,而是“OCI namespace 是否包含 CLONE_NEWCGROUP 的问题”。
🚀 如果你要继续深入(建议)
我可以下一步帮你拆:
👉 runc 内部 clone/unshare 真实源码路径(libcontainer)
👉 containerd 如何生成 OCI spec(默认为什么是 private)
👉 Linux kernel cgroup namespace attach 的真实行为(task_struct 级)
这些才是“真正不会再混淆”的底层。
