Droidspaces如何用5个Namespaces实现完美隔离?PID/MNT/UTS/IPC/Cgroup源码级深度解析
【免费下载链接】Droidspaces-OSSA lightweight, LXC-like container runtime for Android and Linux. Run full Linux distributions natively with zero performance penalty项目地址: https://gitcode.com/gh_mirrors/dr/Droidspaces-OSS
Droidspaces是一个轻量级、类似 LXC 的容器运行时,专为 Android 和 Linux 设计,能在手机上原生运行完整的 Linux 发行版且零性能损耗。它的隔离魔法来自内核的 5 大隔离机制:PID、Mount、UTS、IPC 命名空间与 Cgroup 资源控制。本文将从源码角度带你快速看懂:Droidspaces 到底在哪里、按什么顺序调用了哪些unshare()系统调用,每个命名空间各自隔离了什么。
一、先看全局:5个隔离机制各管什么?
在深入源码前,先用一张表建立直觉:
| 隔离机制 | 隔离内容 | Droidspaces 中的作用 |
|---|---|---|
| PID 命名空间 | 进程号与进程列表 | 容器内 init 是 PID 1,看不到宿主机进程 |
| Mount 命名空间 | 挂载点与文件系统视图 | 容器拥有独立的/、/proc、/sys、/dev |
| UTS 命名空间 | 主机名与域名 | 每个容器可以有自己的 hostname |
| IPC 命名空间 | 共享内存、信号量、消息队列 | 容器内 IPC 对象互不可见 |
| Cgroup(+Cgroup NS) | CPU/内存/进程数等资源 | 限制容器资源,隔离/sys/fs/cgroup视图 |
💡 补充:在 NAT/无网络模式下,Droidspaces 还会额外创建NET 命名空间实现网络隔离,它属于可选能力,在 src/check.c 中被标记为 OPTIONAL。
二、启动前先自检:check.c 如何探测内核支持?
很多用户在 Android 上跑容器失败,其实是内核不支持某个命名空间。Droidspaces 的做法很聪明:不仅"看",还要"试"。
在 src/check.c 的check_ns()函数中,每一步分两关:
- 快速检查:探测
/proc/self/ns/<name>是否存在,确认内核编译了对应支持; - 功能检查:
fork()出一个子进程并真正调用unshare(flag)试一次,成功才算通过(unshare会影响当前进程,所以必须用子进程来"沙盒试错")。
启动前的必需检查在 src/check.c:CLONE_NEWNS(文件系统隔离,必需)、CLONE_NEWPID(进程隔离,必需)、CLONE_NEWUTS(主机名隔离,必需)、CLONE_NEWIPC(IPC 隔离,必需)。而 Cgroup 命名空间则在 src/check.c 中被列为"推荐项"——因为它是 Linux 4.6+ 才有的特性。
三、三进程架构:谁在什么时候创建哪个命名空间?
这是 Droidspaces 源码里最有设计感的地方。它并不是"一个进程打包创建所有命名空间",而是把 5 个隔离点分配给三层进程,源码见 src/monitor.c:
父进程 fork → Monitor 监督者 → 中间进程 → 容器 init(PID 1) │ │ ├─ UTS + IPC └─ PID + Cgroup NS(+ NET) └─ 常驻,负责重启循环为什么这么拆?源码注释解释得很直白(src/monitor.c):unshare(CLONE_NEWPID)每个进程只能调用一次。而 Droidspaces 支持容器内部执行reboot(2)后自动重启,每次重启都需要一个"全新的 PID 命名空间"。所以:
- Monitor(监督者):启动时一次性
unshare(CLONE_NEWUTS | CLONE_NEWIPC),这两个命名空间整个容器生命周期不变; - 中间进程:每次启动/重启循环都 fork 一个新的,
unshare(CLONE_NEWPID)(外加可选的CLONE_NEWNET和CLONE_NEWCGROUP),然后 fork 出真正的容器 init; - 容器 init:成为新 PID 命名空间里的 1 号进程,随后执行
internal_boot()完成剩余隔离。
这样"容器内部重启"时,旧的 PID 命名空间随旧 init 消亡,新循环里的一切干干净净,从机制上杜绝了"幽灵容器"。
四、Mount 命名空间 + pivot_root:文件系统隔离的主角
Mount 命名空间是五者中最复杂的,它的登场位置很特别:在容器 init 进程内部、所有其他准备工作之前(src/boot.c):
unshare(CLONE_NEWNS)—— 拿到独立的挂载视图;mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)—— 把所有挂载点设为私有,防止容器内的挂载操作"泄漏"回宿主机。
源码注释特别提到一个 Android 细节:必须先用MS_PRIVATE起步,因为部分内核(比如 Android rootfs)上MS_SHARED会破坏pivot_root/MS_MOVE的回退路径。
随后internal_boot()按编号步骤依次完成(src/boot.c):
- 第 4 步:把 rootfs 自绑定挂载(
MS_BIND | MS_REC),这是pivot_root的前置条件; - 第 8~13 步:搭建
/dev、挂载全新的procfs、sysfs、/run、/tmp(都是隔离的 tmpfs); - 第 17 步:真正的"换根"——
pivot_root(".", ".old_root")把根目录切换到 rootfs;如果运行在 ramfs 环境(如 Android recovery)则自动回退到MS_MOVE + chroot组合,效果等同于switch_root。
换根完成后,宿主机文件系统就被彻底"甩在身后",.old_root随即卸载——这就是 Mount 命名空间给出的完整文件系统隔离。
五、UTS 与 IPC:轻量但不可或缺
这两个命名空间一次unshare就完成(src/monitor.c),成本低但作用明确:
- UTS:容器可以独立设置主机名。网络配置阶段会通过
sethostname()把配置的主机名写进容器(见 src/net/network.c),hostname命令输出的就不再是你的手机型号; - IPC:System V 共享内存、信号量、消息队列全部独立,容器内的进程无法通过 IPC 与宿主机或其他容器互相"串门"。
六、Cgroup:不只是限额,还有资源视图隔离
Cgroup 是 5 个机制里唯一"既管资源又管视图"的,实现在 src/cgroup.c,源码注释直言这是"移植自 LXC 风格的 Cgroup 配置":
- 建立层级:
ds_cgroup_setup()从/proc/self/mountinfo发现宿主机的 cgroup 层级。Android 上很常见 cgroup2 只挂在/dev/cg2_bpf这类非标准位置,Droidspaces 会自己引导到/sys/fs/cgroup(src/cgroup.c); - 加入与隔离:中间进程先
ds_cgroup_join()进入容器的 cgroup,然后才unshare(CLONE_NEWCGROUP)——顺序很关键,因为 Cgroup 命名空间的"根"就是进程当前所处的位置,如果从根 cgroup 就进入命名空间就什么都隔离不了(src/monitor.c); - 应用限额:按配置写入
memory.max/memory.limit_in_bytes、cpu.max、pids.max(src/cgroup.c),分别对应内存、CPU 配额和进程数上限。
更妙的是:当设置了内存限额后,src/virtualize.c 还会"虚拟化"容器内/proc/meminfo等文件,让容器以为自己的内存就是限额值——对 systemd 等软件极其友好。
七、小结:隔离顺序 = 一张清晰的依赖图
把 5 个机制放回时间轴,你会发现 Droidspaces 的隔离顺序完全由依赖关系决定:
- UTS + IPC→ Monitor 常驻,一次到位;
- Cgroup join → Cgroup NS + PID NS(+ NET NS)→ 中间进程,为"可重启"而生;
- MNT NS → 私有挂载 → pivot_root→ 容器 init,完成最后换根。
这种"分层创建、各司其职"的设计,正是 Droidspaces 作为轻量级 LXC 替代品,却能在 Android 这类受限环境中稳定运行完整 Linux 发行版的关键。想动手验证的话,运行droidspaces check就能看到你的设备对这 5 项隔离能力的逐项体检报告。
核心源码索引:
- 监督者与命名空间分层:src/monitor.c
- 启动换根全流程(含 pivot_root):src/boot.c
- 内核能力自检:src/check.c
- Cgroup 层级与限额:src/cgroup.c
- 功能特性说明:Documentation/Features.md
- 内核配置要求:Documentation/Kernel-Configuration.md
【免费下载链接】Droidspaces-OSSA lightweight, LXC-like container runtime for Android and Linux. Run full Linux distributions natively with zero performance penalty项目地址: https://gitcode.com/gh_mirrors/dr/Droidspaces-OSS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考