若是把linux操做系統比做一個大房子,那命名空間指的就是這個房子中的一個個房間,住在每一個房間裏的人都自覺得獨享了整個房子的資源,但其實你們僅僅只是在共享的基礎之上互相隔離,共享指的是共享全局的資源,而隔離指的是局部上彼此保持隔離,於是命名空間的本質就是指:一種在空間上隔離的概念,當下盛行的許多容器虛擬化技術(典型表明如LXC、Docker)就是基於linux命名空間的概念而來的。php
一方面:若是咱們要深刻研究docker技術,linux namespace是必須掌握的基礎知識。node
另外一方面:Neutron也使用Linux命名空間(Network Namespace),這是理解openstack網絡機制的根本。linux
Linux Namespace是Linux提供的一種內核級別環境隔離的方法,關於隔離的概念其實你們早已接觸過:好比在光盤修復模式下,能夠用chroot切換到其餘的文件系統,chroot提供了一種簡單的隔離模式:chroot內部的文件系統沒法訪問外部的內容。Linux Namespace在此基礎上又提供了不少其餘隔離機制。docker
當前,Linux 支持6種不一樣類型的命名空間。它們的出現,使用戶建立的進程可以與系統分離得更加完全,從而不須要使用更多的底層虛擬化技術。詳細請點擊shell
主要是三個系統調用centos
首先,咱們來看一下一個最簡單的clone()系統調用的示例,(後面,咱們的程序都會基於這個程序作修改):安全
文件名:clone.cbash
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> /* 定義一個給 clone 用的棧,棧大小1M */ #define STACK_SIZE (1024 * 1024) static char container_stack[STACK_SIZE]; char* const container_args[] = { "/bin/bash", NULL }; int container_main(void* arg) { printf("Container - inside the container!\n"); /* 直接執行一個shell,以便咱們觀察這個進程空間裏的資源是否被隔離了 */ execv(container_args[0], container_args); printf("Something's wrong!\n"); return 1; } int main() { printf("Parent - start a container!\n"); /* 調用clone函數,其中傳出一個函數,還有一個棧空間的(爲何傳尾指針,由於棧是反着的) */ int container_pid = clone(container_main, container_stack+STACK_SIZE, SIGCHLD, NULL); /* 等待子進程結束 */ waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0; }
測試開闢一個新的名稱空間:網絡
[root@www ~]# gcc -o clone clone.c #編譯clone.c [root@www ~]# ./clone #執行編譯的結果 Parent - start a container! Container - inside the container! [root@www ~]# #進入了一隔離的空間 [root@www ~]# exit #退出該空間 exit Parent - container stopped! [root@www ~]# #又回到最初的空間
從上面的程序,咱們能夠看到,這和pthread基本上是同樣的玩法。可是,對於上面的程序,父子進程的進程空間是沒有什麼差異的,父進程能訪問到的子進程也能。app
下面, 讓咱們來看幾個例子看看,Linux的Namespace是什麼樣的。
由於下述測試涉及到用戶權限問題,所以咱們新建用戶egon(本人的英文名,哈哈),而且賦予該用戶sudo權限
執行visudo而後新增以下內容:
egon ALL=(ALL) NOPASSWD:ALL
主要目的是獨立出主機名和網絡信息服務(NIS)。
文件名:uts.c
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> /* 定義一個給 clone 用的棧,棧大小1M */ #define STACK_SIZE (1024 * 1024) static char container_stack[STACK_SIZE]; char* const container_args[] = { "/bin/bash", NULL }; /* 與uts有關的代碼:此處只演示主機名的隔離 */ int container_main(void* arg) { printf("Container - inside the container!\n"); sethostname("container",10); /* 設置hostname */ execv(container_args[0], container_args); printf("Something's wrong!\n"); return 1; } int main() { printf("Parent - start a container!\n"); int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | SIGCHLD, NULL); /*啓用CLONE_NEWUTS Namespace隔離 */ waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0; }
測試開闢一個新的UTS名稱空間/容器container,驗證主機名的隔離性:
[egon@www ~]$ gcc -o uts uts.c #編譯utc.c獲得可執行文件uts [egon@www ~]$ sudo ./uts #須要root權限才能開闢新的container Parent - start a container! Container - inside the container! [root@container egon]# #進入一個隔離的空間,即一個container [root@container egon]# hostname #查看該空間下的主機名 container [root@container egon]# exit #退出該container exit Parent - container stopped! [egon@www ~]$ hostname #查看最初的空間下的主機名 www.egon.org #發現確實與剛剛咱們開闢的container是不一樣的主機名,驗證了隔離性 [egon@www ~]$
IPC全稱 Inter-Process Communication,是Unix/Linux下進程間通訊的一種方式,IPC有共享內存、信號量、消息隊列等方法。因此,爲了隔離,咱們也須要把IPC給隔離開來,這樣,只有在同一個Namespace下的進程才能相互通訊。若是你熟悉IPC的原理的話,你會知道,IPC須要有一個全局的ID,即然是全局的,那麼就意味着咱們的Namespace須要對這個ID隔離,不能讓別的Namespace的進程看到。
文件名:ipc.c
要啓動IPC隔離,咱們只須要在調用clone時加上CLONE_NEWIPC參數就能夠了(見下述代碼標紅的地方)
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> /* 定義一個給 clone 用的棧,棧大小1M */ #define STACK_SIZE (1024 * 1024) static char container_stack[STACK_SIZE]; char* const container_args[] = { "/bin/bash", NULL }; /* 與uts有關的代碼:此處只演示主機名的隔離 */ int container_main(void* arg) { printf("Container - inside the container!\n"); sethostname("container",10); /* 設置hostname */ execv(container_args[0], container_args); printf("Something's wrong!\n"); return 1; } int main() { printf("Parent - start a container!\n"); int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD, NULL); /*新增CLONE_NEWIPC就能夠了 */ waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0; }
預備階段(在全局新建IPC隊列):
首先,咱們先建立一個IPC的Queue(以下所示,全局的Queue ID是0)
ipcmk建立隊列
ipcrm刪除隊列
ipcs查看隊列
[egon@www ~]$ ipcs -q #查看隊列 ------ Message Queues -------- key msqid owner perms used-bytes messages [egon@www ~]$ ipcmk -Q #在全局建立一個ipc的隊列,隊列id爲0 Message queue id: 0 [egon@www ~]$ ipcs -q #查看剛剛新建的全局的隊列的信息 ------ Message Queues -------- key msqid owner perms used-bytes messages 0x0c076dce 0 egon 644 0 0
咱們暫且不運行編譯的CLONE_NEWIPC的程序ipc,讓咱們先運行以前編譯的uts,發如今子進程中仍是能看到這個全局的IPC Queue。
[egon@www ~]$ ipcs -q #查看全局的隊列 ------ Message Queues -------- key msqid owner perms used-bytes messages 0x0c076dce 0 egon 644 0 0 [egon@www ~]$ sudo ./uts #進入新的uts容器 Parent - start a container! Container - inside the container! [root@container egon]# ipcs -q #在uts容器下發現仍然能看到全局的IPC隊列,證實此時沒有實現IPC隔離 ------ Message Queues -------- key msqid owner perms used-bytes messages 0x0c076dce 0 egon 644 0 0 [root@container egon]# exit #退出uts容器 exit Parent - container stopped! [egon@www ~]$
測試開闢一個新的IPC名稱空間/容器container,驗證IPC的隔離性:
[egon@www ~]$ gcc -o ipc ipc.c #編譯 [egon@www ~]$ ipcs -q #在全局查看ipc隊列,確定能夠看到 ------ Message Queues -------- key msqid owner perms used-bytes messages 0x0c076dce 0 egon 644 0 0 [egon@www ~]$ sudo ./ipc #進入ipc容器 Parent - start a container! Container - inside the container! [root@container egon]# ipcs -q #在容器內查看ipc隊列,發現查看不到全局的ipc隊列,本身這裏的ipc隊列爲空,驗證了ipc的隔離性
#同理若是在該容器內用ipcmk -Q建立的隊列,在全局也沒法看到,讀者能夠自行測試 ------ Message Queues -------- key msqid owner perms used-bytes messages [root@container egon]# exit exit Parent - container stopped! [egon@www ~]$
空間內的PID 是獨立分配的,意思就是命名空間內的虛擬 PID 可能會與命名空間外的 PID 相沖突,因而命名空間內的 PID 映射到命名空間外時會使用另一個 PID。好比說,命名空間內第一個 PID 爲1,而在命名空間外就是該 PID 已被 init 進程所使用。
文件名:pid.c
基於ipc.c修改而來,見標紅部分,其中只需新增CLONE_NEWPID就徹底可實現PID的隔離,而此處咱們即加了CLONE_NEWUTS又加了CLONE_NEWIPC,隨後才添加了CLONE_NEWPID,表明的意思是:在UTS和IPC隔離的基礎之上再進行PID的隔離,此時的容器已經愈來愈接近於在linux操做系統上新建一個隔離的操做系統了。
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> /* 定義一個給 clone 用的棧,棧大小1M */ #define STACK_SIZE (1024 * 1024) static char container_stack[STACK_SIZE]; char* const container_args[] = { "/bin/bash", NULL }; int container_main(void* arg) { printf("Container [%5d] - inside the container!\n",getpid()); /* 此處的getpid()是爲了獲取容器的初始進程(init)的pid */ sethostname("container",10); /* 設置hostname */ execv(container_args[0], container_args); printf("Something's wrong!\n"); return 1; } int main() { printf("Parent [%5d] - start a container!\n",getpid()); /* 此處的getpid()則是爲了獲取父進程的pid */ int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD, NULL); /*新增CLONE_NEWPID便可,此處表明在UTS和IPC隔離的基礎之上再進行PID的隔離,其實咱們徹底能夠只加CLONE_NEWPID本身:這樣的話就只表明隔離PID了 */ waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0; }
測試開闢一個新的PID名稱空間/容器container,驗證PID的隔離性:
[egon@www ~]$ gcc -o pid pid.c #編譯 [egon@www ~]$ sudo ./pid #進入一個新的容器 Parent [ 4520] - start a container! Container [ 1] - inside the container! [root@container egon]# echo $$ #查看該容器的初始程序(init)ID爲1,而全局的init程序的ID也爲1,證實了兩者的隔離性 1 [root@container egon]# hostname #由於咱們在pid.c文件中加入了CLONE_NEWUTS,因此此時的主機名也是隔離的,看到的是本身的主機名 container [root@container egon]# ipcs -q #由於咱們在pid.c文件中也加入了CLONE_NEWIPC,因此此時的IPC也是隔離的,看不到全局新建的那個IPC隊列 ------ Message Queues -------- key msqid owner perms used-bytes messages
ps:centos7以後使用systemd代替init,此處咱們說的初始程序指的就是這兩者,是一個意思
說明:在傳統的UNIX系統中,PID爲1的進程是init,地位很是特殊。他做爲全部進程的父進程,有不少特權(好比:屏蔽信號等),另外,其還會爲檢查全部進程的狀態,咱們知道,若是某個子進程脫離了父進程(父進程沒有wait它),那麼init就會負責回收資源並結束這個子進程。因此,要作到進程空間的隔離,首先要建立出PID爲1的進程,最好就像chroot那樣,把子進程的PID在容器內變成1。
可是,咱們會發現,在子進程的shell裏輸入ps,top等命令,咱們仍是能夠看獲得全部進程。說明並無徹底隔離。這是由於,像ps, top這些命令會去讀/proc文件系統,因此,由於/proc文件系統在父進程和子進程都是同樣的,因此這些命令顯示的東西都是同樣的。
因此,咱們還須要對文件系統進行隔離,這就須要用到mount命名空間了
進程運行時能夠將掛載點與系統分離,使用這個功能時,咱們能夠達到 chroot 的功能,而在安全性方面比 chroot 更高。
文件名:fs.c
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> /* 定義一個給 clone 用的棧,棧大小1M */ #define STACK_SIZE (1024 * 1024) static char container_stack[STACK_SIZE]; char* const container_args[] = { "/bin/bash", NULL }; int container_main(void* arg) { printf("Container [%5d] - inside the container!\n", getpid()); sethostname("container",10); /* 從新mount proc文件系統到 /proc下 */ system("mount -t proc proc /proc"); execv(container_args[0], container_args); printf("Something's wrong!\n"); return 1; } int main() { printf("Parent [%5d] - start a container!\n", getpid()); /* 啓用Mount Namespace - 增長CLONE_NEWNS參數 */ int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL); waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0; }
咱們基於上次pid容器,在沒有mount隔離狀況下查看/proc、ps aux、top等信息
[egon@www ~]$ sudo ./pid Parent [ 6231] - start a container! Container [ 1] - inside the container! [root@container egon]# ls /proc/ 1 116 132 148 165 18 197 213 230 248 265 282 36 5005 57 63 73 83 938 diskstats locks sysrq-trigger 10 117 133 149 166 180 198 214 231 249 266 283 37 51 58 64 731 84 94 dma mdstat sysvipc 100 118 134 15 167 181 199 215 232 25 267 284 38 514 59 640 74 841 95 driver meminfo timer_list 101 119 135 150 168 182 2 216 233 250 268 285 39 515 5939 641 745 85 957 execdomains misc timer_stats 102 12 136 151 169 183 20 217 234 251 2682 29 3944 517 60 642 75 86 96 fb modules tty 103 120 137 152 17 184 200 218 235 252 2684 293 3946 52 6047 643 76 863 960 filesystems mounts uptime 104 121 138 153 170 185 201 219 236 253 269 294 3982 520 6048 644 77 864 97 fs mpt version 105 122 139 154 171 186 202 22 237 254 27 295 40 53 6052 645 78 87 98 interrupts mtrr vmallocinfo 106 123 14 155 172 187 203 220 238 255 270 296 41 532 6053 646 780 871 99 iomem net vmstat ......省略n行 [root@container egon]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.6 44000 6548 ? Ss 10:24 0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 21 root 2 0.0 0.0 0 0 ? S 10:24 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? S 10:24 0:00 [ksoftirqd/0] root 5 0.0 0.0 0 0 ? S< 10:24 0:00 [kworker/0:0H] root 7 0.0 0.0 0 0 ? S 10:24 0:00 [migration/0] root 8 0.0 0.0 0 0 ? S 10:24 0:00 [rcu_bh] root 9 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/0] root 10 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/1] root 11 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/2] root 12 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/3] root 13 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/4] root 14 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/5] root 15 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/6] root 16 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/7] root 17 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/8] root 18 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/9] root 19 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/10] root 20 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/11] root 21 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/12] root 22 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/13] root 23 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/14] root 24 0.0 0.0 0 0 ? S 10:24 0:00 [rcuob/15] ......省略n行
初次以外還有top命令運行的截圖
測試開闢一個新的MOUNT名稱空間/容器container,驗證MOUNT的隔離性:
[egon@www ~]$ gcc -o fs fs.c #編譯 [egon@www ~]$ sudo ./fs #進入mount容器 Parent [ 6554] - start a container! Container [ 1] - inside the container! [root@container egon]# #此處即是新的容器了 [root@container egon]# ls /proc/ #瀏覽/proc內容,發現少了好多 1 bus crypto execdomains iomem keys loadavg modules pagetypeinfo slabinfo sysrq-trigger uptime 13 cgroups devices fb ioports key-users locks mounts partitions softirqs sysvipc version acpi cmdline diskstats filesystems irq kmsg mdstat mpt sched_debug stat timer_list vmallocinfo asound consoles dma fs kallsyms kpagecount meminfo mtrr scsi swaps timer_stats vmstat buddyinfo cpuinfo driver interrupts kcore kpageflags misc net self sys tty zoneinfo [root@container egon]# ps aux #查看進程信息發現只能兩個進程:一個初始進程id爲1,另一個就算ps命令自己 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.2 115384 2092 pts/0 S 11:35 0:00 /bin/bash root 14 0.0 0.1 139500 1632 pts/0 R+ 11:35 0:00 ps aux
除此以外執行top命令,發現包括top命令自己,也是隻要兩個進程
須要強調的一點是:在經過CLONE_NEWNS建立mount namespace後,父進程會把本身的文件結構複製給子進程中。而子進程中新的namespace中的全部mount操做都隻影響自身的文件系統,而不對外界產生任何影響。這樣能夠作到比較嚴格地隔離。
而且咱們徹底能夠根據本身的須要來爲容器定製mount選項。
Docker的 Mount Namespace
下面就讓咱們來模擬製做一個鏡像,模仿Docker的Mount Namespace
步驟一:
對於chroot來講,chroot 目錄,而後切入到目錄對應的名稱空間下,同理,咱們也須要爲咱們的mount namespace提供一個目錄(即鏡像),因而咱們在/home/egon下新建目錄rootfs
rootfs的目錄結構參照linux根目錄的結構
[root@www ~]# for i in `ls /`;do mkdir /home/egon/rootfs/$i -p;done [root@www ~]# ls /home/egon/rootfs/ bin boot data dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
步驟二 :
把一些咱們須要在命名空間內使用的命令拷貝到/home/egon/rootfs/bin以及/home/egon/rootfs/usr/bin目錄下,須要注意的是:/bin/sh命令必須被拷貝,且要被拷貝到/home/egon/rootfs/bin下,不然沒法chroot
#新增目錄 [root@www ~]# mkdir /home/egon/rootfs/usr/libexec [root@www ~]# mkdir /home/egon/rootfs/usr/bin #拷貝命令 [root@www ~]# cp -r /bin/* /home/egon/rootfs/bin/ [root@www ~]# cp -r /usr/bin/* /home/egon/rootfs/usr/bin/ #拷貝命令依賴的庫,能夠ldd /bin/ls來查看ls命令用來的庫文件,而後定向拷貝,此處咱們就簡單粗暴的使用*拷貝全部了 [root@www ~]# cp -r /lib/* /home/egon/rootfs/lib/ [root@www ~]# cp -r /lib64/* /home/egon/rootfs/lib64/ [root@www ~]# cp -r /usr/libexec/* /home/egon/rootfs/usr/libexec/ #拷貝命令依賴的一些配置文件 [root@www ~]# cp -r /etc/* /home/egon/rootfs/etc/
步驟三:
咱們還能夠爲命名空間定製一些配置文件
[root@www ~]# mkdir /home/egon/conf [root@www ~]# echo 'egon_hostname' >> /home/egon/conf/hostname #定義hostname文件,用來掛載到命名空間中的/etc/hostname [root@www ~]# echo '1.1.1.1 egon_hostname' >> /home/egon/conf/hosts #定義hosts文件,用來掛載到命名空間中的/etc/hosts [root@www ~]# echo 'nameserver 202.110.110.213' >> /home/egon/conf/resolv.conf #定義resolv.conf文件,用來掛載到命名空間中的/etc/resolv.conf
同理,咱們也能夠我新的命名空間定製一些目錄
[root@www ~]# mkdir /tmp/t1 #本文最終會將該目錄掛載到命名空間中的/mnt目錄 [root@www ~]# touch /tmp/t1/egon_test.txt
步驟四:
文件名:newns.c
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <sys/mount.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> /* 定義一個給 clone 用的棧,棧大小1M */ #define STACK_SIZE (1024 * 1024) static char container_stack[STACK_SIZE]; char* const container_args[] = { "/bin/bash", "-l", NULL }; int container_main(void* arg) { printf("Container [%5d] - inside the container!\n", getpid()); sethostname("container",10); /* remount "/proc" to make sure the "top" and "ps" show container's information */ if (mount("proc", "rootfs/proc", "proc", 0, NULL) !=0 ) { perror("proc"); } if (mount("sysfs", "rootfs/sys", "sysfs", 0, NULL)!=0) { perror("sys"); } if (mount("none", "rootfs/tmp", "tmpfs", 0, NULL)!=0) { perror("tmp"); } if (mount("udev", "rootfs/dev", "devtmpfs", 0, NULL)!=0) { perror("dev"); } if (mount("devpts", "rootfs/dev/pts", "devpts", 0, NULL)!=0) { perror("dev/pts"); } if (mount("shm", "rootfs/dev/shm", "tmpfs", 0, NULL)!=0) { perror("dev/shm"); } if (mount("tmpfs", "rootfs/run", "tmpfs", 0, NULL)!=0) { perror("run"); } /* * 模仿Docker的從外向容器裏mount相關的配置文件 * 你能夠查看:/var/lib/docker/containers/<container_id>/目錄, * 你會看到docker的這些文件的。 */ if (mount("conf/hosts", "rootfs/etc/hosts", "none", MS_BIND, NULL)!=0 || mount("conf/hostname", "rootfs/etc/hostname", "none", MS_BIND, NULL)!=0 || mount("conf/resolv.conf", "rootfs/etc/resolv.conf", "none", MS_BIND, NULL)!=0 ) { perror("conf"); } /* 模仿docker run命令中的 -v, --volume=[] 參數乾的事 */ if (mount("/tmp/t1", "rootfs/mnt", "none", MS_BIND, NULL)!=0) { perror("mnt"); } /* chroot 隔離目錄 */ if ( chdir("./rootfs") != 0 || chroot("./") != 0 ){ perror("chdir/chroot"); } execv(container_args[0], container_args); perror("exec1111"); printf("Something's wrong!\n"); return 1; } int main() { printf("Parent [%5d] - start a container!\n", getpid()); int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL); waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0; }
步驟五:
[egon@www ~]$ gcc -o newns newns.c [egon@www ~]$ sudo ./newns #進行新的命名空間 Parent [ 2848] - start a container! Container [ 1] - inside the container! #基於以前所作,咱們已然實現pid隔離 bash-4.2# #chroot進了一個新的命名空間 bash-4.2# pwd #chroot ./rootfs的效果 / bash-4.2# hostname #查看主機名發現實現了主機名隔離 container bash-4.2# ipcs -q #ipc一樣也是隔離的 ------ Message Queues -------- key msqid owner perms used-bytes messages bash-4.2# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 11768 1860 pts/0 S 20:55 0:00 /bin/bash -l root 28 0.0 0.1 35884 1480 pts/0 R+ 20:57 0:00 ps aux bash-4.2# bash-4.2# bash-4.2# bash-4.2# bash-4.2# bash-4.2# bash-4.2# mount proc on /proc type proc (rw,relatime) sysfs on /sys type sysfs (rw,relatime,seclabel) none on /tmp type tmpfs (rw,relatime,seclabel) udev on /dev type devtmpfs (rw,relatime,seclabel,size=490432k,nr_inodes=122608,mode=755) devpts on /dev/pts type devpts (rw,relatime,seclabel,mode=600,ptmxmode=000) shm on /dev/shm type tmpfs (rw,relatime,seclabel) tmpfs on /run type tmpfs (rw,relatime,seclabel) /dev/mapper/centos-root on /etc/hosts type xfs (rw,relatime,seclabel,attr2,inode64,noquota) /dev/mapper/centos-root on /etc/hostname type xfs (rw,relatime,seclabel,attr2,inode64,noquota) /dev/mapper/centos-root on /etc/resolv.conf type xfs (rw,relatime,seclabel,attr2,inode64,noquota) /dev/mapper/centos-root on /mnt type xfs (rw,relatime,seclabel,attr2,inode64,noquota) proc on /proc type proc (rw,relatime) none on /tmp type tmpfs (rw,relatime,seclabel) shm on /dev/shm type tmpfs (rw,relatime,seclabel) tmpfs on /run type tmpfs (rw,relatime,seclabel) /dev/mapper/centos-root on /etc/hosts type xfs (rw,relatime,seclabel,attr2,inode64,noquota) /dev/mapper/centos-root on /etc/hostname type xfs (rw,relatime,seclabel,attr2,inode64,noquota) /dev/mapper/centos-root on /etc/resolv.conf type xfs (rw,relatime,seclabel,attr2,inode64,noquota) /dev/mapper/centos-root on /mnt type xfs (rw,relatime,seclabel,attr2,inode64,noquota) bash-4.2# cat /etc/hostname #驗證步驟三所述 testhostname bash-4.2# cat /etc/hosts #同上 123 bash-4.2# cat /etc/resolv.conf #同上 123 bash-4.2# ls /mnt/ #同上 egon_test.txt
用於隔離網絡資源(/proc/net、IP 地址、網卡、路由等)。後臺進程能夠運行在不一樣命名空間內的相同端口上,用戶還能夠虛擬出一塊網卡。
每一個網絡命名空間都有本身的路由表,它本身的iptables設置提供nat和過濾。Linux網絡命名空間還提供了在網絡命名空間內運行進程的功能。
同進程 ID 同樣,用戶 ID 和組 ID 在命名空間內外是不同的,而且在不一樣命名空間內能夠存在相同的 ID。
參考連接:
https://lwn.net/Articles/531114/
http://www.opencloudblog.com/?p=42
http://os.51cto.com/art/201609/517640.htm
http://os.51cto.com/art/201609/517641.htm