向Docker告別的時候到了

碼農譯站發表於2020-12-28

在容器的遠古時期(大約4年前),Docker是容器遊戲中僅有的參與者。但是現在情況不一樣了,Docker不再是唯一的一個了,只是另一個容器引擎而已。Docker允許我們構建,執行,拉取,上傳,檢視容器映象,但是對每一項任務都有其他可以比Docker做得更好的工具。因此,讓我們看看現在的情況,解除安裝(只是可能)並且忘記Docker的全部資訊。

不過,為什麼不使用Docker?

如果你是一名Docker的老鳥,我想即使考慮使用不同的工具,也需要一些說服自己的理由。那麼,理由就在這裡:

首先,Docker是一個嘗試做所有事情的工具,通常來說這並不是最好的方式。大多數情況下,最好選擇一種專門只做一件事,並且能把這件事做得非常好的工具。

如果你擔心切換到不同的工具後,不得不學著使用不同的CLI,不同的API或者通常不太一樣的概念,那麼這不會成為一個問題。選擇接下來文章中的任何工具都是完全無縫的,因為它們(包括Docker)都遵循了OCI(Open Container Initiative)的相同規範。這個規範中包含了容器的執行時,分散式,映象,涵蓋了容器需要的所有特性。

由於OCI的存在,你可以選擇一套最適合你的工具集,與此同時,仍然可以使用相同的API和CLI命令,就像Docker一樣。

所以,如果你想嘗試新的工具,接下來我們比較一下Docker和它的競爭對手都有哪些優缺點和特性,看看是不是有必要考慮放棄Docker,而使用一些新的亮瞎眼的工具。

容器引擎

 在比較Docker和其他亮瞎眼的工具時,我們需要將其分解為元件。首先我們要討論的是容器引擎。容器引擎是一種可以提供操作映象和容器使用者介面的一種工具,有了它你就不需要處理SECCOMP機制或者SELinux策略等一系列的事情。它的工作還包括從遠端倉庫中拉取映象並將其擴充套件到硬碟。它看起來也執行容器,但實際上它的工作是建立容器清單和帶有映象層的目錄。然後將他們傳遞到容器執行時,就像runc或crun(稍後討論)。

現在有許多可用的容器引擎,但Docker眾多的競爭中最突出的是Red Hat開發的Podman。和Docker不同的是,Podman不需要守護程式來執行,也不需要root許可權,這是Docker長期以來關注的問題。Podman不僅可以執行容器,還可以執行pod。如果你不熟悉pod的概念,pod就是Kubernetes中的最小可部署計算單元。它由一個或多個容器組成執行任務。這使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命令,你只需要將docker重新命名為podman即可。

除了Docker和Podman,還有其他的容器引擎,但我認為它們都是窮途末路,或者不適合本地開發。但想要有一個完整的畫面,我們至少要提到還有哪些:

  1. LXD——LXD是LXC(Linux容器)的容器管理器(守護程式)。該工具提供了執行系統容器的能力,這些系統容器提供了類似於VM的容器環境。它位於非常狹窄的空間中,沒有許多使用者,所以除非有具體的用例,你最好使用Docker或Podman。
  2. CRI-O——當你通過google查詢什麼是CRI-O時,你可能會發現它被描述成容器引擎。不過,它實際上是容器執行時。它是專門為Kubernetes執行時而構建的,而不是使用者使用的終端。
  3. rkt——rkt是由CoreOS開發的容器引擎。這裡提到了這個專案僅僅是為了畫面的完整性,因為這個專案已經結束了,開發也停止了,因此它不該被使用。

構建映象

對於容器引擎來說,Docker只有一種選擇。但是當構建映象時,我們可以有很多的選擇。

首先介紹一下Buildah。這是Red Hat開發的另一個工具,它和Podman的組合更配。如果你已經安裝了Podman,可能會注意到Podman的構建命令實際上是偽裝的Buildah,因為它的二進位制檔案包含在Podman中。

作為它的特性,它和Padman有相同的路線——它是不需要守護程式和root許可權,併產生OCI的映象,所以它保證你的映象能與Docker構建相同的方式執行。它還能從Dockerfile或者Containerfile構建映象,這是兩種相同的東西,但是有不同的名稱。除此之外,Buildah還對映象層提供了更好的控制,允許你在單一層中提交更改。但與Docker的區別是,由Buildah構建的映象是屬於特定使用者的,因此你可以只列出來自己構建的映象。

現在考慮到Buildah已經包含在了Podman CLI中,你可能會問,為什麼還要使用單獨的Buildah CLI?Buildah CLI是Podman中包含的命令的超集,所以你可能不需要接觸Buildah CLI,通過使用它你可能會發現一些額外的特性。

綜上所述,我們來看一個演示:

~ $ 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中是等價的。

下一個要介紹的是谷歌的Kaniko。Kaniko也是從Dockerfile構建映象,與Buildah類似,它也不需要守護程式。Kaniko與Buildah的主要區別是Kaniko更專注於在Kubernetes中構建映象。

Kaniko意味著通過使用gcr.io/kaniko-project/executor可以作為映象被執行,這對於Kubernetes來說是有意義的,但是對於本地構建來說不太方便,並且在一定程度上違背了目的,因為你需要使用Docker來執行Kaniko映象來構建你的映象。這等於說,如果你在尋找在Kubernetes叢集中構建映象的工具,那麼Kaniko可能是一個不錯的選擇,因為它是不需要守護程式,而且更安全。

