当前位置: 首页 > news >正文

containerd 下 cgroupns - 小镇

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 级)

这些才是“真正不会再混淆”的底层。