乐趣区

关于docker:向Docker告别的时候到了

在容器的远古期间(大概 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,通过应用它你可能会发现一些额定的个性(无关 Podman 和 Buildah 之间差别的细节,请参阅上面的文章)。

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

~ $ 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 在内的每一种工具都有其优缺点,评估哪一组工具最适宜你的工作流和用例是很重要的,我心愿本文能在这方面帮忙你。

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

退出移动版