Docker基础: Linux内核命名空间之(1) mnt namespace

作为开源Container技术代表的Docker,它跟Linux内核的Namespace和Cgroup两大特性密不可分。物有本末,事有终始。知所先后,则近道矣。理解Linux的这两大特性将有助于我们更深入的理解Docker。在前面的文章中,我们曾经体验过如何使用chroot和LXC,在本文中我们将会使用unshare命令来演示Linux内核的MNT Namespace是如何动作的。

Namespace的历史

Namespace并不是Linux才推出的东西,早在很久之前,Unix上就有类似的东西,而HPUX和Solaris商用的Conatiner更是以前就有推出。而在Linux的2.6之后的版本Namespace就逐步的被加了进来。

Linux Namespace的6大类型

项番 类型 功能说明
No.1 MNT Namespace 提供磁盘挂载点和文件系统的隔离能力
No.2 IPC Namespace 提供进程间通信的隔离能力
No.3 Net Namespace 提供网络隔离能力
No.4 UTS Namespace 提供主机名隔离能力
No.5 PID Namespace 提供进程隔离能力
No.6 User Namespace 提供用户隔离能力

Ubuntu版本

root@ubuntu:~# uname -a
Linux ubuntu 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
root@ubuntu:~#

事前确认

确认当前进程PID

root@ubuntu:~# echo $$
32968
root@ubuntu:~#

确认当前进程的各个namespace

root@ubuntu:~# ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 Sep 15 10:23 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 uts -> uts:[4026531838]
root@ubuntu:~#

内容说明

项番 内容说明
No.1 linux会在/proc下创建所对应的进程相关的信息,ns则为Namespace的信息
No.2 $$为当前进程PID,/proc/$$/ns下的Namespace的个数回随着Linux内核的高低不同显示的个数不同,因为Linux所支持的Namespace不是一次到位的
No.3 mnt:[4026531840],不同的Namespace都有不同的编号,比如32968的mnt的namespace的编号就是4026531840
No.4 关于Cgroup会单独在后面进行说明

没有隔离的mount

首先我们来看一下没有隔离的mount是怎样动作的,为了简单起见使用tmpfs这种基于内存的文件系统来模拟。

事前准备

root@ubuntu:~# mkdir /tmp/testnoisolation

mount tmpfs

root@ubuntu:~# mount -t tmpfs tmpfs /tmp/testnoisolation
root@ubuntu:~# cd /tmp/testnoisolation
root@ubuntu:/tmp/testnoisolation# 

创建文件

root@ubuntu:/tmp/testnoisolation# touch aaa bbb ccc ddd
root@ubuntu:/tmp/testnoisolation# ll
total 4
drwxrwxrwt  2 root root  120 Sep 15 10:56 ./
drwxrwxrwt 13 root root 4096 Sep 15 10:55 ../
-rw-r--r--  1 root root    0 Sep 15 10:56 aaa
-rw-r--r--  1 root root    0 Sep 15 10:56 bbb
-rw-r--r--  1 root root    0 Sep 15 10:56 ccc
-rw-r--r--  1 root root    0 Sep 15 10:56 ddd
root@ubuntu:/tmp/testnoisolation#

确认

在新起一个终端来确认目录/tmp/testnoisolation的信息

admin01@ubuntu:~$ echo $$
33414
admin01@ubuntu:~$ ls -l /tmp/testnoisolation
total 0
-rw-r--r-- 1 root root 0 Sep 15 10:56 aaa
-rw-r--r-- 1 root root 0 Sep 15 10:56 bbb
-rw-r--r-- 1 root root 0 Sep 15 10:56 ccc
-rw-r--r-- 1 root root 0 Sep 15 10:56 ddd
admin01@ubuntu:~$

有隔离的mount

事前准备

root@ubuntu:~# mkdir /tmp/testisolation

使用unshare隔离mnt namespace

虽然也可以使用Linux内核提供的系统函数写简单的程序来实现,但是多少有点喧宾夺主的感觉。linux已经提供了非常贴心的unshare命令,只需要下面一行语句我们就能重新启动一个bash的进程,而在其中的mnt namespace是被隔离的。

