這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
【編者的話】 現在一說到“容器”,幾乎所有人首先想到的就是Docker。Docker作為目前最主流的容器標準,掩蓋了許多前輩和後續者的光輝。事實上,Docker既不是第一個容器類產品(OpenVZ、Lxc等都遠遠早於它),也不會是最後一個。今天我們來聊一個最近有點火的新容器標準:AppC。
AppC是 CoreO小型股份有限公司在2014年12月發起的社區項目,旨在設計一種新式的跨平台容器在鏡像格式、運行方式和服務發現機制等方面的標準。
從官方的表態說,這個項目最初誕生的原因是,主流容器工具 Docker 正在從一個單純的容器工具成為自成一體的生態圈。而 Docker 的中心式管理方式(由每個主機上的 Docker -d 後台進程統一控制)對於 Systemd 以及第三方的任務編排工具並不友好(具體原因稍後分析)。
因此 CoreOS 希望設計一種去中心化的、功能更純粹、同時更關注效能和安全的應用程式容器,將諸如日誌管理、容器調度、叢集編排等工作都交給外部工具去完成。
Docker 的發起者是 DotCloud 公司,這個公司原本的業務就是做 PaaS 平台,這也決定了 Docker 的發展方向就是成為一個“大而全”的平台性質的產品。這種做法本身也符合佔市場絕大多數的“福士使用者”希望“一站式解決方案”的訴求。
可以這樣說,兩者本質的出發點和想解決的問題並不相同。因此,希望大家秉著開放和包容的心態來看待 Docker 和 AppC 的比較。而不是抱著選擇“哪一個是最好的容器標準”的目的,因為這個問題可能和“哪個程式設計語言是最好的語言”一樣,只能交給時間去定論。
現在符合 AppC 標準的容器已經有幾款了(都十分的小眾),不可能挨個對比。下面就只以 CoreOS 官方推出的 Rkt 容器作為與 Docker 的比較對象。以下內容都屬個人測試的結果,不代表 Docker 或 CoreOS 任何一方的官方觀點。
由淺入深的說。首先是最容易感覺到的一些差異。
操作命令的方式
可以看到,Docker的所有命令都包含在了 Docker 這一個命令列工具中。
而 Rkt 中與鏡像相關的命令是由 AppC 統一的命令列工具 actool 提供的,而容器本身的操作由各個容器自己提供,例如 rkt。
Docker 的容器停止以後還會被背景 Docker -d 進程記錄,還能夠再次 restart,而 Rkt 的容器裡啟動並執行應用則更像是一個普通的應用,結束了就真的結束了。
另外也能看出,Rkt 提供的功能只是 Docker 的子集,後者在日誌、鏡像、管理方面提供的支援完整很多。
然後,來看一下 Docker 和 Rkt 的一個十分重要的差異。
容器進程運行方式
Rkt 的每個容器進程由 rkt 命令直接 fork 出來。而 Docker 的容器進程是由使用者執行的 Docker 命令列工具發送訊息給背景 Docker -d 進程,由 Docker -d 進程間接 fork 的。這咋看起來沒什麼區別,但是 Docker 的這種方式就給第三方的任務編排工具帶來了一些困擾。
有些進程管理工具,比如 systemd 是通過 cgroup 來控制和跟蹤進程的生命週期的,而 SysV 則是通過進程號和繼承關係來跟蹤進程生命週期。比如說當需要結束一個進程的時候,進程管理工具就會找到相應進程的所有子進程一起結束。
但 Docker 的這種進程運行模型,使得不論是通過進程樹還是 cgroup 樹都無法看出建立容器的 Docker 命令列與容器本身有任何關係。因此許多任務管理工具如果不對 Docker 進程進行特別對待,就無法正常的管理通過 Docker 啟動的容器裡的進程。
看鏡像的結構
Docker 匯出的鏡像是一個 tar 檔案,裡面的內容是分層的。
解壓以後的每一個目錄其實就是鏡像的一層。
Rkt 的鏡像是一個 gzip 檔案,裡面沒有分層,直接就是所有容器中的檔案的打包。
個人覺得分層以後雖然複雜了一點,但能夠複用空間,其實是比較有用的。
最後來看一下 AppC 比較強調的安全性和效能方面。
安全性
Docker 下載一個鏡像,直接 Docker pull 了事,傳輸過程可加密可不加密,Docker 也不會問你是否瞭解這個鏡像的來源。
而 Rkt 預設要求所有傳輸過程加密,並且下載鏡像前使用者必須首先添加對鏡像來源簽名的信任,除非使用者明確指定取消驗證,否則鏡像即使下載了 Rkt 也會拒絕運行它。
容器效能
效能方面,可以從一個側面來說明:構建一個最小的可運行鏡像需要哪些東西。
下面的 hello 這個檔案是一個靜態編譯(無任何非系統庫依賴)的程式,啟動並執行時候會列印一個“Hello World”。
把它放到一個空白的 Docker 鏡像裡面。
運行容器會發現 Docker 提示找不到 Bash。
將同樣的程式放到一個空白的 AppC 鏡像裡面。
運行容器就能夠正常工作。
這一點看出 Docker 在運行容器裡的任何程式的時候,實際上都會先在容器裡面啟動一個 Shell,再由這個 Shell 去容器執行指定的命令。而 Rkt 則是純純的直接運行了指定的程式,相比之下在效能和鏡像內容的“信噪比”上略佔優。
如果對AppC和Rkt容器感興趣,可以參考我在InfoQ的這篇文章:CoreOS那些事之Rkt容器嘗鮮(上)
Q&A
問:關於鏡像的問題是否可以基於本地源來建立?我個人覺得本地源對於企業來說很重要。
答:AppC的鏡像建立方式不太一樣,現在還不支援用編寫Dockerfile這樣的方式建立,而是把檔案放到指定結構的目錄,然後直接用actool工具打包建立。
問:能支援不同的發行版?
答:AppC是跨系統的,只是一個標準。Rkt可以在任意的Linux髮型版使用。
問:Rkt的最小鏡像是?
答:Rkt的最小鏡像可以小到裡面只有一個可執行程式。
問:“信噪比”的概念不是很明白。
答: 內容“信噪比”就是說實際使用者要的檔案和其他輔助檔案的比例。
問:Rkt容器可以起多進程嗎?
答: 和Docker一樣的,入口命令只能一個,裡面可以後台運行多個進程。
問:“但 Docker 的這種進程運行模型,使得不論是通過進程樹還是 cgroup 樹都無法看出建立容器的 Docker 命令列與容器本身有任何關係。因此許多任務管理工具如果不對 Docker 進程進行特別對待,就無法正常的管理通過 Docker 啟動的容器裡的進程。”這裡提到的任務工具對Docker進程特別對待,通常需要怎麼處理,才可以方便使用者的任務工具對Docker啟動容器裡的進程進行管理?
答: 就是說在比如結束容器進程的時候,不能通過啟動容器的命令所在的pid或者cgroup來跟蹤容器內的進程,而要和Docker後台服務進程去取。
問:那Rkt的日誌網路等是怎麼處理的呢?
答: 這個Rkt就撒手不管,讓使用者自己選擇其他工具,比如Kubernetes或者Mesos這些架構都可以用,AppC目的就是做純粹關注容器本身功能(環境隔離)的容器。
問:Rkt運行自己的鏡像和Docker的鏡像有什麼區別嗎?
答:鏡像格式上有些區別,不過其實兩者應該是很容易轉換的,Docker容器到AppC容器轉換的工具已經有了,反轉的還沒有,估計Docker現在自己是主流,也沒打算做這種事情。
問:Rkt有提供Restful的API嗎?
答:沒有,因為要實現Restful API就必需要有一個常駐背景進程,這樣就違背了Rkt做純粹的容器工具,並儘可能的減少對系統入侵性的設計意圖了。
問:感覺 Rkt+CoreOS 和 Docker+Machine/Swarm/Compose 這兩種組合都在做叢集的事情?
答:是的,其實是存在一定競爭關係的。只不過CoreOS覺得Docker越做越複雜,不符合他們的應用情境,就建立了一套,順便改進一些Docker的小毛病。但CoreOS依然會對Docker解決方案繼續提供長期支援。
問:Rkt能使用Docker的鏡像嗎?
答:能,Rkt支援直接下載DockerHub或其他Docker Repo的鏡像,只是下載後會自動轉換成AppC格式儲存到本地。
===========================
以上內容根據2015年5月19日晚群分享內容整理。
分享人林帆,ThoughtWorks 成都 Cloud&DevOps 小組成員,目前主要研究內容是應用程式容器化和CoreOS系統相關領域。近期主要文章有CSDN的《CoreOS實踐指南》系列,InfoQ的《CoreOS那些事》系列,和程式員雜誌2015年5月刊的《Linux容器:Docker vs Rkt》等。DockOne每周都會組織定向的技術分享,歡迎感興趣的同學加我(liyingjiesx)參與。