Red Hat 的去 Docker 化容器實踐
最近幾年,開源項目 Docker (已更名為Moby) 在容器普及化方面建樹頗多。然而,它的功能特性不斷集中到一個單一、龐大的系統,該系統由具有 root 許可權運行的守護進程 dockerd
管控,這引發了人們的焦慮。對這些焦慮的闡述,具有代表性的是 Red Hat 公司的容器團隊負責人 Dan Walsh 在 KubeCon + CloudNativecon 會議中的演講。Walsh 講述了他的容器團隊目前的工作方向,即使用一系列更小、可協同工作的組件替代 Docker。他的戰鬥口號是「拒絕臃腫的守護進程」,理由是與公認的 Unix 哲學相違背。
Docker 模塊化實踐
就像我們在早期文獻中看到的那樣,容器的基礎操作不複雜:你首先拉取一個容器鏡像,利用該鏡像創建一個容器,最後啟動這個容器。除此之外,你要懂得如何構建鏡像並推送至鏡像倉庫。大多數人在上述這些步驟中使用 Docker,但其實 Docker 並不是唯一的選擇,目前的可替換選擇是 rkt
。rkt 引發了一系列標準的創建,包括運行時標準 CRI,鏡像標準 OCI 及網路標準 CNI 等。遵守這些標準的後端,如 CRI-O 和 Docker,可以與 Kubernetes 為代表的管理軟體協同工作。
這些標準促使 Red Hat 公司開發了一系列實現了部分標準的「核心應用」供 Kubernetes 使用,例如 CRI-O 運行時。但 Kubernetes 提供的功能不足以滿足 Red Hat 公司的 OpenShift 項目所需。開發者可能需要構建容器並推送至鏡像倉庫,實現這些操作需要額外的一整套方案。
事實上,目前市面上已有多種構建容器的工具。來自 Sysdig 公司的 Michael Ducy 在分會場中回顧了 Docker 本身之外的 8 種鏡像構建工具,而這也很可能不是全部。Ducy 將理想的構建工具定義如下:可以用可重現的方式創建最小化鏡像。最小化鏡像並不包含操作系統,只包含應用本身及其依賴。Ducy 認為 Distroless, Smith 及 Source-to-Image 都是很好的工具,可用於構建最小化鏡像。Ducy 將最小化鏡像稱為「微容器」。
可重現鏡像 是指構建多次結果保持不變的鏡像。為達到這個目標,Ducy 表示應該使用「宣告式」而不是「命令式」的方式。考慮到 Ducy 來自 Chef 配置管理工具領域,你應該能理解他的意思。Ducy 給出了符合標準的幾個不錯的實現,包括 Ansible 容器、 Habitat、 nixos-容器和 Simth 等,但你需要了解這些項目對應的編程語言。Ducy 額外指出 Habitat 構建的容器自帶管理功能,如果你已經使用了 systemd、 Docker 或 Kubernetes 等外部管理工具,Habitat 的管理功能可能是冗餘的。除此之外,我們還要提到從 Docker 和 Buildah 項目誕生的新項目 BuildKit, 它是 Red Hat 公司 Atomic 工程的一個組件。
使用 Buildah 構建容器
![[Buildah logo]](/data/attachment/album/201805/10/122437qhminlii9nhbwbbw.png "Buildah logo")
Buildah 名稱顯然來自於 Walsh 風趣的 波士頓口音; 該工具的品牌宣傳中充滿了波士頓風格,例如 logo 使用了波士頓梗犬(如圖所示)。該項目的實現思路與 Ducy 不同:為了構建容器,與其被迫使用宣告式配置管理的方案,不如構建一些簡單工具,結合你最喜歡的配置管理工具使用。這樣你可以如願的使用命令行,例如使用 cp
命令代替 Docker 的自定義指令 COPY
。除此之外,你可以使用如下工具為容器提供內容:1) 配置管理工具,例如Ansible 或 Puppet;2) 操作系統相關或編程語言相關的安裝工具,例如 APT 和 pip; 3) 其它系統。下面展示了基於通用 shell 命令的容器構建場景,其中只需要使用 make
命令即可為容器安裝可執行文件。
# 拉取基礎鏡像, 類似 Dockerfile 中的 FROM 命令
buildah from redhat
# 掛載基礎鏡像, 在其基礎上工作
crt=$(buildah mount)
ap foo $crt
make install DESTDIR=$crt
# 下一步,生成快照
buildah commit
有趣的是,基於這個思路,你可以復用主機環境中的構建工具,無需在鏡像中安裝這些依賴,故可以構建非常微小的鏡像。通常情況下,構建容器鏡像時需要在容器中安裝目標應用的構建依賴。例如,從源碼構建需要容器中有編譯器工具鏈,這是因為構建並不在主機環境進行。大量的容器也包含了 ps
和 bash
這樣的 Unix 命令,對微容器而言其實是多餘的。開發者經常忘記或無法從構建好的容器中移除一些依賴,增加了不必要的開銷和攻擊面。
Buildah 的模塊化方案能夠以非 root 方式進行部分構建;但mount
命令仍然需要 CAP_SYS_ADMIN
,有一個 工單 試圖解決該問題。但 Buildah 與 Docker 都有同樣的限制,即無法在容器內構建容器。對於 Docker,你需要使用「特權」模式運行容器,一些特殊的環境很難滿足這個條件,例如 GitLab 持續集成;即使滿足該條件,配置也特別繁瑣。
手動提交的步驟可以對創建容器快照的時間節點進行細粒度控制。Dockerfile 每一行都會創建一個新的快照;相比而言,Buildah 的提交檢查點都是事先選擇好的,這可以減少不必要的快照並節省磁碟空間。這也有利於隔離私鑰或密碼等敏感信息,避免其出現在公共鏡像中。
Docker 構建的鏡像是非標準的、僅供其自身使用;相比而言,Buildah 提供多種輸出格式,其中包括符合 OCI 標準的鏡像。為向後兼容,Buildah 提供了一個「使用 Dockerfile 構建」的命令,即 buildah bud
, 它可以解析標準的 Dockerfile。Buildah 提供 enter
命令直接查看鏡像內部信息,run
命令啟動一個容器。實現這些功能僅使用了 runc
在內的標準工具,無需在後台運行一個「臃腫的守護進程」。
Ducy 對 Buildah 表示質疑,認為採用非宣告性不利於可重現性。如果允許使用 shell 命令,可能產生很多預想不到的情況;例如,一個 shell 腳本下載了任意的可執行程序,但後續無法追溯文件的來源。shell 命令的執行受環境變數影響,執行結果可能大相徑庭。與基於 shell 的工具相比,Puppet 或 Chef 這樣的配置管理系統在理論上更加可靠,因為它們的設計初衷就是收斂於最終配置;事實上,可以通過配置管理系統調用 shell 命令。但 Walsh 對此提出反駁,認為已有的配置管理工具可以在 Buildah 的基礎上工作,用戶可以選擇是否使用配置管理;這樣更加符合「機制與策略分離」的經典 Unix 哲學。
目前 Buildah 處於測試階段,Red Hat 公司正努力將其集成到 OpenShift。我寫這篇文章時已經測試過 Buildah,它缺少一些文檔,但基本可以穩定運行。儘管在錯誤處理方面仍有待提高,但它確實是一款值得你關注的容器工具。
替換其它 Docker 命令行
Walsh 在其演講中還簡單介紹了 Red hat 公司 正在開發的另一個暫時叫做 libpod 的項目。項目名稱來源於 Kubernetes 中的 「pod」, 在 Kubernetes 中 「pod」 用於分組主機內的容器,分享名字空間等。
Libpod 提供 kpod
命令,用於直接檢查和操作容器存儲。Walsh 分析了該命令發揮作用的場景,例如 dockerd
停止響應或 Kubernetes 集群崩潰。基本上,kpod
獨立地再次實現了 docker
命令行工具。kpod ps
返回運行中的容器列表,kpod images
返回鏡像列表。事實上,命令轉換速查手冊 中給出了每一條 Docker 命令對應的 kpod
命令。
這種模塊化實現的一個好處是,當你使用 kpod run
運行容器時,容器直接作為當前 shell 而不是 dockerd
的子進程啟動。理論上,可以直接使用 systemd 啟動容器,這樣可以消除 dockerd
引入的冗餘。這讓由套接字激活的容器成為可能,但暫時基於 Docker 實現該特性並不容易,即使藉助 Kubernetes 也是如此。但我在測試過程中發現,使用 kpod
啟動的容器有一些基礎功能性缺失,具體而言是網路功能(!),相關實現在活躍開發過程中。
我們最後提到的命令是 push
。雖然上述命令已經足以滿足本地使用容器的需求,但沒有提到遠程倉庫,藉助遠程倉庫開發者可以活躍地進行應用打包協作。倉庫也是持續部署框架的核心組件。skopeo 項目用於填補這個空白,它是另一個 Atomic 成員項目,按其 README
文件描述,「包含容器鏡像及鏡像庫的多種操作」。該項目的設計初衷是,在不用類似 docker pull
那樣實際去下載可能體積龐大的鏡像的前提下,檢查容器鏡像的內容。Docker 拒絕加入 檢查功能,建議通過一個額外的工具實現該功能,這促成了 Skopeo 項目。除了 pull
、push
,Skopeo 現在還可以完成很多其它操作,例如在,不產生本地副本的情況下將鏡像在不同的倉庫中複製和轉換。由於部分功能比較基礎,可供其它項目使用,目前很大一部分 Skopeo 代碼位於一個叫做 containers/image 的基礎庫。Pivotal、 Google 的 container-diff 、kpod push
及 buildah push
都使用了該庫。
kpod
與 Kubernetes 並沒有緊密的聯繫,故未來可能會更換名稱(事實上,在本文刊發過程中,已經更名為 podman
),畢竟 Red Hat 法務部門還沒有明確其名稱。該團隊希望實現更多 pod 級別的命令,這樣可以對多個容器進行操作,有點類似於 docker compose
實現的功能。但在這方面,Kompose 是更好的工具,可以通過 複合 YAML 文件 在 Kubernetes 集群中運行容器。按計劃,我們不會實現類似於 [swarm
] 的 Docker 命令,這部分功能最好由 Kubernetes 本身完成。
目前看來,已經持續數年的 Docker 模塊化努力終將碩果累累。但目前 kpod
處於快速迭代過程中,不太適合用於生產環境,不過那些工具的與眾不同的設計理念讓人很感興趣,而且其中大部分的工具已經可以用於開發環境。目前只能通過編譯源碼的方式安裝 libpod,但最終會提供各個發行版的二進位包。
via: https://anarc.at/blog/2017-12-20-docker-without-docker/
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive