您好,登錄后才能下訂單哦!
Docker通過namespace實現了資源隔離,通過cgroups實現了資源限制,通過寫時復制(copy-on-write)實現了高效的文件操作。
1.namespace資源隔離
namepsace的6項隔離:
namespace |
系統調用參數 |
隔離內容 |
UTS |
CLONE_NEWUTS |
主機名與域名 |
IPC |
CLONE_NEWIPC |
信號量,消息隊列和共享內存 |
PID |
CLONE_NEWPID |
進程編號 |
Network |
CLONE_NEWNET |
網絡設備,網絡棧,端口等 |
Mount |
CLONE_NEWNS |
掛載點(文件系統) |
User |
CLONE_NEWUSER |
用戶和用戶組 |
Linux內核實現namespace的主要目的之一是實現輕量級虛擬化(容器)服務。在同一個namespace下的進程可以感知彼此的變化,而對外界進程一無所知。這樣就可以讓容器中的進程產生錯覺,仿佛自己置身于一個獨立的系統環境中,以達到獨立和隔離的目的。
進行namespace API操作的4種方式
namespace的API包括clone(),setns()以及unshare(),還有/proc下的部分文件。為了確定隔離的到底是哪6項namespace,在使用這些API時,通常需要指定以下6個參數的一個或多個,通過位或操作來實現。
CLONE_NEWUTS,CLONE_NEWIPC,CLONE_NEWPID,CLONE_NEWNET,CLONE_NEWNS,CLONE_NEWUSER.
通過clone()在創建新進程的同時創建namespace
使用clone()來創建一個獨立namespace的進程是最常見的做法,也是Docker使用namespace的最基本的方法,它的調用方式如下。
NAME clone, __clone2 - create a child process SYNOPSIS /* Prototype for the glibc wrapper function */ #include <sched.h> int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
clone()實際上是fork系統調用的一種更通用的實現方式,它可以通過flags來控制使用多少功能。一共有20多種CLONE_*的flag(標志位)參數用來控制clone進程的方方面面(如是否與父進程共享虛擬內存等).
查看/proc/[pid]/ns文件
從3.8版本內核開始,用戶可以在該文件下看到指向不同namespace號的文件:
ls -l /proc/2597/ns total 0 lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 cgroup -> cgroup:[4026531835] lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 ipc -> ipc:[4026531839] lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 mnt -> mnt:[4026531840] lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 net -> net:[4026531957] lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 pid -> pid:[4026531836] lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 user -> user:[4026531837] lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 uts -> uts:[4026531838]
如果2個進程namespace號相同,說明它們在同一個namespace下。
/proc/[pid]/ns里設置這些符號鏈接的另一個作用是,一旦上述鏈接文件被打開,那么就算該namespace下的所有進程都已經結束,這個namespace也會一直存在,后續進程也可以再加進來。在Docker中,通過文件描述符定位和加入一個存在的namespace是最基本的方式。
另外,把/proc/[pid]/ns目錄文件使用--bind方式掛載起來可以直到同樣的作用:
# mount --bind /proc/2454/ns/uts uts
通過setns()加入一個已經存在的namespace
上面提到,在進程都結束的情況下,也可以通過掛載的形式把namespace保留下來,保留namespace的目的是為以后有進程加入做準備。在Docker中,使用docker exec命令在已經運行著的容器中執行一個新命令,就需要用到該方法。通過setns()系統調用,進程從原先的namespace加入某個已經存在的namespace,使用方法如下。通常為了不影響進程的調用者,也為了使新加入的pid namespace生效,會在setns()函數執行后使用clone創建子進程繼續執行命令,讓原先的進程結束。
NAME setns - reassociate thread with a namespace SYNOPSIS #define _GNU_SOURCE /* See feature_test_macros(7) */ #include <sched.h> int setns(int fd, int nstype);
fd = open(argv[1],O_RDONLY); setns(fd,0); execvp(argv[2],&argv[2]);
假設編譯后的程序為"setns-test"
# ./setns-test ~/uts /bin/bash
至此,就可以在新加入的namespace中執行shell命令了。
通過unshare()在原先進程上進行namespace隔離
它與clone()很像,不同的是,unshare()運行在原先的進程上,不需要啟動一個新進程。
NAME unshare - disassociate parts of the process execution context SYNOPSIS #include <sched.h> int unshare(int flags);
調用unshare()的主要作用就是不啟動一個新進程就可以起到隔離的效果,相當跳出原先的namespace進行操作。這樣,就可以在原進程進行一些需要隔離的操作。Linux自帶的unshare命令,就是通過unshare()系統調用實現的。Docker目前并沒有使用這個系統調用。
總結
以上就是本文關于Docker探索namespace詳解的全部內容,希望對大家有所幫助,感興趣的朋友可以繼續參閱本站:淺談Docker安全機制內核安全與容器之間的網絡安全、詳解Docker使用Linux iptables 和 Interfaces管理容器網絡等,有什么問題可以隨時留言,小編會及時回復大家的。感謝朋友們對本站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。