无需root权限的Buildah工作原理:在非特权环境下构建容器

Buildah 是一个用于构建开放容器倡议 (OCI) 容器镜像的工具和库。
191 位读者喜欢这篇文章。
How Kubernetes is helping Docker blossom

马士基航运。CC SA-BY 4.0

在之前的文章中,包括 无需root权限的 Podman 工作原理是什么?,我谈到了 Podman,它是一个允许用户管理 Pod、容器和容器镜像的工具。

Buildah 是一个用于构建开放容器倡议 (OCI) 容器镜像的工具和库,它与 Podman 互补。(这两个项目都由 containers 组织维护,我也是该组织的成员。)在本文中,我将讨论无需 root 权限的 Buildah,包括它与 Podman 之间的区别。

我们使用 Buildah 的目标是构建一个低级工具,可以直接使用或集成到其他工具中来构建容器镜像。

为什么要使用 Buildah?

以下是我描述容器镜像的方式:它基本上是一个 rootfs 目录,其中包含运行容器所需的代码。此目录称为 rootfs,因为它通常看起来像 Linux 机器上的 / (根),这意味着您可能会在 rootfs 中找到像 /etc/usr/bin 等目录。

容器镜像的第二部分是一个 JSON 文件,用于描述 rootfs 的内容。它包含诸如运行容器的命令、入口点、运行容器所需的环境变量、容器的工作目录等字段。基本上,此 JSON 文件允许容器镜像的开发者描述容器镜像的预期使用方式。此 JSON 文件中的字段已在 OCI 镜像格式规范 中标准化。

然后,rootfs 和 JSON 文件会被 tar 压缩在一起,以创建一个存储在容器注册表中的镜像包。要创建分层镜像,您需要将更多软件安装到 rootfs 中并修改 JSON 文件。然后,您将新 rootfs 和旧 rootfs 的差异打包成 tar 文件,并将其存储在另一个镜像 tarball 中。第二个 JSON 文件通过校验和引用第一个 JSON 文件。

多年前,Docker 引入了 Dockerfile,这是一种简化的脚本语言,用于构建容器镜像。Dockerfile 非常棒并且真正流行起来,但它有许多用户抱怨的缺点。例如

  • Dockerfile 鼓励将用于构建容器的工具包含在容器镜像中。容器镜像不需要包含 yum/dnf/apt,但大多数都包含其中一个及其所有依赖项。

  • 每一行都会导致创建一个层。因此,机密可能会错误地添加到容器镜像中。如果您在 Dockerfile 的一行中创建了一个机密,然后在下一行中将其删除,则该机密仍然存在于镜像中。

我对“容器革命”的最大抱怨之一是,自从它开始已经六年了,构建容器镜像的唯一方法仍然是使用 Dockerfiles。除了 Buildah 之外,还出现了许多工具而不是 docker build,但大多数工具仍然只处理 Dockerfile。因此,用户继续破解 Dockerfile 的问题。

请注意,umocidocker build 的替代方案,允许您构建容器镜像而无需 Dockerfile。

我们使用 Buildah 的目标是构建一个简单的工具,该工具只需在磁盘上创建一个 rootfs 目录,并允许其他工具填充该目录,然后创建 JSON 文件。最后,Buildah 将创建 OCI 镜像并将其推送到容器注册表,任何容器引擎(如 Docker、Podman、CRI-O 或另一个 Buildah)都可以使用它。

Buildah 还支持 Dockerfile,因为我们知道构建容器的大部分人已经创建了 Dockerfiles。

直接使用 Buildah

很多人直接使用 Buildah。Buildah 的一个很棒的功能是,您可以直接在 Bash 中编写容器构建脚本。

下面的示例创建一个名为 myapp.sh 的 Bash 脚本,该脚本使用 Buildah 拉取 Fedora 镜像,然后使用机器上的 dnfmake 将软件安装到容器镜像 rootfs $mnt 中。然后,它使用 buildah config 将一些字段添加到 JSON 文件中,并将容器提交到容器镜像 myapp。最后,它将容器镜像推送到容器注册表 quay.io。(它可以将其推送到任何容器注册表。)现在,任何容器引擎或 Kubernetes 都可以使用此 OCI 镜像。

