Docker並非惟一的容器化工具,可能還有更好的選擇……python
在容器的早期時代(其實更像是4年前),Docker是容器遊戲中惟一的玩家。但如今狀況已經不同了,Docker再也不是惟一的一個,而只是其中一個容器引擎而已。Docker容許咱們構建、運行、拉、推或檢查容器鏡像,然而對於每一項任務,都有其餘的替代工具,甚至可能比Docker作得還要好。因此,讓咱們探索一下,而後再卸載(只是可能),直至徹底忘記Docker……linux
若是你已經使用Docker很長時間了,估計要真正說服你去考慮其餘工具,得先提供些依據。nginx
首先,Docker是一個單體工具。它嘗試去涵蓋全部的功能,一般這並非最佳實踐。大多數狀況下,咱們都是隻選擇一種專門的工具,它只作一件事,而且作得很是好,很是精。docker
若是懼怕切換到不一樣的工具集是由於將不得不學習使用不一樣的CLI、API或者說不一樣的概念,那麼這不會是一個問題。本文中展現的任何工具均可以是徹底無縫的,由於它們(包括Docker)都遵循OCI (Open Container Initiative)下的相同規範。它們包含了容器運行時、容器分發和容器鏡像的規範,其中涵蓋了使用容器所需的全部特性。安全
有了OCI,你能夠選擇一套最符合你需求的工具,同時你仍然能夠享受跟Docker同樣使用相同的API和CLI命令。ide
因此,若是你願意嘗試新的工具,那麼讓咱們比較一下Docker和它的競爭對手的優缺點和特性,看看是否有必要考慮放棄Docker,使用一些新的閃亮的工具。工具
在比較Docker和其餘工具時,咱們須要將其分解爲組件,首先咱們先討論一下容器引擎。Container Engine是一種工具,它爲處理鏡像和容器提供用戶界面,這樣就沒必要處理SECCOMP規則或SELinux策略之類的事情。它的工做還包括從遠程倉庫提取鏡像並將其擴展到磁盤。它看起來也是運行容器,但實際上它的工做是建立容器清單和帶有鏡像層的目錄。而後它將它們傳遞到容器運行時,如runC或Crun(稍後咱們將討論這一點)。佈局
目前已經有許多容器引擎,但Docker最突出的競爭對手是由紅帽開發的Podman。與Docker不一樣,Podman不須要Daemon來運行,也不須要root特權,這是Docker長期以來一直關注的問題。基於它的名字,Podman不只能夠運行容器,還能夠運行pods。若是你不熟悉pods的概念,其實,簡單的歸納就是,Pod是Kubernetes的最小計算單元。它由一個或多個容器(主容器和執行支持任務的Sidecar)組成,這使得Podman用戶之後更容易將他們的工做負載遷移到Kubernetes。所以,做爲一個簡單的演示,這是如何在一個Pod中運行兩個容器:學習
\~ \$ podman pod create --name mypod \~ \$ podman pod list POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID 211eaecd307b mypod Running 2 minutes ago 1 a901868616a5 \~ \$ podman run -d --pod mypod nginx # First container \~ \$ podman run -d --pod mypod nginx # Second container \~ \$ podman ps -a --pod CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD POD NAME 3b27d9eaa35c docker.io/library/nginx:latest nginx -g daemon o... 2 seconds ago Up 1 second ago brave\_ritchie 211eaecd307b mypod d638ac011412 docker.io/library/nginx:latest nginx -g daemon o... 5 minutes ago Up 5 minutes ago cool\_albattani 211eaecd307b mypod a901868616a5 k8s.gcr.io/pause:3.2 6 minutes ago Up 5 minutes ago 211eaecd307b-infra 211eaecd307b mypod
最後,Podman提供了與Docker徹底相同的CLI命令,所以只需執行alias docker = podman並裝做什麼都沒有改變。測試
除了Docker和Podman以外,還有其餘的容器引擎,但我我的認爲它們都是沒什麼出路的技術,或者都不太適合本地開發和使用。可是,要全面瞭解,至少要看一下其中的內容:
LXD——LXC (Linux Containers)是一個容器管理器(守護進程)。該工具提供了運行系統容器的能力,這些系統容器提供了更相似於VM的容器環境。它位於很是狹窄的空間,沒什麼用戶,因此除非你有很是具體的實例,不然最好仍是使用Docker或Podman。
CRI-O——當你Google什麼是CRI-O你可能會發現它被描述爲容器引擎。不過,實際上它只是容器運行時。其實它既不是引擎,也不適合「正常」使用。個人意思是,它是專門爲Kubernetes運行時(CRI)而構建的,而不是爲最終用戶使用的。
對於容器引擎來講,通常都只選擇Docker。可是,當涉及到構建鏡像時,選擇的餘地仍是比較多的。
首先,介紹一下Buildah。Buildah是紅帽開發的另外一個工具,它與Podman配合使用至關合適。若是已經安裝了Podman,你可能會注意到podman build子命令,它實際上只是假裝的Buildah,由於它的二進制文件已經包含在Podman裏。
至於它的特性,它遵循了與Podman相同的路線——無守護程序和無根的,並遵循OCI的鏡像標準,因此它能保證所構建的鏡像和Docker構建的是同樣的。它還可以從Dockerfile或更恰當的命名Containerfile來構建鏡像,Dockerfile和Containerfile都是相同的,只是命名的區別。除此以外,Buildah還對鏡像層提供了更精細的控制,容許在單層中提交更多變動。惟一的例外是(在我看來)與Docker的區別是,由Buildah構建的鏡像是基於用戶的,所以用戶能夠只列出本身構建的鏡像。
那麼,考慮到Buildah已經包含在Podman CLI中,你們可能會問,爲何還要使用單獨的Buildah CLI?Buildah CLI是podman build中包含的命令的超集,因此基本不須要單獨接觸Buildah CLI,可是經過使用它,你可能還會發現一些額外有用的特性(有關podman build和buildah之間的差別的細節,請參閱這個文章[1])。
如今,咱們來看看一個演示:
\~ \$ buildah bud -f Dockerfile . \~ \$ buildah from alpine:latest # Create starting container - equivalent to "FROM alpine:latest" Getting image source signatures Copying blob df20fa9351a1 done Copying config a24bb40132 done Writing manifest to image destination Storing signatures alpine-working-container # Name of the temporary container \~ \$ buildah run alpine-working-container -- apk add --update --no-cache python3 # equivalent to "RUN apk add --update --no-cache python3" fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86\_64/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86\_64/APKINDEX.tar.gz ... \~ \$ buildah commit alpine-working-container my-final-image # Create final image Getting image source signatures Copying blob 50644c29ef5a skipped: already exists Copying blob 362b9ae56246 done Copying config 1ff90ec2e2 done Writing manifest to image destination Storing signatures 1ff90ec2e26e7c0a6b45b2c62901956d0eda138fa6093d8cbb29a88f6b95124c \~ # buildah images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/my-final-image latest 1ff90ec2e26e 22 seconds ago 51.4 MB
從上面的腳本能夠看到,咱們能夠只用buildah bud構建鏡像,bud表明使用Dockerfile構建,可是你還可使用更多Buildahs的腳本:from,run和copy,這些命令對應命令Dockerfile的(FROM image,RUN…,COPY…)。
下一個是谷歌的Kaniko。Kaniko也是從Dockerfile構建容器鏡像,跟Buildah相似,也不須要守護進程。與Buildah的主要區別在於,Kaniko更專一於在Kubernetes中構建鏡像。
Kaniko使用gcr.io/ Kaniko -project/executor做爲鏡像運行。這對於Kubernetes來講是行得通的,可是對於本地構建來講不是很方便,而且在某種程度上違背了它的初衷,由於咱們得先使用Docker來運行Kaniko鏡像,而後再去構建鏡像。也就是說,若是正在爲Kubernetes集羣中構建鏡像的工具進行選型(例如在CI/CD Pipeline中),那麼Kaniko多是一個不錯的選擇,由於它是無守護程序的,並且(可能)更安全。
從我我的的經驗來看——我在Kubernetes/OpenShift集羣中使用了Kaniko和Buildah來構建鏡像,我認爲二者都能很好地完成任務,但在使用Kaniko時,我看到了一些將鏡像導入倉庫時的,會有隨機構建崩潰和失敗的狀況。
第三個競爭者是Buildkit,也能夠稱爲下一代的Docker build。它是Moby項目的一部分。在Docker裏可使用DOCKER_BUILDKIT=1 Docker build…做爲實驗特性進行啓用。那麼,它的核心價值到底有哪些?它引入了許多改進和炫酷的特性,包括並行構建、跳過未使用的階段、更好的增量構建和無根構建。然而另外一方面,它仍然須要運行守護進程(buildkitd)才能運行。因此,若是你不想擺脫Docker,可是想要一些新的特性和更好的改進,那麼使用Buildkit多是最好的選擇。
和前面同樣,這裏咱們也還有一些「光鮮亮麗的產品」,它們也都有很是具體的場景,雖然並非咱們的首選:
Source-To-Image(S2I)是一個不須要Dockerfile直接從源代碼構建鏡像的工具包。這個工具在簡單的、預期的場景和工做流中運行的很好,可是若是有太多的定製,或者該項目沒有預期的佈局,你很快就會以爲這個工具很煩人和笨拙。若是你對Docker還不是頗有信心,或者若是在OpenShift集羣上構建鏡像,那麼你能夠嘗試考慮一下使用S2I,由於使用S2I構建是一個內置特性。
Jib是谷歌的另外一個工具,專門用於構建Java鏡像。它包括Maven和Gradle插件,能夠輕鬆地構建鏡像,而不會干擾Dockerfile。
最後一個大塊兒是容器運行時,它負責運行容器。容器運行時是整個容器生命週期/棧的一部分,除非你對速度、安全性等有一些很是具體的要求,不然通常是不須要對其進行干擾。因此,若是讀者看到這裏已經厭倦,那麼能夠跳過這一部分。若是不是,那麼有關容器運行時的選擇,以下:
runC是基於OCI容器運行時規範建立的,且最流行的容器運行時。Docker(經過containerd)、Podman和crio使用它,因此幾乎全部東西都依賴於LXD。它幾乎是全部產品/工具的默認首選項,因此即便你在閱讀本文後放棄Docker,但你仍然會用到runC。
runC的另外一款替代方產品爲Crun,名稱相似(容易混淆)。這是Red Hat開發的工具,徹底用C編寫(runC是用Go編寫的)。這使得它比runC更快,內存效率更高。考慮到它也是OCI兼容的運行時。因此,若是你想作個測試,切換起來很容易。儘管它如今還不是很流行,但在RHEL 8.3技術預覽版中,它將做爲一個替代OCI運行時,同時,考慮到它是紅帽的產品,咱們可能最終會看到它會成爲Podman或CRI-O的默認首選項。
說到CRI-O。前面我說過,CRI-O實際上不是一個容器引擎,而是容器運行時。這是由於CRI-O不包括好比推送鏡像這樣的特性,而這正是容器引擎的特性。做爲運行時的CRI-O在內部使用runC運行容器。一般狀況下不須要在單機嘗試這個工具,由於它被構建爲用於Kubernetes節點上的運行時,能夠看到它被描述爲「Kubernetes須要的全部運行時,僅此而已」。所以,除非你正在設置Kubernetes集羣(或OpenShift集羣——CRI-O已是默認首選項了),不然不大可能會接觸到這個。
本節的最後一個內容是containerd,它是CNCF的一個畢業的項目。它是一個守護進程,充當各類容器運行時和操做系統的API。在後臺,它依賴於runC,是Docker引擎的默認運行時。谷歌Kubernetes引擎(GKE)和IBM Kubernetes服務(IKS)也在使用。它是Kubernetes容器運行時接口的一個部署(與CRI-O相同),所以它是Kubernetes集羣運行時的一個很好的備選項。
容器棧的最後一部分是鏡像的檢測與分發。這有效地替代了docker inspect,還(可選地)增長了遠程鏡像倉庫之間複製/映射鏡像的能力。
這裏惟一要提到的能夠完成這些任務的工具是Skopeo。它由紅帽公司開發,是Buildah,Podman和CRI-O的配套工具。除了咱們都從Docker中知道的基本的skopeo inspect以外,Skopeo還可以使用skopeo copy複製鏡像,它容許你在遠程鏡像倉庫之間映射鏡像,而無需先將它們拉到本地倉庫。若是你使用本地倉庫,此功能也能夠做爲pull/push。
另外,我還想提一下Dive,這是一個檢查、探測和分析鏡像的工具。它對用戶更友好一些,提供了更可讀的輸出,能夠更深刻地探測鏡像,並分析和衡量其效率。它也適合在CI管道中使用,它能夠測量你的鏡像是否「足夠高效」,或者換句話說——它是否浪費了太多空間。
本文的目的並非要說服你們徹底拋棄Docker,而是向你們展現構建、運行、管理和分發容器及其鏡像的整個場景和全部選項。包括Docker在內的每一種工具都有其優缺點,評估哪一組工具最適合你的工做流和場景纔是最重要的,真心但願本文能在這方面幫助到你。
原文連接:https://towardsdatascience.com/its-time-to-say-goodbye-to-docker-5cfec8eff833