docker進行隔離的資源:1、檔案系統;2、網路(Network);3、進程間的通訊;4、針對權限的使用者和使用者群組;5、進程內的PID和宿主機的PID;6、主機名稱與域名等。
本教學操作環境:linux5.9.8系統、docker-1.13.1版、Dell G3電腦。
docker容器的本質是宿主機上的一個程序。
Docker透過namespace實現了資源隔離,透過cgroups實現了資源限制,透過*寫時複製機制(copy-on-write)*實現了高效的文件操作。
namespace 機制提供一個資源隔離方案。
PID,IPC,Network等系統資源不再試全域性的,而是屬於某個特定的Namespace.
每個namespace下的資源對於其他的namespace下的資源是透明的,不可見的。
Linux 核心實現namespace的一個主要目的就是實現輕量級虛擬化(容器)服務,在同一個namespace下的進程可以感知彼此的變化,而對外界的進程一無所知,以達到獨立和隔離的目的。
namespace可以隔離哪些
一個容器要想與其他容器互不干擾需要能夠做到:
#檔案系統需要是被隔離的
網路也是需要被隔離的
進程間的通訊也要被隔離
針對權限,使用者與使用者群組也需要隔離
#進程內的PID也需要與宿主機器中的PID進行隔離
容器也要有自己的主機名稱
有了以上的隔離,我們認為一個容器可以與宿主機和其他容器隔離開的。
剛好Linux 的namespace可以做到這些。
namespace | 隔離內容 | 系統呼叫參數 |
---|---|---|
UTS | 主機名稱與網域名稱 | CLONE_NEWUTS |
#IPC | 訊號量、訊息佇列與共用記憶體 | #CLONE_NEWIPC |
Network | 網路設備、網路堆疊、連接埠等 | CLONE_NEWNET |
PID | 進程編號 | CLONE_NEWPID |
#Mount | 掛載點(檔案系統) | CLONE_NEWNS |
User | 使用者與使用者群組 | CLONE_NEWUSER |
UTS namespace
UTS (UNIX TIme-sharing System) namespace 提供了主機和域名的隔離,這樣每個Docker容器就可以擁有獨立的主機名稱和域名,在網絡上可以被視為一個獨立的節點,而不是宿主機上的一個進程。
Docker中,每個映像基本上都以自己提供的服務名稱來命名hostname,且不會對宿主機產生任何影響。
IPC namespace
進程間通訊(Inter-Process Communication,IPC)設計的IPC資源包括常見的信號量、訊息佇列和共享記憶體。
申請IPC資源就申請了一個全域唯一的32位元ID。
IPCnamespace中包含了系統IPC識別碼以及實作POSIX訊息佇列的檔案系統。
在同一個IPC namespace中的進程彼此可見,不同的namespace中的進程則互不可見。
PID namespace
PID namespace的隔離非常實用,他對進程PID重新編號,即兩個不同namespace下的進程可以擁有相同的PID,每個PID namespace都有自己的計數程式。
核心為所有的PID namespace維護了一個樹狀結構,最頂層的是系統初始時創建的,稱為root namespace。新建立的PIDnamespace稱為child namespace,而原先的PID namespace就是新建立的PID namespace的child namespace,而原來的PID namespace就是新建立的PID namespace的 parent namespace。
透過這種方式,不同的PID namespace會形成=一個層級體系,所屬的父節點可以看到子節點中的進程,並且可以透過訊號等方式對子節點中的進程產生影響。但是子節點確看不到父節點PID namespace中的任何內容。
mount namespace
mount namespace透過隔離檔案系統掛載點對隔離檔案系統提供支援。
隔離後,不同的mount namespace中的檔案結構會改變也互不影響。
network namespace
network namespace主要提供了關於網路資源的隔離,包括網路設備,IPv4,IPv6協定堆疊、IP路由表、防火牆、/proc/ net目錄、/sys/class/net目錄、套接字等。
user namespace
user namespace隔離了安裝相關的識別碼和屬性
namespace的動作
namespace的API包括clone() setns() unshare() 還有/proc下的部分檔案
為了確定隔離的是那些namespace,需要指定以下6個參數的一個或多個| 進行分隔。 6個參數就是上面表中提到的CLONE_NEWUTS、CLONE_NEWIPC、CLONE_NEWPID、CLONE_NEWNET、CLONE_NEWUSER
##clone()
#使用clone() 來建立一個獨立的進程,是最常見的做法,也是Docker使用namespace最基本的方法。int clone(int(*child_func)(void *),void *child_stack,int flags, void *arg);clone() 是 Linux 系統呼叫fork() 的一種更通用的實作方式,可以透過flags來控制使用多少功能。
共有20多種CLONE_*的flag,控制clone進程的方方面面。
/proc/[pid]/ns
使用者可以在/proc/[pid ]/ns檔案下看到指向不同namespace好的檔案。ls -l /proc/10/ns中括號內的為namespace號碼
把/proc/[pid]/ns目錄檔案使用--bind方式掛載也可以達到link的作用
touch ~/utsmount --bind /proc/10/ns/uts ~/uts
setns()
Docker中使用docker exec指令在已經執行的指令執行一個新的指令就需要使用setns() 。 透過setns()系統調用,進程從原來的namespace加入某個已經存在的namespace
通常為了不影響進程的調用者,也為了讓新加入的pid namespace生效,會在setns()函數執行後使用clone() 建立子程序繼續執行指令,讓原先的行程結束運作。
int setns(int fd, in nstype); #fd 表示要加入namespace的文件描述符。是一个指向/proc/[pid]/ns目录的文件描述符,打开目录链接可以获得 #nstype 调用者可以检查fd指向的namespace类型是否符合实际要求,该参数为0则不检查為了把新加入的namespace利用起來,需要引入execve()系列函數,該函數可以執行使用者指令,常用的就是呼叫/bin/bash並接受參數
unshare()
透過unshare() 在原先的進程上namespace隔離 unshare與clone很像,unshare不需要新啟動一個進程,在原有的進程上就可以進行使用。
docker並沒有使用
fork() 系統呼叫
fork並不屬於namespace的APIcgroups是Linux核心提供的一種機制,這個機制可以根據需求把一系列系統任務及其子任務整合(或分隔)到按資源分等級的不同組內,從而為系統資源管理提供一個統一的架構。
cgroups是Linux的另一個強大的核心工具,有了cgroups,不僅可以限制被namespace隔離的資源,還可以為資源設定權重、計算使用量、操控任務(進程或縣城)啟停等。說穿了就是:cgroups可以限制、記錄任務組所使用的實體資源(包括CPU,Memory,IO等),是建構Docker等一系列虛擬化管理工具的基石。
cgroups 的作用
cgroups 為不同使用者層面的資源管理提供了一個統一接口,從單一的資源控製到作業系統層面的虛擬化,cgroups提供了4個功能。
以上是docker對哪些資源進行隔離的詳細內容。更多資訊請關注PHP中文網其他相關文章!