不只有Docker:可選擇的容器化工具還有很多……
本文轉載自公眾號“讀芯術”(ID:AI_Discovery)。
在過去的容器時代(更確切地說是四年前),Docker是容器角逐賽中的唯一參與者。今非昔比,現在的Docker已經不再是唯一,只是業界全景圖中的容器引擎之一。
Docker允許構建、運行、拉取、推送或檢查容器鏡像,但是對于每個任務來說,其他的可替代工具可能比Docker做得更好。因此,我們必須得探討一下現狀,這也許會讓你卸載并完全忘記Docker。
為什么不使用Docker?
對于已經用了很久docker的人,可能需要花費些功夫去說服自己去考慮轉換使用不同的工具。
Docker是一個龐大單一的工具,它嘗試做任何事,但通常沒有用最好的方法去做。我們最好選擇只做一件事,但確實做得很好的專門工具。如果害怕切換不同的工具集,擔心不得不學習使用不同的命令行界面(CLI)、不同的API或通常使用不同的概念,那么現在這將不再是問題。
選擇本文中顯示的任何工具都是完全無縫銜接的,因為它們(包括Docker)都遵循開放容器計劃(OCI)下的相同規范。該計劃包含有關容器運行時、容器分發和容器鏡像的規范,涵蓋了使用容器所需的所有功能。借助OCI,你可以選擇最符合需求的一組工具,與此同時仍然可以使用與Docker相同的API和CLI命令。
因此,如果你愿意嘗試新工具,那么請比較一下Docker及其競爭對手的優勢、劣勢和功能,看看是否有必要考慮放棄Docker,試試某些新工具。
容器引擎
在將Docker與其他任何工具進行比較時,我們需要按組件對其進行分類,并且首先要談的是容器引擎。
容器引擎是一種工具,提供了用于處理圖像和容器的用戶界面,因此不必擔心擾亂SECCOMP規則或SELinux策略。它的工作還包括從遠程存儲庫中提取圖像并將其擴展到磁盤,似乎也在運行容器,但它實際上的工作是創建帶有圖像層的容器清單和目錄,然后將它們傳遞到容器運行時,如runc或crun。
目前有許多可用的容器引擎,Docker最主要的競爭對手是Red Hat開發的Podman。與Docker不同,Podman不需要運行守護進程,也不需要root特權,這是Docker長期以來一直關注的問題。
顧名思義,Podman不僅可以運行容器,還可以運行pods。pod是Kubernetes的最小計算單元。它由一個或多個容器組成,執行支持任務。這使Podman用戶以后可以更輕松地將其工作負載遷移到Kubernetes。以下是如何在單個pod中運行2個容器的方法:
- ~ $ podman podcreate --name mypod
- ~ $ podman podlist
- POD ID NAME STATUS CREATED # OFCONTAINERS INFRA ID
- 211eaecd307b mypod Running 2 minutes ago 1 a901868616a5
- ~ $ podman run -d--pod mypod nginx # Firstcontainer
- ~ $ podman run -d--pod mypod nginx # Secondcontainer
- ~ $ podman ps -a--pod
- CONTAINERID 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
最后,Podman提供了與Docker完全相同的CLI命令,只需執行alias Docker=Podman并假裝沒有任何更改。
除了Docker和Podman,還有其他的容器引擎,但是筆者認為它們都沒有出路,或者都不適合本地開發和使用。具體原因如下:
- LXD——LXD是用于LXC(Linux容器)的容器管理器(守護進程)。這個工具提供了運行系統容器的能力,這些容器提供了更類似于VMs的容器環境。它位于非常狹窄的空間中,用戶不多,所以除非有非常具體的用例,否則最好使用Docker或Podman。
- CRI-O——當搜索什么是CRI-O時,可能會發現它被描述為容器引擎。不過,它實際上是容器運行時。此外,它也不適合“正常”使用。筆者的意思是,它是專門為Kubernetes運行時(CRI)而構建的,而不是供最終用戶使用。
- rkt——rkt(“火箭”)是CoreOS開發的容器引擎。這里提到這個項目只是為了文章的完整性,因為項目結束了,它的開發也停止了,所以趁早別用它。
構建鏡像
容器引擎中,Docker只有一個替換項,但當談到構建鏡像,我們有更多的選擇。
首先來介紹Buildah。Buildah是redhat開發的另一個工具,它可以很好地與Podman配合使用。如果已經安裝了Podman,可能會注意到Podman build子命令,它實際上只是偽裝的Buildah,其二進制文件包含在Podman中。
它的功能遵循與Podman相同的路線,是無守護程序和無根的,并且可以生成OCI兼容的鏡像,可以確保你的鏡像與Docker構建鏡像的運行方式相同。除此之外,Buildah還提供了對圖像層的更精細的控制,允許將許多更改提交到單個層中。與Docker相比,Buildah構建的鏡像是特定于用戶的,因此只能列出自己構建的鏡像。
那么,既然Buildah已經包含在podman CLI中,為什么還要使用單獨的Buildah CLI?原因在于,buildahcli是podman build中包含的命令的超集,可能不需要接觸buildah CLI,但是通過使用它,可能還會發現一些額外有用的特性。
可以看一個小型過程展示:
- ~ $ buildah bud-f Dockerfile .
- ~ $ buildah from alpine:latest # Create starting container - equivalentto "FROM alpine:latest"
- Getting image source signatures
- Copying blobdf20fa9351a1 done
- Copying configa24bb40132 done
- Writing manifest toimage destination
- Storing signatures
- alpine-working-container # Name of the temporary container
- ~ $ buildah runalpine-working-container -- apk add --update --no-cache python3 # equivalent to "RUN apk add--update --no-cache python3"
- fetchhttp://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
- fetchhttp://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
- ...
- ~ $ buildahcommit alpine-working-container my-final-image # Create final image
- Getting image source signatures
- Copying blob50644c29ef5a skipped: already exists
- Copying blob362b9ae56246 done
- Copying config1ff90ec2e2 done
- Writing manifest toimage destination
- Storing signatures
- 1ff90ec2e26e7c0a6b45b2c62901956d0eda138fa6093d8cbb29a88f6b95124c
- ~# buildah images
- REPOSITORY TAG IMAGE ID CREATED SIZE
- localhost/my-final-imagelatest 1ff90ec2e26e 22 seconds ago 51.4 MB
從上面的腳本可知,可以僅使用buildah bud來構建鏡像,其中bud代表使用Dockerfile進行構建,但是還可以使用更多的腳本化方法,通過Buildahs的from、run和copy,這與Dockerfile中的命令等效。
接下來是Google的Kaniko。Kanik也與Dockerfile構建容器鏡像,類似于Buildah,它也不需要守護進程。其與Buildah的主要區別在于,Kaniko更專注于在Kubernetes中構建鏡像。
Kanik使用gcr.io/kaniko-project/executor作為鏡像運行,這對于Kubernetes有意義,但對于本地構建而言并不方便,且無法達到目的,因為需要使用Docker運行Kaniko鏡像來構建新鏡像。
話雖如此,如果正在尋找用于在Kubernetes集群中構建鏡像的工具(例如在CI/CD管道中),無守護進程并且(也許)更安全,Kaniko可能是一個不錯的選擇。
不過,根據筆者的個人經驗,同時使用Kaniko和Buildah在Kubernetes/OpenShift集群中構建鏡像,筆者認為兩者都可以很好地完成工作,但是使用Kaniko時,筆者看到了一些隨機的構建崩潰,并且在將鏡像推送到注冊表時失敗了。
Docker的第三個競爭者是buildkit,也可以稱為下一代docker build。它是Moby項目的一部分(與Docker一樣),可以使用DOCKER_BUILDKIT = 1 dockerbuild作為實驗特性啟用Docker。
它引入了許多改進和功能,包括并行構建步驟、跳過未使用的階段、更好的增量構建和無根構建。但另一方面,它仍然需要運行守護程序(buildkitd)。因此,如果不想擺脫Docker,但是想要一些新功能和不錯的改進,那么使用buildkit可能是理想選擇。
除此之外,還有一些值得一提的內容,但不是筆者的最佳選擇:
- Source-To-Image(S2I)是一個工具包,可直接從源代碼構建鏡像,而無需Dockerfile。該工具非常適合簡單的預期場景和工作流程,但如果不需要太多自定義或項目的布局不理想,那么它很快就會變得笨拙。如果對Docker不太有把握,或者在OpenShift集群上構建鏡像,則可以考慮使用S2I,因為使用S2I進行構建是內置功能。
- Jib是Google的另一種工具,專門用于構建Java鏡像。它包括Maven和Gradle插件,可以輕松構建鏡像而不會擾亂Dockerfile。
- 最后是Bazel,它是Google的另一種工具,不僅用于構建容器鏡像,而且是一個完整的構建系統。如果只想構建鏡像,那么鉆研Bazel可能會有些過頭,但絕對會是一種不錯的學習體驗。
容器運行時
最后一個難題是容器運行時,它負責運行容器。容器運行時是整個容器生命周期/堆棧的一部分,除非對速度、安全性等有非常特定的要求,否則它不會被輕易擾亂。有以下可選工具:
runc是基于OCI容器運行時規范創建的最受歡迎的容器運行時。Docker(通過容器)、Podman和CRI-O使用了它,所以幾乎所有東西都希望使用LXD(它使用LXC)。幾乎所有內容都是默認設置,即使你在閱讀本文后放棄使用Docker,也很可能仍會使用runc。
還有一種類似runc但令人困惑替代方法,名為crun。這是Red Hat開發的工具,完全用C編寫(runc用Go編寫)。這使其比runc更快、更高效。它也是OCI兼容的運行時,如果想自己檢查一下,可以輕松切換到它。雖然目前不太流行,但它將作為RHEL8.3版本中的替代OCI運行時出現在技術預覽中,最終可能會被Podman或CRI-O視為默認的Red Hat產品。
說到CRI-O,之前筆者說過CRI-O并不是容器引擎,而是容器運行時。這是因為CRI-O不包含推送鏡像之類的功能,而這正是你所期望的容器引擎的特性。
作為運行時的CRI-O在內部使用runc來運行容器。該運行時不是應該在計算機上嘗試使用的運行時,因為它是為在Kubernetes節點上用作運行時而構建的,被描述為“所有Kubernetes所需的運行時,僅此而已”。
因此,除非要設置Kubernetes集群(或OpenShift集群——CRI-O已經是默認值),否則別接觸此集群。
最后要講的是容器化,這是云原生計算基金會(CNCF)即將畢業的項目。這是一個守護程序,可充當各種容器運行時和操作系統的API外觀。在后臺,它依賴于runc,是Docker引擎的默認運行時。
GoogleKubernetes Engine(GKE)和IBM Kubernetes Service(IKS)也使用它。它是Kubernetes容器運行時界面(與CRI-O相同)的實現,是Kubernetes集群運行時的理想選擇。
鏡像檢查和分發
容器堆棧的最后一部分是鏡像檢查和分發。這有效地代替了docker inspect,并且(可選地)增加了在遠程注冊表之間復制/鏡像的功能。
唯一可以完成這些任務的工具是Skopeo。它是由Red Hat制造的,并且是Buildah、Podman和CRI-O的隨附工具。除了從Docker知道的基本skopeo inspect外,Skopeo還能夠使用skopeo copy來復制鏡像,這使得可以在遠程注冊表之間制作鏡像,無需先將它們拉到本地注冊表。如果使用本地注冊表,此功能也可以用作拉取/推送。
另外,筆者還想提到一下Dive,它是一種檢查、瀏覽和分析圖像的工具,更加人性化,提供了更具可讀性的輸出,并且可以更深入地挖掘(或潛水,我想)鏡像,并分析和衡量其效率。它也適用于CI管道,可以在其中測量鏡像是否“足夠有效”。
圖源:unsplash
筆者并非想說服你完全放棄使用Docker,而是希望展示所有工具的全景圖以及構建、運行、管理和分發容器及其鏡像的所有選項。包括Docker在內的每種工具都有其優缺點,我們必須評估哪種工具最適合工作流程和用例,這一點很重要。