Namespace是怎么回事?

       Linux namespace,可以理解为将全局的操作系统资源,逻辑上划分成功能独立的单元。如进程号PID,这些个单元有各自独立的PID空间,还比如网络栈,这些个独立的单元有各自独立的路由表,网络接口。linux实现了mount、UTS、IPC、network、pid、user这六种namespace。

 

下面先用unshare来测试实验梳理一下linux namespace。

[root@centos ~]# unshare --help

Usage:

  unshare [options] <program> [<argument>...]

Run a program with some namespaces unshared from the parent.



Options:

 -m, --mount             unshare mounts namespace

 -u, --uts                unshare UTS namespace (hostname etc)

 -i, --ipc                 unshare System V IPC namespace

 -n, --net                unshare network namespace

 -p, --pid                unshare pid namespace

 -U, --user               unshare user namespace

 -f, --fork                fork before launching <program>

   --mount-proc[=<dir>]   mount proc filesystem first (implies --mount)

 -r, --map-root-user       map current user to root (implies --user)
[root@centos ~]# unshare -m --mount-proc -u -i -n -p -U -r -f  /bin/bash

unshare: unshare failed: Invalid argument    // 说明是哪个参数不支持



逐个减少参数后,反复执行后,确认是-U这个参数的问题。

只指定-U参数

[root@centos ~]# unshare -U  /bin/bash

unshare: unshare failed: Invalid argument    // 问题确认, user namespace不支持吗?

 

查询了网上资料,确认了docker版本、内核都已经支持user ns的前提下,centos7默认没有启用user namespace。

 

执行下面的命令启用user namespace,然后reboot

[root@centos ~]# grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"

资料来源:

https://github.com/procszoo/procszoo/wiki/How-to-enable-%22user%22-namespace-in-RHEL7-and-CentOS7%3F

Reboot后,执行下面的命令:

[root@centos ~]# unshare -m --mount-proc -u -i -n -p -U -r -f  /bin/bash

[root@centos ~]# ip link

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

在新的network namespace,只存在loop这个设备

[root@centos ~]# ip route

[root@centos ~]

在新的network namespace,路由表是空的

[root@centos ~]# ip link add  type veth    // 添加veth设备

[root@centos ~]# ip link

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

2: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000

    link/ether 52:e9:ba:d6:23:4e brd ff:ff:ff:ff:ff:ff

3: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000

    link/ether ba:6f:7a:dc:9f:4b brd ff:ff:ff:ff:ff:ff

在新的network namespace,创建了veth设备

 

[root@centos ~]# hostname onecloud

[root@centos ~]# hostname

onecloud

在宿主机上执行hostname

[root@centos ~]# hostname

centos

在新的UTS namespace,可以设置属于自己的hostname, domain

 

[root@centos ~]#mkdir /tmp1 && mount -t tmpfs -o size=20m tmpfs /tmp1

[root@centos ~]# df -h | grep tmp1

tmpfs          20M     0   20M   0% /tmp1

在宿主机上执行

[root@centos ~]# df -h | grep tmp1

[root@centos ~]#

在新的mount namespace,执行mount动作后,宿主机被屏蔽了。这也是容器volume工作的基础(volume相关的知识会另外讲到)。

 

[root@centos ~]# ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD

root         1     0  0 11:08 pts/3    00:00:00 /bin/bash

root        12     1  0 11:09 pts/3    00:00:00 ps -ef

在宿主机执行

[root@centos ~]# ps -ef

root     14069 14052  0 11:08 pts/3    00:00:00 unshare -m --mount-proc -u -i -n -p -U -r -f /bin/bash

root     14071 14069  0 11:08 pts/3    00:00:00 /bin/bash

root     14100   967  0 11:09 ?        00:00:00 sleep 60

root     14106 13000  0 11:10 pts/2    00:00:00 ps -ef

在新的pid namespace,bash是第一号进程

 

接下来,我们来看看有点模糊的user namespace

执行下面的命令:

[test@centos ~]$ id

uid=1000(test) gid=1000(test) groups=1000(test)

[test@centos ~]$ hostname test

hostname: you must be root to change the host name

