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() 來建立一個獨立namespace的程序,是最常見的做法,也是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號
如果兩個程序指向的namespace號相同,那麼說明他們在同一個namespace
設定link的作用是,即便該namespace下的所有程序都已經結束,這個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的API
cgroups是Linux核心提供的一種機制,這種機制可以根據需求把一系列系統任務及其子任務整合(或分隔)到按資源分等級的不同組內,從而為系統資源管理提供一個統一的框架。
cgroups是Linux的另外一個強大的核心工具,有了cgroups,不僅可以限制被namespace隔離起來的資源,還可以為資源設定權重、計算使用量、操控任務(程序或縣城)啟停等。說白了就是:cgroups可以限制、記錄任務組所使用的物理資源(包括CPU,Memory,IO等),是構建Docker等一系列虛擬化管理工具的基石。
cgroups 的作用
cgroups 為不同使用者層面的資源管理提供了一個統一介面,從單個的資源控制到作業系統層面的虛擬化,cgroups提供了4大功能。
推薦學習:《》
以上就是docker對哪些資源進行隔離的詳細內容,更多請關注TW511.COM其它相關文章!