unshare 是 Linux 系统中一个强大的命令行工具,用于在一个或多个新的命名空间(Namespace) 中运行程序。它和 nsenter 命令一起,构成了容器技术(如 Docker)的基石-。
核心概念:命名空间(Namespace)
简单来说,命名空间是 Linux 内核提供的一种资源隔离机制。它能让一组进程拥有独立的系统资源视图,仿佛运行在一个独立的系统中。
unshare 命令通过 unshare() 系统调用,将当前进程从父进程的某些命名空间中“剥离”出来,创建一个新的、隔离的环境。
核心选项与用法
unshare 的基本语法是 unshare [选项] [程序 [参数...]]。如果不指定程序,默认会运行 $SHELL 或 /bin/sh。
下表总结了最常用的选项及其作用:
| 选项 | 长选项 | 隔离的命名空间 | 作用 |
|---|---|---|---|
-m | --mount | 挂载点 (Mount) | 拥有独立的文件系统挂载点,在此命名空间内的挂载/卸载操作不会影响主机。 |
-u | --uts | 主机名 (UTS) | 拥有独立的主机名和域名(NIS域名)。 |
-i | --ipc | 进程间通信 (IPC) | 拥有独立的 System V IPC 和 POSIX 消息队列。 |
-n | --net | 网络 (Network) | 拥有独立的网络栈,包括网络接口、IP 地址、路由表和防火墙规则。 |
-p | --pid | 进程ID (PID) | 拥有独立的进程 ID 空间,其第一个进程的 PID 为 1。 |
-U | --user | 用户 (User) | 拥有独立的用户和组 ID 映射,非特权用户可在其命名空间内成为 root。 |
-C | --cgroup | 控制组 (Cgroup) | 拥有虚拟化的 cgroup 视图。 |
-r | --map-root-user | 与 -U 配合 | 将当前用户映射为新用户命名空间中的 root 用户 (UID 0)。 |
-f | --fork | 与 -p 配合 | 创建子进程来执行指定程序,并使其成为新 PID 命名空间中的第一个进程。 |
--mount-proc | 与 -p 配合 | 在新 PID 命名空间中挂载 /proc 文件系统,以确保 ps、top 等命令显示正确的进程信息。 |
常见用法与技巧
1. 创建隔离的网络环境(沙盒)
这项功能非常实用,甚至无需 root 权限即可操作。
# 进入一个只有 lo(回环)接口的新网络命名空间
unshare -rn
# 此时运行 ip addr 或 ifconfig,你将看不到任何物理网卡
ip addr
# 注意,lo 接口默认是 down 状态,需要手动启用
ip link set lo up
这个隔离的网络环境可用于安全地运行不信任的程序,或进行网络实验。
2. 创建独立的 PID 空间(迷你容器)
这是模拟容器最核心的用法之一。
# 创建一个新的 PID 命名空间,并挂载 /proc
sudo unshare --pid --fork --mount-proc /bin/bash
# 在新命名空间中查看进程,你将看到类似容器的进程列表
ps aux
注意:
-
必须使用
--fork,否则新进程不会成为 PID 1。 -
必须使用
--mount-proc或手动挂载/proc,否则ps等命令看到的是主机的进程信息。
3. 非 root 用户获得“伪 root”权限
利用 User Namespace,普通用户可以在自己创建的命名空间内拥有 root 权限。
# 创建一个新的用户命名空间,并将当前用户映射为 root
unshare --user --map-root-user /bin/bash
# 此时在 shell 中执行 id,会显示 uid=0(root)
id
# 虽然显示为 root,但在主机上你仍是普通用户,此 root 权限仅限于该命名空间内
这为普通用户运行需要“表面”root 权限的程序提供了可能。
4. 隔离主机名(UTS)
# 在新的 UTS 命名空间中启动一个 shell
sudo unshare --uts /bin/bash
# 修改主机名,这不会影响主机
hostname new-isolated-hostname
高级技巧
1. 创建持久的命名空间
默认情况下,当命名空间内的最后一个进程退出时,命名空间就会消亡。但你可以通过 bind mount 使其持久化。
# 1. 创建一个新的挂载命名空间,并使其持久化
sudo unshare -m /bin/bash
# 在命名空间内,获取当前进程的 PID,比如是 1234
echo $$
# 在命名空间内执行(或另开一个终端执行):
sudo touch /var/run/my-mount-ns
sudo mount --bind /proc/1234/ns/mnt /var/run/my-mount-ns
之后,即使在原来的 shell 退出后,你也可以通过 nsenter 命令重新进入这个命名空间:
sudo nsenter --mount=/var/run/my-mount-ns /bin/bash
2. 组合多个命名空间
你可以同时使用多个选项,创建一个高度隔离的环境。
# 隔离 UTS, User, PID, Mount, 并挂载 /proc
sudo unshare -uUrpfm --mount-proc /bin/bash
这条命令几乎模拟了一个最小化的容器环境-。
3. 高级网络模拟
unshare -rn 创建的命名空间只有 lo 接口。你可以使用 ip link 命令创建虚拟以太网对(veth pair),将一个 veth 端放入新命名空间,另一个留在主机或其他命名空间,从而实现命名空间间的网络通信。
# 在终端1
unshare -rn
# 获取 PID,假设为 1234
echo $$
# 在终端2(或另一个终端)
# 创建一对 veth 设备,一端放入命名空间 1234
sudo ip link add veth0 type veth peer name veth1
sudo ip link set veth1 netns 1234
# 然后分别为 veth0 和 veth1 配置 IP 并启用
注意事项与常见问题
-
/proc问题:使用--pid时必须配合--fork和--mount-proc,否则进程视图不会隔离。 -
权限问题:大多数命名空间(如 Mount、PID、Network)需要 root 权限。User Namespace 是例外,它允许非特权用户使用。
-
挂载传播:在
unshare -m创建的新挂载命名空间中,默认的挂载事件传播类型会被设为private,以确保隔离性。 -
SHELL环境变量:如果未指定程序,unshare会运行$SHELL变量指向的 shell。如果$SHELL未设置,则默认使用/bin/sh。 -
持久化 PID 命名空间:需要 Linux 内核 4.17 或更新版本。
总结
unshare 是一个深入理解 Linux 容器技术的绝佳工具。通过组合不同的命名空间选项,你可以在单台 Linux 主机上轻松创建出各种隔离环境,无论是用于安全测试、应用调试,还是深入学习容器原理。

118

被折叠的 条评论
为什么被折叠?



