Linux ip netns 的 mount / pid / net 命名空间组合使用场景

12次阅读

需用 unshare –pid –mount-proc –net=ns1 –fork bash 启动带独立 /proc 和 netns 的 shell;ip netns exec 不创建新 mount/pid 命名空间,故无法隔离 /proc、/sys;组合 user+net+pid 时须配置 uid_map/gid_map 并设 setgroups=deny。

Linux ip netns 的 mount / pid / net 命名空间组合使用场景

netns 里怎么让进程看到自己的 /proc 和 /sys

默认创建的 ip netns 只隔离网络栈,/proc/sys 仍是宿主机视图,导致 pslsmod 或容器内工具行为异常。必须手动挂载独立的伪文件系统。

实操建议:

  • 先用 unshare --pid --mount-proc --user --fork bash 启动带独立 /proc 的 shell,再进 netns;否则 mount --bind 到已有 netns 的 /proc 会失败(因为已挂载)
  • 进 netns 后执行:
    mkdir -p /var/run/netns/ns1 mount -t proc proc /proc mount -t sysfs sysfs /sys
  • 注意:挂载前确保 /proc 目录为空且未被占用,否则报错 Device or resource busy
  • /proc 挂载后,ps aux 显示的 PID 是该命名空间内的 PID(从 1 开始),但实际进程仍运行在宿主机 PID 命名空间中——这是预期行为,不是 bug

为什么 ip netns exec 不继承 mount 或 pid 命名空间

ip netns exec 本质是用 setns() 系统调用切换到目标 netns,但它不创建新 mount 或 pid 命名空间,也不重挂载 /proc。所以你在 netns 里看到的仍是宿主机的挂载点和进程列表。

常见错误现象:

  • 在 netns 中执行 df -h,显示的是宿主机磁盘使用情况,而非“隔离环境”的存储视图
  • ip netns exec ns1 ps aux 看到所有宿主机进程,而非仅该 netns 内启动的进程
  • 试图在 netns 内 mount --bind 新路径失败,提示 Permission denied(因未启用 --mount 权限)

解决方向:不用 ip netns exec,改用 unshare 组合命令,例如:

unshare --net=/var/run/netns/ns1 --pid --mount-proc --fork bash

多个命名空间组合时 uid_map 和 setgroups 的坑

当你同时用 --user + --net + --pid,内核要求必须配置 user namespace 的 uid/gid 映射,否则 setns() 失败或进程无法访问网络设备。

关键参数差异:

  • 没配 /proc/self/uid_map 就执行 ip link set dev veth0 netns ns1,会报错:Operation not permitted
  • setgroups 必须设为 deny 才能写 gid_map,否则报错:Operation not permitted
  • 典型初始化顺序:
    unshare --user --net --pid --fork bash echo "0 1000 1" > /proc/self/uid_map echo "deny" > /proc/self/setgroups echo "0 1000 1" > /proc/self/gid_map
  • uid_map 中第二列(host UID)必须是你当前 shell 的真实 UID,否则 netns 内 pingss 会因权限不足失败

netns + pidns 下 systemd 服务起不来的原因

在完整隔离的 netns + pidns 中直接运行 systemd --system 几乎必然失败,不是配置问题,而是设计限制:systemd 需要访问 /dev/kmsg/run/systemd 等全局路径,且依赖 cgroup v1/v2 的挂载状态。

实用替代方案:

  • 不要在 netns 中启动完整 systemd,改用 dbus-run-session + 单个守护进程(如 dnsmasq -k -C /etc/dnsmasq.d/ns1.conf
  • 若真需 init-like 行为,用 init=/bin/bash 启动最小 init,再手动 exec 主进程,避免 fork 多进程带来的 pidns 混乱
  • 检查 /proc/1/cgroup:如果显示的是宿主机 cgroup 路径(如 /system.slice),说明未进入独立 cgroup,systemd 会拒绝启动
  • 绝大多数场景下,“netns + 手动启动单个网络服务”比“netns + systemd”更稳定、更易调试

复杂点在于命名空间不是开关式隔离,而是叠加式约束——漏掉任意一层(比如忘了 --mount-procuid_map),就可能让某个看似无关的系统调用突然失败,而且错误信息往往不指向根本原因。

text=ZqhQzanResources