在容器的远古期间(大概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 listPOD ID         NAME    STATUS    CREATED         # OF CONTAINERS   INFRA ID211eaecd307b   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 --podCONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS  NAMES               POD           POD NAME3b27d9eaa35c  docker.io/library/nginx:latest  nginx -g daemon o...  2 seconds ago  Up 1 second ago          brave_ritchie       211eaecd307b  mypodd638ac011412  docker.io/library/nginx:latest  nginx -g daemon o...  5 minutes ago  Up 5 minutes ago         cool_albattani      211eaecd307b  mypoda901868616a5  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,通过应用它你可能会发现一些额定的个性(无关Podman和Buildah之间差别的细节,请参阅上面的文章)。

综上所述,咱们来看一个演示:

~ $ buildah bud -f Dockerfile .~ $ buildah from alpine:latest  # Create starting container - equivalent to "FROM alpine:latest"Getting image source signaturesCopying blob df20fa9351a1 done  Copying config a24bb40132 done  Writing manifest to image destinationStoring signaturesalpine-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.gzfetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz...~ $ buildah commit alpine-working-container my-final-image  # Create final imageGetting image source signaturesCopying blob 50644c29ef5a skipped: already exists  Copying blob 362b9ae56246 done  Copying config 1ff90ec2e2 done  Writing manifest to image destinationStoring signatures1ff90ec2e26e7c0a6b45b2c62901956d0eda138fa6093d8cbb29a88f6b95124c~ # buildah imagesREPOSITORY               TAG     IMAGE ID      CREATED         SIZElocalhost/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在内的每一种工具都有其优缺点,评估哪一组工具最适宜你的工作流和用例是很重要的,我心愿本文能在这方面帮忙你。

 欢送关注我的公众号,如果你有喜爱的外文技术文章,能够通过公众号留言举荐给我。