[test@centos ~]$ unshare -m --mount-proc -u -i -n -p -U -r -f  /bin/bash

unshare: unshare failed: Operation not permitted

[test@centos ~]$ unshare -u -i -n -p -U -r -f  /bin/bash   //去掉了参数-m --mount-proc

[root@centos ~]# id

uid=0(root) gid=0(root) groups=0(root)

[root@centos ~]# hostname test

[root@centos ~]# mount -t tmpfs -o size=20m tmpfs /tmp1

mount: permission denied

[root@centos ~]# ip link add type veth

[root@centos ~]# ip link

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

2: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000

    link/ether 3e:93:49:1a:0b:bc brd ff:ff:ff:ff:ff:ff

3: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000

    link/ether 82:f2:8d:1e:18:e3 brd ff:ff:ff:ff:ff:ff

[root@centos ~]# useradd jacky

bash: /usr/sbin/useradd: Permission denied

 

可以得出几点:

  1. test这个普通用户,在linux系统里是没有权限执行与mount有关的命令的,因此执行unshare这个命令也不能带-m参数。当然,如果是宿主机的管理员root执行unshare,是没有这个限制的。
  2. user namespace的默认管理员root,是“map test user to root”而来,有权限设置主机名,管理网络,没有权限mount,也没有权限管理用户

 

那么如果是管理员root的情况呢?

先准备一个centos 的rootfs

mkdir /opt/rootfs && cd /opt

docker export $(docker create centos) | tar -C ./rootfs -xf -

[root@centos opt]# unshare -m --mount-proc -u -i -n -p -U -r -f  /bin/bash

[root@centos opt]# chroot ./rootfs/

[root@centos /]# useradd peter     //创建新的用户

[root@centos /]# passwd

Changing password for user root.   // 重新设置root管理员的密码

New password:

BAD PASSWORD: The password is a palindrome

Retype new password:

passwd: all authentication tokens updated successfully.

我们用命令chroot将rootfs切换到了/opt/rootfs,因此ueradd、passwd命令的结果就不会影响宿主机系统的配置。如果不切换rootfs,那useradd、passwd改变的就是宿主机系统的配置,这将是很危险的

 

我们再从用户态看看,linux系统的namespace是怎么样的形式:

[root@centos opt]# unshare -m --mount-proc -u -i -n -p -U -r -f  /bin/bash

[root@centos opt]# ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD

root         1     0  0 14:08 pts/2    00:00:00 /bin/bash

root        12     1  0 14:08 pts/2    00:00:00 ps -ef

[root@centos opt]# ll /proc/1/ns/       // 1号进程创建了新的namespace

total 0

lrwxrwxrwx 1 root root 0 Apr 26 14:08 ipc -> ipc:[4026532455]

lrwxrwxrwx 1 root root 0 Apr 26 14:08 mnt -> mnt:[4026532452]

lrwxrwxrwx 1 root root 0 Apr 26 14:08 net -> net:[4026532458]

lrwxrwxrwx 1 root root 0 Apr 26 14:08 pid -> pid:[4026532456]

lrwxrwxrwx 1 root root 0 Apr 26 14:08 user -> user:[4026532450]

lrwxrwxrwx 1 root root 0 Apr 26 14:08 uts -> uts:[4026532454]

[root@centos opt]# exit

exit

[root@centos opt]# ll /proc/1/ns      // 宿主机1号进程的namespace

total 0

lrwxrwxrwx 1 root root 0 Apr 26 14:11 ipc -> ipc:[4026531839]

lrwxrwxrwx 1 root root 0 Apr 26 14:11 mnt -> mnt:[4026531840]

lrwxrwxrwx 1 root root 0 Apr 26 14:11 net -> net:[4026531962]

lrwxrwxrwx 1 root root 0 Apr 26 14:11 pid -> pid:[4026531836]

lrwxrwxrwx 1 root root 0 Apr 26 14:11 user -> user:[4026531837]

lrwxrwxrwx 1 root root 0 Apr 26 14:11 uts -> uts:[4026531838]

很显然,这些个ns的id表示它们是属于不同的namespace。

 

好了,通过上面的过程,我们基本上明白了namespace在linux上是怎么回事。

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