cat myapp.sh
#!/bin/sh
ctr=$(buildah from fedora)
mnt=$(buildah mount $ctr)
dnf -y install --installroot $mnt httpd
make install DESTDIR=$mnt myapp
rm -rf $mnt/var/cache $mnt/var/log/*
buildah config --command /usr/bin/myapp -env foo=bar --working-dir=/root $ctr
buildah commit $ctr myapp
buildah push myapp http://quay.io/username/myapp

要创建真正小的镜像,您可以使用 scratch 替换上面脚本中的 fedora,Buildah 将构建一个容器镜像,该镜像仅包含容器镜像内部 httpd 软件包的要求。无需 Python 或 DNF。

Podman 与 Buildah 的关系

通过 Buildah,我们有了一个用于构建容器镜像的低级工具。Buildah 还提供了一个库,供其他工具构建容器镜像。Podman 旨在取代 Docker 命令行界面 (CLI)。Docker CLI 命令之一是 docker build。我们需要有 podman build 来支持使用 Dockerfiles 构建容器镜像。Podman 集成了 Buildah 库以允许它执行 podman build。任何时候您执行 podman build,您都在执行 Buildah 代码来构建您的容器镜像。如果您只打算使用 Dockerfiles 来构建容器镜像,我们建议您只使用 Podman;根本不需要 Buildah。

使用 Buildah 库的其他工具

Podman 并不是唯一利用 Buildah 库的工具。OpenShift 4 Source-to-Image (S2I) 也将使用 Buildah 来构建容器镜像。OpenShift S2I 允许使用 OpenShift 的开发者使用 Git 命令来修改源代码;当他们将源代码的更改推送到 Git 存储库时,OpenShift 会启动一个作业来编译源代码更改并创建一个容器镜像。它还在底层使用 Buildah 来构建此镜像。

Ansible-Bender 是一个通过 Ansible playbook 构建容器镜像的新项目。对于熟悉 Ansible 的人来说,Ansible-Bender 可以轻松描述容器镜像的内容,然后使用 Buildah 打包容器镜像并将其发送到容器注册表。

我们很乐意看到其他工具和语言用于描述和构建容器镜像,并欢迎其他人使用 Buildah 来进行转换。

无需 root 权限的问题

Buildah 在无需 root 权限的模式下工作正常。它以与 Podman 相同的方式使用用户命名空间。如果您执行

$ buildah bud --tag myapp -f Dockerfile .
$ buildah push myapp http://quay.io/username/myapp

在您的主目录中,一切正常。

但是,如果您执行上面描述的脚本,它将失败!

问题是,当在无需 root 权限的模式下运行 buildah mount 命令时,buildah 命令必须将自身置于用户命名空间中并创建一个新的挂载命名空间。不允许无 root 权限的用户在未在用户命名空间中运行时挂载文件系统。

当 Buildah 可执行文件退出时,用户命名空间和挂载命名空间会消失,因此挂载点不再存在。这意味着在 buildah mount 之后尝试写入 $mnt 的命令将失败,因为 $mnt 不再挂载。

我们如何使脚本在无需 root 权限的模式下工作?

Buildah unshare

Buildah 有一个特殊的命令 buildah unshare,允许您进入用户命名空间。如果您在不使用任何命令的情况下执行它,它将在用户命名空间中启动一个 shell,您的 shell 看起来像是在以 root 身份运行,并且主目录的所有内容看起来都归 root 所有。如果您查看 /usr 中的所有者或文件,它会将它们列为 nfsnobody(或 nobody)所有。这是因为您的用户 ID (UID) 现在是用户命名空间中的 root,并且真正的 root (UID=0) 未映射到用户命名空间中。内核将用户命名空间中未映射的 UID 拥有的所有文件表示为 NFSNOBODY 用户。当您退出 shell 时,您将退出用户命名空间,您将回到正常的 UID,并且主目录将再次归您的 UID 所有。

如果您想执行上面定义的 myapp.sh 命令,您可以执行 buildah unshare myapp.sh,脚本现在将正确运行。

结论

现在可以在非特权环境中构建和运行容器,并且相当实用。开发者几乎没有理由以 root 用户身份开发容器。

如果你想使用传统的容器引擎,并使用 Dockerfile 进行构建,那么你应该直接使用 Podman。但如果你想尝试用新的方式构建容器镜像,而不使用 Dockerfile,那么你真的应该看看 Buildah。

标签
User profile image.
Daniel Walsh 在计算机安全领域工作了近 30 年。Dan 于 2001 年 8 月加入红帽公司。

6 条评论

非常好的信息……感谢与我们分享。

不错

不错的文章

这个容器随时都很有用

太棒了,考虑环境是每个人的责任。继续努力。

我将成为你帖子的常客 :)

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.