登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux namespace 与 cgroup 的隔离职责对比

来源:17golang原创

时间:2026-11-01 10:14:13 296浏览 收藏

在容器里看到“隔离”这个词时,先把问题拆成两类:是要让进程看不到宿主的某类资源,还是要限制它能消耗多少资源?前者主要由 Linux namespace 处理,后者主要由 cgroup 处理。两者经常同时配置,但职责不能互换。

namespace 改变进程看到的资源视图,cgroup 管理进程所属的层级并限制、统计资源;cgroup namespace 只进一步虚拟化 cgroup 路径视图,不等于 CPU 或内存限额。

下面用 cgroup v2 的接口名称做对照。示例命令只用于说明检查入口,具体挂载方式仍取决于发行版和服务管理器。

先看两者解决什么问题

namespace 的核心是“同一类全局资源,在不同 namespace 中呈现不同视图”。例如 PID namespace 影响进程看到的进程号层级,NET namespace 隔离网络设备、协议栈和端口,MNT namespace 隔离挂载点,UTS namespace 影响主机名视图。它解决的是可见性和命名空间边界。

cgroup 的核心是“把进程放进一棵层级树,再由 controller 管理资源分配”。CPU、memory、pids 等控制器可以对层级中的进程做限制或统计;父级约束会沿子树生效,子级不能把父级的资源约束抬高。

namespace 视图边界与 cgroup 资源边界的静态关系说明图
图1:职责结构说明图,左侧是进程可见的资源视图,右侧是进程所属的资源控制层级。

支持范围:namespace 隔离哪些视图

需要隔离系统视图时,先选择具体 namespace 类型,而不是笼统地说“开 namespace”。常见对应关系如下:

类型主要隔离对象适合回答的问题
PID进程 ID 视图容器内能看到哪些进程
NET网络设备、协议栈、端口进程使用哪套网络栈
MNT挂载点进程看到哪棵文件系统树
USER用户与组 ID 映射容器内身份如何映射到宿主
CGROUPcgroup 根目录视图进程看到的 cgroup 路径从哪里开始

检查某个进程属于哪些 namespace,可以读取 /proc/PID/ns/ 下的链接。下面命令只列出名称和目标,重点是观察 namespace 类型,而不是把输出当作资源限额结果。

# 查看当前 shell 的 namespace 句柄,比较不同进程的链接目标
ls -l /proc/$$/ns

# 只查看 PID、网络和挂载视图,便于做职责对照
readlink /proc/$$/ns/pid /proc/$$/ns/net /proc/$$/ns/mnt

最小示例:从 /proc 和 cgroup 文件读取边界

cgroup v2 把控制器放在统一层级中。cgroup.controllers 表示当前层级可用的控制器,cgroup.subtree_control 表示父级为子层级启用的控制器,cgroup.procs 用来查看或迁移进程。真正的资源限制通常写入对应控制器文件,例如内存控制器的配置文件。

这意味着 cgroup 与 namespace 的检查入口也不同:namespace 先看 /proc/PID/ns 的视图句柄,cgroup 先看 /proc/PID/cgroup 的成员路径和 cgroup 目录里的控制器文件。不要因为进程看不到宿主路径,就推断它已经获得了 CPU 或内存上限。

# 查看进程当前的 cgroup v2 成员路径;0:: 通常表示统一层级
cat /proc/$$/cgroup

# 在已挂载的 cgroup v2 目录中查看可用控制器和子树控制器
cat /sys/fs/cgroup/cgroup.controllers
cat /sys/fs/cgroup/cgroup.subtree_control

# 查看该层级直接管理的进程,避免把 namespace 视图当成资源统计
cat /sys/fs/cgroup/cgroup.procs

上面的路径是常见的 cgroup v2 检查入口,不代表每台机器都把统一层级挂在同一目录。生产环境应先确认实际挂载点,并由现有的 systemd 或容器运行时管理层级,避免手工配置与服务管理器互相覆盖。

兼容处理:容器里两者怎样协同

一个容器通常同时需要两种边界:用 PID、NET、MNT、USER 等 namespace 组织“容器内看到的世界”,再把容器进程放进宿主 cgroup 树的某个子树,用 controller 做资源治理。cgroup namespace 让容器内看到的 cgroup 根目录从自己的层级开始,减少宿主祖先路径泄露,但它不创建独立的资源池。

容器进程、namespace、cgroup v2 子树与宿主父级的静态协同关系图
图2:容器协同结构图,说明可见性边界、资源治理边界与委派边界如何叠加。

因此排查顺序可以保持很短:

  1. 进程列表、端口或挂载点不符合预期,先检查对应的 PID、NET 或 MNT namespace。
  2. CPU、内存、进程数表现异常,检查进程的 cgroup 路径、控制器可用性和具体限制文件。
  3. /proc/PID/cgroup 中出现相对路径或 .. 时,结合 cgroup namespace 和挂载视图判断可见性,不要直接当作越权证据。

资源与安全注意:迁移时别把两种机制混用

把旧的容器配置迁到 cgroup v2 或新的运行时前,建议逐项确认:

  • 隐藏系统视图的需求归到 namespace,CPU、内存、I/O、进程数限制归到 cgroup controller。
  • 不要把 cgroup namespace 当作资源限制;它解决的是路径和根目录视图,资源限制仍由 cgroup 层级和控制器完成。
  • 检查父级是否已经启用对应 controller;cgroup v2 的控制器分配受自上而下的层级约束。
  • 保留 /proc/PID/ns、/proc/PID/cgroup、cgroup.controllers 和 cgroup.procs 作为回归检查点。

一句话记忆:namespace 决定“看见哪套系统资源”,cgroup 决定“在这棵资源树上能分到多少”。容器的隔离效果来自两者叠加,而不是其中任意一个单独完成。

相关问题

namespace 能限制内存使用吗?

不能。namespace 主要提供资源视图隔离;内存上限和统计应检查 cgroup 的 memory controller。

cgroup namespace 会创建新的 cgroup 树吗?

它虚拟化进程看到的 cgroup 根目录和路径,实际资源层级仍受宿主 cgroup 层级与控制器约束。

为什么进程在容器里看到的 PID 与宿主不同?

通常是 PID namespace 提供了不同的进程号视图;这和进程是否被放进某个 cgroup 是两个独立判断。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>