【Docker】進階之路:(五)Docker引擎
- Docker引擎簡介
- Docker引擎的組件構成
- runc
- containerd
Docker引擎簡介
Docker引擎是用來運行和管理容器的核心部分。Docker首次發布時,Docker 引擎由LXC 和 Docker daemon 兩個核心組件構成。
Docker daemon 是單一的二進制文件,包含諸如 Docker 客戶端、Docker API、容器運行時、鏡像構建等。 LXC 提供了對諸如命名空間(Namespace)和控制組(CGroup)等基礎工具的操作能力,它們是基于 Linux 內核的容器虛擬化技術。
在 Docker 舊版本中,Docker daemon、LXC 和操作系統之間的交互關系。
其中,LXC是基于Linux的,存在對外部工具的嚴重依賴關系,對于Docker的跨平臺目標的實現是個問題。因此,Docker公司開發了名為Libcontainer的自研工具,用于替代LXC。Libcontainer的目標是成為與平臺無關的工具,可基于不同內核為Docker上層提供必要的容器交互功能。在Docker 0.9版本中,Libcontainer取代LXC成為默認的執行驅動。同時,Docker的整體性帶來了越來越多的問題。難于變更、運行越來越慢,這對于Docker生態的發展來說弊大于利。Docker公司意識到了這些問題,開始努力著手拆解這個大而全的Dockerdaemon,并將它模塊化。盡可能地拆解出其中的功能特性,并用小而專的工具來實現它。這些小工具可以是可替換的,也可以被第三方拿去用于構建其他工具。目前,所有容器執行和容器運行時的代碼已經完全從daemon中移除,并重構為小而專的工具。
在改進版本中,基于開放容器計劃,Docker引擎采用了模塊化的設計原則,組件是可以替換的。Docker引擎主要由Docker Client、Docker daemon、containerd、runc組成,共同負責容器的創建和運行。
Docker引擎的組件構成
runc
在 Docker daemon 進程的拆解和重構時,OCI 也正在著手定義兩個容器相關的規范,即鏡像規范和容器運行時規范,兩個規范均于 2017 年 7 月發布了 1.0 版。
Docker 公司參與了這些規范的制定工作,并貢獻了許多代碼。從 Docker 1.11 版本(2016 年初)開始,Docker 引擎盡可能實現了 OCI 的規范。例如,Docker daemon 不再包含任何容器運行時的代碼——所有的容器運行代碼在一個單獨的 OCI 兼容層中實現。默認情況下,Docker 使用 runc 來實現這一點。runc 是 OCI 容器運行時標準的參考實現,如上面圖5-3中的 runc 容器運行時層。runc 項目的目標之一就是與 OCI 規范保持一致。目前 OCI 規范均為 1.0 版本,我們不希望它們頻繁地迭代,畢竟穩定勝于一切。除此之外,Docker 引擎中的 containerd 組件確保了 Docker 鏡像能夠以正確的 OCI Bundle 的格式傳遞給 runc。其實,在 OCI 規范以 1.0 版本正式發布之前,Docker 引擎就已經遵循該規范實現了部分功能。
runc實質上是一個輕量級的、針對Libcontainer進行了包裝的命令行交互工具。Libcontainer取代了早期Docker架構中的LXC。runc的作用是創建容器,而且速度非常快。不過runc是一個CLI包裝器,實質上就是一個獨立的容器運行時工具。因此,直接下載runc或基于源碼編譯二進制文件,即可擁有一個全功能的runc。但runc只是一個基礎工具,并不提供類似Docker引擎所擁有的豐富功能。
有時也將runc所在的架構層稱為OCI層。關于runc的發布信息見GitHub中opencontainers/runc庫的release。
containerd
在對 Docker daemon 的功能進行拆解后,所有的容器執行邏輯被重構到一個新的名為 containerd(發音為 container-dee)的工具中。Containerd的主要任務是容器的生命周期管理,即start | stop | pause | rm … containerd等。它在 Linux 和 Windows 中以 daemon 的方式運行,從 1.11 版本之后 Docker 就開始在 Linux 上使用。
Docker 引擎技術棧中,containerd 位于 daemon 和 runc 所在的 OCI 層之間。Kubernetes 也可以通過 cri-containerd 使用 containerd。
正如Docker 引擎簡介中所述,containerd 最初被設計為輕量級的小型工具,僅用于容器的生命周期管理。然而,隨著時間的推移,它被賦予了更多的功能,例如鏡像管理等。其原因之一是,這樣便于在其他項目中使用containd。例如,在 Kubernetes 中,containerd 就是一個很受歡迎的容器運行時。然而在 Kubernetes項目中,如果 containerd 能夠完成一些諸如 push 和 pull 鏡像這樣的操作就更好了。因此,如今的 containerd 還能夠完成一些除容器生命周期管理之外的操作。不過,所有的額外功能都是模塊化的、可選的,便于自行選擇所需功能。 Kubernetes項目在使用 containerd 時,可以僅包含所需的功能。