每個優(yōu)秀的容器平臺都應(yīng)該使用命名空間和控制組技術(shù)來構(gòu)建容器。最佳的容器平臺還會集成其他容器安全技術(shù),例如系統(tǒng)權(quán)限、強制訪問控制系統(tǒng)(如 SELinux 和 AppArmor)以及安全計算。正如用戶所期望的,Docker 中集成了上述全部安全技術(shù)!
下面主要對 Docker 中用到的主要 Linux 技術(shù)進行簡要介紹。
內(nèi)核命名空間屬于容器中非常核心的一部分! 該技術(shù)能夠?qū)⒉僮飨到y(tǒng)(OS)進行拆分,使一個操作系統(tǒng)看起來像多個互相獨立的操作系統(tǒng)一樣。
這種技術(shù)可以用來做一些非??岬氖虑椋热缭谙嗤?OS 上運行多個 Web 服務(wù),同時還不存在端口沖突的問題。該技術(shù)還允許多個應(yīng)用運行在相同 OS 上并且不存在競爭,同時還能共享配置文件以及類庫。
舉兩個簡單的例子。
用戶可以在相同的 OS 上運行多個 Web 服務(wù),每個端口都是 443。為了實現(xiàn)該目的,可以將兩個 Web 服務(wù)應(yīng)用分別運行在自己的網(wǎng)絡(luò)命名空間中。這樣可以生效的原因是每個網(wǎng)絡(luò)命名空間都擁有自己的 IP 地址以及對應(yīng)的全部端口。
也可能需要將每個 IP 映射到 Docker 主機的不同端口之上,但是使用 IP 上的哪個端口則無須其他額外配置。
用戶還可以運行多個應(yīng)用,應(yīng)用間共享類庫和配置文件,但是版本可能不同。為了實現(xiàn)該目標(biāo),需要在自己的掛載命名空間中運用每個應(yīng)用程序。這樣做能生效的原因,是每個掛載命名空間內(nèi)都有系統(tǒng)上任意目錄的獨立副本。
下圖展示了一個抽象的例子,兩個應(yīng)用運行在相同的主機上,并且同時使用 443 端口。每個 Web 服務(wù)應(yīng)用都運行在自己的網(wǎng)絡(luò)命名空間之內(nèi)。

Linux Docker 現(xiàn)在利用了下列內(nèi)核命名空間。
? 進程ID(PID)。
? 網(wǎng)絡(luò)(NET)。
? 文件系統(tǒng)/掛載(MNT)。
? 進程內(nèi)通信(IPC)。
? 用戶(USER)。
? UTS。
下面會簡要介紹每種技術(shù)都做了些什么。但重要的是要理解,Docker 容器是由各種命名空間組合而成的。再次強調(diào)一遍,Docker 容器本質(zhì)就是命名空間的有組織集合。
例如,每個容器都由自己的 PID、NET、MNT、IPC、UTS 構(gòu)成,還可能包括 USER 命名空間。這些命名空間有機的組合就是所謂的容器。下圖展示了兩個運行在相同 Linux 主機上的容器。

接下來簡要介紹一下 Docker 是如何使用每個命名空間的。
⒈ 進程 ID 命名空間
Docker 使用 PID 命名空間為每個容器提供互相獨立的容器樹。每個容器都擁有自己的進程樹,意味著每個容器都有自己的 PID 為 1 的進程。PID 命名空間也意味著容器不能看到其他容器的進程樹,或者其所在主機的進程樹。
⒉ 網(wǎng)絡(luò)命名空間
Docker 使用 NET 命名空間為每個容器提供互相隔離的網(wǎng)絡(luò)棧。網(wǎng)絡(luò)棧中包括接口、ID 地址、端口地址以及路由表。例如,每個容器都有自己的 eth0 網(wǎng)絡(luò)接口,并且有自己獨立的 IP 和端口地址。
⒊ 掛載點命名空間
每個容器都有互相隔離的根目錄 /。這意味著每個容器都有自己的 /etc、/var、/dev 等目錄。容器內(nèi)的進程不能訪問 Linux 主機上的目錄,或者其他容器的目錄,只能訪問自己容器的獨立掛載命名空間。
⒋ 進程內(nèi)通信命名空間
Docker 使用 IPC 命名空間在容器內(nèi)提供共享內(nèi)存。IPC 提供的共享內(nèi)存在不同容器間也是互相獨立的。
⒌ 用戶命名空間
Docker 允許用戶使用 USER 命名空間將容器內(nèi)用戶映射到 Linux 主機不同的用戶上。常見的例子就是將容器內(nèi)的 root 用戶映射到 Linux 主機的非 root 用戶上。用戶命名空間對于 Docker 來說還屬于新生事物且非必選項。該部分內(nèi)容在未來可能出現(xiàn)改變。
⒍ UTS 命名空間
Docker 使用 UTS 命名空間為每個容器提供自己的主機名稱。
如下圖所示,容器本質(zhì)就是命名空間的有機組合!

