-f, --fork fork before launching <program> --map-user=<uid>|<name> map current user to uid (implies --user) --map-group=<gid>|<name> map current group to gid (implies --user) -r, --map-root-user map current user to root (implies --user) -c, --map-current-user map current user to itself (implies --user) --map-auto map users and groups automatically (implies --user) --map-users=<outeruid>,<inneruid>,<count> map count users from outeruid to inneruid (implies --user) --map-groups=<outergid>,<innergid>,<count> map count groups from outergid to innergid (implies --user)
--kill-child[=<signame>] when dying, kill the forked child (implies --fork) defaults to SIGKILL --mount-proc[=<dir>] mount proc filesystem first (implies --mount) --propagation slave|shared|private|unchanged modify mount propagation in mount namespace --setgroups allow|deny control the setgroups syscall in user namespaces --keep-caps retain capabilities granted in user namespaces
-R, --root=<dir> run the command with root directory set to <dir> -w, --wd=<dir> change working directory to <dir> -S, --setuid <uid> set uid in entered namespace -G, --setgid <gid> set gid in entered namespace --monotonic <offset> set clock monotonic offset (seconds) intime namespaces --boottime <offset> set clock boottime offset (seconds) intime namespaces
-h, --help display this help -V, --version display version
$ unshare --fork --pid --mount-proc --user --map-root-user bash # id uid=0(root) gid=0(root) groups=0(root),65534(nogroup) # reboot Failed to connect to bus: No data available Failed to open initctl fifo: Permission denied Failed to talk to init daemon.
通过-R dir / --root=dir参数可以指定系统根目录。低版本的unshare可能不支持这个参数,可以使用sudo unshare sh -c 'chroot ubuntu-20.04 && bash'命令代替。
网络命名空间
使用ip netns命令可以进行网络命名空间的管理。
创建命名空间
1
$ sudo ip netns add netns1
获取命名空间列表
1 2 3 4 5
$ sudo ip netns ls netns1 $ ls -l /var/run/netns/netns1 -r--r--r-- 1 root root 0 May 21 15:30 /var/run/netns/netns1 $ sudo ./unshare -R ubuntu-20.04 --net=/var/run/netns/netns1 bash
网络命名空间会存储在/var/run/netns目录下。
在网路命名空间中执行命令
1 2 3
$ sudo ip netns exec netns1 ip a 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
启用网络设备
1 2 3 4 5 6 7 8
$ sudo ip netns exec netns1 ip linkset lo up $ sudo ip netns exec netns1 ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever
$ sudo ip link add veth1 type veth peer name veth2 $ sudo ip linkset veth2 netns netns1 $ sudo ip netns exec netns1 ip linkset veth2 up $ sudo ip netns exec netns1 ip addr add 192.168.10.2/24 dev veth2 $ sudo ip linkset veth1 up $ sudo ip addr add 192.168.10.1/24 dev veth1
配置路由转发
1 2 3 4
$ sudo ip netns exec netns1 ip route add default via 192.168.10.1 dev veth2 $ sudo iptables -A FORWARD -o veth1 -j ACCEPT $ sudo iptables -A FORWARD -i veth1 -j ACCEPT $ sudo iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE
eth0需要替换成本机的实际网络接口
此时,容器内就可以访问外网了。
与unshare相结合
unshare也提供了--net=/var/run/netns/netns1参数来创建网络命名空间,但是实际测试下来发现有些问题。所以比较保险的方案还是将sudo ip netns exec netns1与unshare结合起来使用。
1 2 3 4 5 6 7 8 9 10 11 12 13
$ sudo ip netns exec netns1 unshare -R ubuntu-20.04 ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 29: veth2@if30: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether fe:2c:29:36:5c:9a brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.10.2/24 scope global veth2 valid_lft forever preferred_lft forever inet6 fe80::fc2c:29ff:fe36:5c9a/64 scope link valid_lft forever preferred_lft forever