root@ubuntu:~# echo $$
32968
root@ubuntu:~# unshare --mount /bin/bash
root@ubuntu:~#

好像没有任何变化,其实这个已经不是刚才我们的32968进程了,而是一个新的进程,通过确认$$就能确认

root@ubuntu:~# echo $$
33447
root@ubuntu:~#

再来确认一下,33447和32968两个进程的关系,我们能清楚地看到这是父子关系的两个进程,虽然都是bash

admin01@ubuntu:~$ ps -ef |grep 32968 |grep -v grep
root      32968  32967  0 10:16 pts/0    00:00:00 -su
root      33447  32968  0 11:09 pts/0    00:00:00 /bin/bash
admin01@ubuntu:~$ pstree 32968
bashqqqbash
admin01@ubuntu:~$

mount tmpfs

root@ubuntu:~# echo $$
33447
root@ubuntu:~# mount -t tmpfs tmpfs /tmp/testisolation
root@ubuntu:~# cd /tmp/testisolation
root@ubuntu:/tmp/testisolation#

创建文件

root@ubuntu:/tmp/testisolation# touch aaa bbb ccc ddd
root@ubuntu:/tmp/testisolation# ll
total 4
drwxrwxrwt  2 root root  120 Sep 15 11:15 ./
drwxrwxrwt 14 root root 4096 Sep 15 11:02 ../
-rw-r--r--  1 root root    0 Sep 15 11:15 aaa
-rw-r--r--  1 root root    0 Sep 15 11:15 bbb
-rw-r--r--  1 root root    0 Sep 15 11:15 ccc
-rw-r--r--  1 root root    0 Sep 15 11:15 ddd
root@ubuntu:/tmp/testisolation#

确认

在新起一个终端来确认目录/tmp/testisolation的信息,没有任何信息。

admin01@ubuntu:~$ ll /tmp/testisolation
total 8
drwxr-xr-x  2 root root 4096 Sep 15 11:02 ./
drwxrwxrwt 14 root root 4096 Sep 15 11:02 ../
admin01@ubuntu:~$

新mnt Namespace编号

/proc/$$/ns下面会列出当前的namespace信息,我们来看看一下这个使用unshare隔离了mnt namespace的信息

root@ubuntu:~# ls -l /proc/33447/ns
total 0
lrwxrwxrwx 1 root root 0 Sep 15 11:25 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 mnt -> mnt:[4026532506]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 uts -> uts:[4026531838]
root@ubuntu:~#

与之前进行比较,我们可以清晰地发现,除了mnt的namespace编号从4026531840变为4026532506之外,其余都没有改变。这也是使用unshare -m或者unshare –mnt所实现的隔离,创建了新的namespace。

和chroot的比较

在比较原始的chroot中,画地为牢之后,是无法挣脱其所指定的根的,虽然有效但是略显粗暴。而namespace则自由的多,起码可以自由的动作,当然不只是这一点区别,但是这一点是最为直观能看出来的

root@ubuntu:/tmp/testisolation# pwd
/tmp/testisolation
root@ubuntu:/tmp/testisolation# cd ../testnoisolation/
root@ubuntu:/tmp/testnoisolation# ll
total 4
drwxrwxrwt  2 root root  120 Sep 15 10:56 ./
drwxrwxrwt 14 root root 4096 Sep 15 11:17 ../
-rw-r--r--  1 root root    0 Sep 15 10:56 aaa
-rw-r--r--  1 root root    0 Sep 15 10:56 bbb
-rw-r--r--  1 root root    0 Sep 15 10:56 ccc
-rw-r--r--  1 root root    0 Sep 15 10:56 ddd
root@ubuntu:/tmp/testnoisolation#

其他相关

内容 URL
docker基础:从chroot理解namespace的隔离 http://blog.csdn.net/liumiaocn/article/details/52388793
在CentOS7上使用LXC管理容器 http://blog.csdn.net/liumiaocn/article/details/52348219
如何使用RHEL/CentOS 7安装创建和管理LXC (Linux Containers) http://blog.csdn.net/liumiaocn/article/details/52337479

你可能感兴趣的:(#,深入浅出Docker)