如果說命名空間用于隔離,那么控制組就是用于限額。
假設(shè)容器就是酒店中的房間。每個容器間都是互相獨立的,但是每個房間都共享一部分公共資源,比如供應(yīng)水電、共享游泳池、共享健身、共享早餐餐吧等。
CGroup 允許用戶設(shè)置一些限制(以酒店作為類比)來保證不會存在單一容器占用全部的公共資源,如用光全部水或者吃光早餐餐吧的全部食物。
拋開酒店的例子,在 Docker 的世界中,容器之間是互相隔離的,但卻共享 OS 資源,比如 CPU、RAM 以及硬盤 I/O。CGroup 允許用戶設(shè)置限制,這樣單個容器就不能占用主機全部的 CPU、RAM 或者存儲 I/O 資源了。
以 root 身份運行容器不是什么好主意,root 擁有全部的權(quán)限,因此很危險。但是,如果以非 root 身份在后臺運行容器的話,非 root 用戶缺少權(quán)限,處處受限。所以用戶需要一種技術(shù),能選擇容器運行所需的 root 用戶權(quán)限。了解一下 Capability!
在底層,Linux root 用戶是由許多能力組成的。其中一部分包括以下幾點。
? CAP_CHOWN:允許用戶修改文件所有權(quán)。
? CAP_NET_BIND_SERVICE:允許用戶將socket綁定到系統(tǒng)端口號。
? CAP_SETUID:允許用戶提升進程優(yōu)先級。
? CAP_SYS_BOOT:允許用戶重啟系統(tǒng)。
Docker 采用 Capability 機制來實現(xiàn)用戶在以 root 身份運行容器的同時,還能移除非必須的 root 能力。如果容器運行只需要 root 的綁定系統(tǒng)網(wǎng)絡(luò)端口號的能力,則用戶可以在啟動容器的同時移除全部 root 能力,然后再將 CAP_NET_BIND_SERVICE 能力添加回來。
Docker 采用主流 Linux MAC 技術(shù),例如 AppArmor 以及 SELinux。
基于用戶的 Linux 發(fā)行版本,Docker 對新容器增加了默認的 AppArmor 配置文件。根據(jù) Docker 文檔的描述,默認配置文件提供了“適度的保護,同時還能兼容大部分應(yīng)用”。
Docker 允許用戶在啟動容器的時候不設(shè)置相應(yīng)策略,還允許用戶根據(jù)需求自己配置合適的策略。
Docker 使用過濾模式下的 Seccomp 來限制容器對宿主機內(nèi)核發(fā)起的系統(tǒng)調(diào)用。
按照 Docker 的安全理念,每個新容器都會設(shè)置默認的 Seccomp 配置,文件中設(shè)置了合理的默認值。這樣做是為了在不影響應(yīng)用兼容性的前提下,提供適度的安全保障。
用戶同樣可以自定義 Seccomp 配置,同時也可以通過向 Docker 傳遞指定參數(shù),使 Docker 啟動時不設(shè)置任何 Seccomp 配置。
Docker 基本支持所有的 Linux 重要安全技術(shù),同時對其進行封裝并賦予合理的默認值,這在保證了安全的同時也避免了過多的限制,如下圖所示。

自定義設(shè)置某些安全技術(shù)會非常復(fù)雜,因為這需要用戶深入理解安全技術(shù)的運作原理,同時還要了解 Linux 內(nèi)核的工作機制。希望這些技術(shù)在未來能夠簡化配置的過程,但就現(xiàn)階段而言,使用 Docker 在對安全技術(shù)的封裝中提供的默認值是很不錯的選擇。