以我的個人經驗來看——我在Kubernetes/OpenShift叢集中使用了Kaniko和Buildah來構建映象,都能很好地完成工作,但在使用Kaniko時,我遇到了一些將映象匯入registry時的隨機構建崩潰和失敗。

第三個競爭者是buildkit,也被稱為是下一代docker。它是Moby專案的一部分,可以使用DOCKER_BUILDKIT=1 啟用Docker。那麼,這到底會帶來什麼呢?它引入了許多改進和很牛的特性,包括並行構建步驟、跳過未使用階段、更好的增量構建和無root構建。但另一方面,它仍然需要執行守護程式。所以,如果你不想擺脫Docker,但是想要一些新的特性和更好的改進,那麼使用buildkit可能是最好的選擇。

這裡我們也有一些值得被提到的具體用例,但它們並不是我的首選:

  1. Source-To-Image (S2I) 是一個不使用Dockerfile直接從原始碼構建映象的工具包。這個工具在簡單的、預期的場景和工作流中工作得很好,但是如果你需要很多的定製,或者專案沒有預期的佈局,那麼它很快就會變得很煩人和笨拙。如果你對Docker還不是很有信心,或者在OpenShift叢集上構建映像,你可能會考慮使用S2I,因為使用S2I構建是一個內建特性。
  2. Jib是谷歌開發的另一個工具,專門用於構建Java映象。它包括Maven和Gradle外掛,可以輕鬆地構建映象,而不會干擾dockerfile。
  3. 最後但並非不重要的是Bazel,它是谷歌的另另另另一個工具。它不僅用於構建容器映象,而是一個完整的構建系統。如果你只是想構建一個映象,那麼鑽研Bazel可能有點過頭,但絕對是一個很好的學習體驗,所以如果你願意,rules_docker部分是一個很好的起點。

容器執行時

最後一個難題是容器執行時,它負責執行容器。容器執行時是整個容器生命週期的一部分,除非你對su速度,安全有非常具體的要求,否則你可能不會修改它。所以,如果讀到這裡你覺得厭倦了,那麼你可以跳過這一部分。另一方面,如果你只是想知道有哪些選擇,具體如下:

runc是基於OCI容器執行時規範而建立的最流行的容器執行時。Docker(通過containerd)、Podman和CRI-O都在使用它,所以幾乎所有東西都希望使用LXD。可以新增的東西不多,它是所有東西的預設值,所以即使你在閱讀本文後放棄Docker,也很可能仍然會使用runc。

runc的另一種類似的方法是crun。這是Red Hat開發的工具,完全用C編寫(runc是用Go編寫的)。這使得它比runc更快,記憶體效率更高。考慮到它也是OCI相容的執行時,如果你想自檢的話,應該可以很容易地切換到它。儘管它現在還不是很流行,但在預覽版中,它將作為一個替代OCI執行時的RHEL 8.3版本,考慮到它是Red Hat的產品,我們可能最終會看到它作為Podman或CRI-O的預設版本。

說到CRI-O。前面我說過,CRI-O不是一個真正的容器引擎,而是容器執行時。這是因為CRI-O不包括像推送映象這樣的特性,而這正是你所期望的容器引擎特性。作為執行時的CRI-O在內部使用runc執行容器。你不應該在機器上嘗試使用這個執行時,因為它被構建為用於Kubernetes節點上的執行時,您可以看到它被描述為“Kubernetes需要的所有執行時,僅此而已”。因此,除非您正在設定Kubernetes叢集(或OpenShift叢集),否則您可能不應該接觸這個。

本節的最後一個內容是containerd,它是CNCF的一個畢業專案。它是一個守護程式,充當各種容器執行時和作業系統的API。在後臺它依賴於runc,是Docker引擎的預設執行時。它也被谷歌Kubernetes引擎(GKE)和IBM Kubernetes服務(IKS)使用。它是Kubernetes容器執行時介面的一個實現(與CRI-O相同),因此它是Kubernetes叢集執行時的一個很好的候選物件。

映象檢測和分散式

容器棧的最後一部分是影像的檢測與分散式。這有效地替代了docker檢查,還增加了遠端registry之間複製/映象映象的能力。

這裡我要提到的唯一可以完成這些任務的工具是Skopeo。它由Red Hat製作,是Buildah, Podman和CRI-O的配套工具。除了我們都從Docker中知道的基本的skopeo檢查之外,skopeo還能夠使用skopeo copy複製映象,它允許您在遠端registry之間映象映像,而無需首先將它們拉到本地registry。如果您使用本地registry,此功能也可以作為拉取/下載。

另外,我還想提一下Dive,這是一個檢查、探索和分析映象的工具。它對使用者更友好一些,提供了更可讀的輸出,可以更深入地挖掘你的映象,並分析和衡量其效率。它也適合在CI管道中使用,它可以測量你的映象是否“足夠高效”,或者換句話說——它是否浪費了太多空間。

結論

本文的目的並不是要說服你完全拋棄Docker,而是向您你展示構建、執行、管理和分發容器及其映像的整個場景和所有選項。包括Docker在內的每一種工具都有其優缺點,評估哪一組工具最適合你的工作流和用例是很重要的,我希望本文能在這方面幫助你。

 歡迎關注我的公眾號,如果你有喜歡的外文技術文章,可以通過公眾號留言推薦給我。

 

原文連結:https://dev.to/martinheinz/it-s-time-to-say-goodbye-to-docker-386h

相關文章