https://lwn.net/Articles/741841/ @文卿

Docker (现在的Moby项目)中集成了很多关于容器相关的操作,而这也带来了一个很大的隐患,因为这些操作都在一个单一的带有root权限的守护进程中运行。而这一担心也反映在了今年KubeCon+CloudNativeCon大会上Dan Walsh的演讲中。Walsh的演讲中提到当前红帽容器团队在做大量的工作来将Docker替换为一系列小组件。他认为当前的Docker违反了长久以来Unix的哲学。 [编辑] The quest to modularize Docker

正如前面文章中所说,基础容器操作命令并不复杂:用户只需要拉取一个镜像,从该镜像创建容器并启动容器。而后用户需要的是构建新的镜像并上传该镜像。目前大多数用户依然使用Docker来完成上述工作。但实际上并不仅仅Docker可以完成上述工作。rkt项目就带来了CRI,OCI,CNI等标准来允许CRI-O或者Docker来与Kubernetes进行交互。

上述标准也促使红帽创建了一些列‘核心工具’比如CRI-O来满足Kubernetes的需要。但是红帽的OpenShift项目需要的工具更多。开发者需要构建容器镜像并推送到镜像服务中心。

事实也证明了目前已经有很多工具可以用来构建容器。除了Docker外,来自Sysdig的Michael Ducy在演讲中提到了8个镜像构建工具。而这还不是全部。Ducy指出一个理想的镜像构建工具应该可以反复构建出最小依赖镜像。这一镜像没有包含操作系统,仅仅是应用和运行应用需要的依赖。Ducy认为Distroless,Smith和Source-to-Image这些工具都是非常好的镜像构建工具。他称这些镜像为“微容器”。

一个可反复构建容器指用户可以多次构建镜像并且每次构建的镜像是相同的。Ducy指出这需要一个“声明式”的解决方案。这里他举了Ansible Container,Habitat,nixos-container和Smith的例子。但是我们不得不提到的是Docker的BuildKit和红帽Atomic项目的Buildah。 [编辑] Building Containers with Buildah

Buildah项目显然并没有遵从Ducy上述的规则。取而代之的是构建一个可以被配置管理工具使用的简单工具。用户可以使用cp来完成文件的安装,也可以使用Ansible或者Puppet,甚至是APT或者pip来安装容器中需要的内容。这就是为什么通过buildah构建容器看起来就像是在容器中使用shell命令和make命令。

pull a base image, equivalent to a Dockerfile’s FROM command

buildah from redhat

mount the base image to work on it

crt=$(buildah mount) cp foo $crt make install DESTDIR=$crt

then make a snapshot

buildah commit

这样做的一个好处是可以真正构建出一个非常精简的容器镜像,因为用户在构建镜像过程中不需要安装任何依赖。通常在构建镜像时,目标应用的构建需要容器内部安装相应的依赖。比如从源代码构建一个应用就需要容器中安装编译器。大量容器中会附带ps或者bash命令,这些命令对于微容器其实是多余的。而开发者往往会忘记从镜像中删除这类多余的依赖。这也就带来了额外的开销和可能的安全隐患。

Buildah这种构建方式使得用户构建镜像是在非root权限下,这带来了一系列麻烦,比如mount命令需要CAP_SYS_ADMIN权限,无法在容器中构建容器等等。

手动逐步提交允许用户细粒度的控制创建容器的快照。在Dockerfile中每一行都会创建一个新的快照。借助Buildah则可以控制快照的创建,从而隔离敏感数据。

因为Docker采用了非标准的镜像格式,Buildah除了能构建标准OCI镜像外,还可以通过build-using-dockerfile或者buildah bud来解析Dockerfile。除此以外,buildah还支持enter命令来查看镜像并通过run命令直接启动容器。而完成上述这些操作仅需要一个标准runc工具。

Ducy批评Buildah没有遵循声明方式,因此镜像的构建不可重复。比如构建过程中执行shell命令就可能造成各种不一致的结果。Walsh则认为已有的配置管理工具可以基于Buildah之上,这正是践行了经典的UNIX哲学中的"分离"原则(提供机制而非策略)。

在写作本文时,Buildah还处在beta版本。而红帽正尝试将其集成到OpenShift。从试用的情况看,Buildah工作的非常稳定。
[编辑] Replacing the rest of the Docker command-line

Walsh在演讲中提到的另一个工具是libpod。名字源于Kubernetes中的"pod"。

libpod中包含的kpod命令可以说是一个docker命令的翻版。kpod中重新实现了大量的docker命令,比如列出运行的容器(kpod ps)或者查看镜像(kpod images)。这里的对照表列出了当前kpod支持的所有docker命令。

kpod提供的一个实用的功能是可以直接启动容器。这也就意味着容器的启动并不需要经过dockerd。我们可以通过systemd来启动容器。这对于一些应用是非常友好的。但是目前kpod还缺少一些非常基本的功能,比如网络。

上述的所有工具都是针对本地容器的,而用户会使用push命令来上传镜像。skopeo项目可以完成很多与镜像相关的操作。该项目的初衷是在线查看容器镜像服务中的镜像内容而无需下载。但是Docker拒绝合并这组补丁,而是建议单独创建一个工具来完成这些工作,这也导致了skopeo项目的诞生。由于许多项目都需要这一功能,因此skopeo的代码被用在了很多项目中,比如Pivotal,container-diff,kpod push,buildah push等。

kpod命令并没有和Kubernetes绑定,因此命令的名字在将来会修改。事实上在这篇文章撰写过程中,命令就已经修改为https://github.com/projectatomic/libpod/blob/master/docs/podman.1.md podman]。此外团队计划实现更多pod一级的命令。

上面提到的这些工具都还在开发过程中,并没有任何工具能够直接使用到生产环境中。如果想使用其中的工具,最简单的方法就是直接通过源代码进行编译。也许在不久的将来我们能够直接通过包管理工具来安装这些工具。