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






























