土法炼钢兴趣小组的算法知识备份

【操作系统百科】namespace:容器的内核根基

文章导航

分类入口
os
标签入口
#namespace#user-ns#pid-ns#mount-ns#net-ns#rootless#container

目录

docker run 背后的内核机制就两项:namespace(视图隔离)和 cgroup(资源限制)。本文专讲 namespace——如何把全局内核资源切成多份、让一群进程”活在自己的宇宙”里。

一、总览

flowchart TB
    T[task_struct]-->N[nsproxy]
    N-->MNT[mnt_namespace<br/>挂载视图]
    N-->PID[pid_namespace<br/>PID 空间]
    N-->NET[net_namespace<br/>网络栈]
    N-->IPC[ipc_namespace<br/>SysV/POSIX/mq]
    N-->UTS[uts_namespace<br/>hostname/domain]
    N-->TIME[time_namespace<br/>CLOCK_MONOTONIC 偏移]
    N-->CG[cgroup_namespace<br/>cgroup 视图]
    T-->U[user_namespace<br/>uid/gid 映射 + capabilities]
    classDef k fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    classDef u fill:#f0883e22,stroke:#f0883e,color:#adbac7;
    class T,N,MNT,PID,NET,IPC,UTS,TIME,CG k
    class U u

注意:user namespace 不在 nsproxy 里,挂在 task 直接引用。它是最特别的一种——是其他 ns 的”权限根”。

二、七种 namespace 逐一看

2.1 mount namespace(MNT)

每个 mnt ns 有独立的挂载表。namespace 内的 mount/umount 不影响外部。

mount propagationprivatesharedslaveunbindable。容器运行时用 slave 继承宿主机的 /proc/sys,但自己的 mount 不传回宿主。

pivot_root vs chroot:容器一般用 pivot_root 切根——比 chroot 安全(不能”退出”),且需要 mount ns 支持。

2.2 pid namespace(PID)

pid ns 内部的进程看到的 PID 从 1 开始。

2.3 net namespace(NET)

独立的网络栈:接口、路由表、firewall、socket port、sysctl net。

创建 net ns 后默认只有 lo。要让容器能通信:

ip netns add foo/var/run/netns/foo 持久化 net ns。

2.4 ipc namespace

SysV shm/sem/msg、POSIX mqueue 被隔离。不同 ns 互不可见。

2.5 uts namespace

hostname 和 domainname。docker run -h myhost 就是 UTS ns + sethostname。

2.6 user namespace(关键)

最重要且最复杂。提供 uid/gid 映射:容器内 uid 0(root)可以映射到 host 上的 uid 100000(非特权)。

/proc/<pid>/uid_map:
0     100000   65536

含义:容器 uid 0-65535 映射到 host uid 100000-165535。

capability 的语义也被改写:user ns 内 root 对本 ns 内的资源有特权,对外部无特权。

这是 rootless 容器(podman、rootless docker、unpriv Firejail)的技术基础。

2.7 cgroup namespace

v2 引入。容器看到的 cgroup 路径以自己所在 cgroup 为根。避免容器里看到 host 的 cgroup 结构。

2.8 time namespace

5.6+ 引入。独立的 CLOCK_MONOTONICCLOCK_BOOTTIME 偏移。checkpoint/restore(CRIU)迁移时恢复单调时钟不倒退。

不隔离 CLOCK_REALTIME——墙钟是全局的,不适合多租户。

三、API 三件套

3.1 clone3 / clone

struct clone_args args = {
    .flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET |
             CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER,
    .exit_signal = SIGCHLD,
};
pid_t pid = syscall(SYS_clone3, &args, sizeof(args));

在 fork 时直接建新 ns。这是 docker/containerd/runc 标准路径。

3.2 unshare

unshare(CLONE_NEWNS | CLONE_NEWPID);
// 注意 CLONE_NEWPID 不影响当前进程,只对后续 fork 的子生效

命令行:unshare -pfu bash 在新 ns 里起 bash。

3.3 setns

int fd = open("/proc/<pid>/ns/net", O_RDONLY);
setns(fd, CLONE_NEWNET);

加入已有 ns。nsenter 命令行封装。

四、ns 的生命周期

每个 ns 是内核对象,引用计数:

全部归零时销毁。这是为什么 ip netns 要 bind 到 /var/run/netns/X——让 netns 在最后一个进程退出后仍持久。

五、rootless 的现实

rootless 容器最大优势:host 上不需要 root。故障面小、安全性高。

但坑:

podman 的 rootless 模式成熟得多;docker rootless 仍需 daemon 侧配置。

六、namespace 与 cgroup 分工

两者正交:namespace 不限资源,cgroup 不隔视图。docker 两者都用。

七、观察 namespace

ls -l /proc/<pid>/ns/
# mnt -> mnt:[4026532...]
# net -> net:[...]
# ...

inode 号相同 = 两进程在同一 ns。

lsns              # util-linux 提供
lsns -t net       # 按类型

nsenter -t <pid> -a 进入某 pid 所在的全部 ns。

八、常见 bug

bug A:容器看到 host 的 /proc 原因:没 remount /proc(新 pid ns 后要 mount -t proc proc /proc

bug B:docker exec 的命令在容器里 PID 不是 1 原因:exec 把进程加入容器的 pid ns,但顶层是容器 init;exec 的是其子孙

bug C:rootless 容器里 ping 不能用 原因:ping 要 cap_net_raw;user ns 里默认无 解决sysctl net.ipv4.ping_group_range;或 setcap

bug D:user ns 映射后文件权限混乱 原因:容器内 uid 1000 映射 host uid 101000;host 上没这个 uid 的文件所有者 解决:挂载前 chown,或用 id-mapped mount(5.12+)

bug E:pid ns init 死了,里面进程全没 原因:内核会 SIGKILL ns 内所有进程 理解:这是 feature;容器要由 init 兜底

九、现代化趋势

十、小结

下一篇 B-18 讲 cgroup v2——统一的资源控制模型,PSI 压力指标,以及 systemd slice 体系。


参考文献

工具


上一篇消息队列 下一篇cgroup v2:资源控制的统一模型

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-14 · os

【操作系统百科】OverlayFS

OverlayFS 用 lower/upper/work 三层实现联合挂载——容器镜像层栈的内核根基。本文讲 copy_up、whiteout、opaque、metacopy、redirect_dir、性能与 Docker overlay2 驱动的工程细节。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。


By .