Buildah 是一个命令行工具,用于快速轻松地构建与 开放容器倡议组织 (Open Container Initiative) 兼容(也即与 Docker 和 Kubernetes 兼容)的镜像。它可以作为 Docker 守护进程的 docker build
命令(即,使用传统的 Dockerfile 构建镜像)的直接替代品,但它足够灵活,允许您使用您喜欢的任何工具来构建镜像。Buildah 很容易集成到脚本和构建管道中,最棒的是,它不需要运行容器守护进程来构建其镜像。
docker build 的直接替代品
您可以立即开始使用 Buildah,将其放在当前使用 Dockerfile 和 docker build
构建镜像的地方。Buildah 的 build-using-dockerfile
或 bud
参数使其行为方式与 docker build
完全相同,因此很容易将其集成到现有脚本或构建管道中。
与我之前撰写的关于 Buildah 的文章一样,我喜欢使用从源代码安装 “GNU Hello” 的示例。考虑以下 Dockerfile
FROM fedora:28
LABEL maintainer Chris Collins <collins.christopher@gmail.com>
RUN dnf install -y tar gzip gcc make \
&& dnf clean all
ADD http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz /tmp/hello-2.10.tar.gz
RUN tar xvzf /tmp/hello-2.10.tar.gz -C /opt
WORKDIR /opt/hello-2.10
RUN ./configure
RUN make
RUN make install
RUN hello -v
ENTRYPOINT "/usr/local/bin/hello"
Buildah 可以像 buildah bud -t hello .
一样轻松地从此 Dockerfile 创建镜像,替换 docker build -t hello .
[chris@krang] $ sudo buildah bud -t hello .
STEP 1: FROM fedora:28
Getting image source signatures
Copying blob sha256:e06fd16225608e5b92ebe226185edb7422c3f581755deadf1312c6b14041fe73
81.48 MiB / 81.48 MiB [====================================================] 8s
Copying config sha256:30190780b56e33521971b0213810005a69051d720b73154c6e473c1a07ebd609
2.29 KiB / 2.29 KiB [======================================================] 0s
Writing manifest to image destination
Storing signatures
STEP 2: LABEL maintainer Chris Collins <collins.christopher@gmail.com>
STEP 3: RUN dnf install -y tar gzip gcc make && dnf clean all
<snip>
构建完成后,您可以使用 buildah images
命令查看新镜像
[chris@krang] $ sudo buildah images
IMAGE ID IMAGE NAME CREATED AT SIZE
30190780b56e docker.io/library/fedora:28 Mar 7, 2018 16:53 247 MB
6d54bef73e63 docker.io/library/hello:latest May 3, 2018 15:24 391.8 MB
新的镜像,标记为 hello:latest
,可以推送到远程镜像仓库,或使用 CRI-O 或其他 Kubernetes CRI 兼容运行时运行,或推送到远程仓库。如果您正在测试它作为 Docker build 的替代品,您可能需要将镜像复制到 docker 守护进程的本地镜像存储中,以便 Docker 可以运行它。这可以使用 buildah push
命令轻松完成
[chris@krang] $ sudo buildah push hello:latest docker-daemon:hello:latest
Getting image source signatures
Copying blob sha256:72fcdba8cff9f105a61370d930d7f184702eeea634ac986da0105d8422a17028
247.02 MiB / 247.02 MiB [==================================================] 2s
Copying blob sha256:e567905cf805891b514af250400cc75db3cb47d61219750e0db047c5308bd916
144.75 MiB / 144.75 MiB [==================================================] 1s
Copying config sha256:6d54bef73e638f2e2dd8b7bf1c4dfa26e7ed1188f1113ee787893e23151ff3ff
1.59 KiB / 1.59 KiB [======================================================] 0s
Writing manifest to image destination
Storing signatures
[chris@krang] $ sudo docker images | head -n2
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/hello latest 6d54bef73e63 2 minutes ago 398 MB
[chris@krang] $ sudo docker run -t hello:latest
Hello, world!
一些差异
与 Docker build 不同,Buildah 不会自动为 Dockerfile 中的每个指令提交对层的更改——它每次都从头到尾构建所有内容。从积极的方面来看,这意味着非缓存构建(例如,您使用自动化或构建管道进行的构建)最终会比其 Docker build 的对应项更快一些,尤其是在有很多指令的情况下。这对于从自动化部署或持续交付的角度来看,将新更改快速投入生产非常有利。
但实际上,对于镜像开发而言,缺乏缓存可能不是那么有用,因为在反复构建时,缓存层可以节省大量时间。但这仅适用于 build-using-dockerfile
命令。当使用 Buildah 本地命令时,正如我们将在下面看到的,您可以选择何时将更改提交到磁盘,从而实现更灵活的开发。
Buildah 本地命令
Buildah 真正 闪光的地方在于其本地命令,您可以使用这些命令与容器构建进行交互。Buildah 具有与构建过程中创建的临时容器实际交互的命令,而不是为每次构建都使用 build-using-dockerfile/bud
。(Docker 也使用临时的或中间容器,但在镜像构建时您实际上不会与它们交互。)
再次使用 “GNU Hello” 示例,考虑使用 Buildah 命令构建此镜像
#!/usr/bin/env bash
set -o errexit
# Create a container
container=$(buildah from fedora:28)
# Labels are part of the "buildah config" command
buildah config --label maintainer="Chris Collins <collins.christopher@gmail.com>" $container
# Grab the source code outside of the container
curl -sSL http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz -o hello-2.10.tar.gz
buildah copy $container hello-2.10.tar.gz /tmp/hello-2.10.tar.gz
buildah run $container dnf install -y tar gzip gcc make
Buildah run $container dnf clean all
buildah run $container tar xvzf /tmp/hello-2.10.tar.gz -C /opt
# Workingdir is also a "buildah config" command
buildah config --workingdir /opt/hello-2.10 $container
buildah run $container ./configure
buildah run $container make
buildah run $container make install
buildah run $container hello -v
# Entrypoint, too, is a “buildah config” command
buildah config --entrypoint /usr/local/bin/hello $container
# Finally saves the running container to an image
buildah commit --format docker $container hello:latest
应该立即显而易见的一件事是,这是一个 Bash 脚本,而不是 Dockerfile。使用 Buildah 的本地命令可以很容易地编写脚本,无论您喜欢使用哪种语言或自动化环境。这可以是 makefile、Python 脚本或您喜欢使用的任何工具。
那么这里发生了什么?第一个 Buildah 命令 container=$(buildah from fedora:28)
,从 fedora:28 镜像创建一个正在运行的容器,并将容器名称(命令的输出)存储为变量以供以后使用。所有其余的 Buildah 命令都使用 $container
变量来说明要对哪个容器执行操作。在大多数情况下,这些命令是不言自明的:buildah copy
将文件移动到容器中,buildah run
在容器中执行命令。很容易将它们与 Dockerfile 等效项匹配起来。
最后一个命令 buildah commit
,将容器提交到磁盘上的镜像。当使用 Buildah 命令而不是从 Dockerfile 构建镜像时,您可以使用 commit
命令来决定何时保存更改。在上面的示例中,所有更改都是一次性提交的,但也可以包含中间提交,允许您选择从中开始的缓存点。(例如,在 dnf install
之后缓存到磁盘特别有用,因为这可能需要很长时间,但每次都可靠地相同。)
挂载点、安装目录和 chroot
另一个有用的 Buildah 命令为构建镜像带来了很大的灵活性。buildah mount
将容器的根目录挂载到主机上的挂载点。例如
[chris@krang] $ container=$(sudo buildah from fedora:28)
[chris@krang] $ mountpoint=$(sudo buildah mount ${container})
[chris@krang] $ echo $mountpoint
/var/lib/containers/storage/overlay2/463eda71ec74713d8cebbe41ee07da5f6df41c636f65139a7bd17b24a0e845e3/merged
[chris@krang] $ cat ${mountpoint}/etc/redhat-release
Fedora release 28 (Twenty Eight)
[chris@krang] $ ls ${mountpoint}
bin dev home lib64 media opt root sbin sys usr
boot etc lib lost+found mnt proc run srv tmp var
这非常棒,因为现在您可以与挂载点交互以更改容器镜像。这允许您使用主机上的工具来构建和安装软件,而不是将这些工具包含在容器镜像本身中。例如,在上面的 Bash 脚本中,我们需要安装 tar、Gzip、GCC 和 make 包才能在容器内编译 “GNU Hello”。使用挂载点,我们可以使用相同的软件构建镜像,但下载的 tarball 和 tar、Gzip 等 RPM 都在主机上,而不是在容器和生成的镜像中
#!/usr/bin/env bash
set -o errexit
# Create a container
container=$(buildah from fedora:28)
mountpoint=$(buildah mount $container)
buildah config --label maintainer="Chris Collins <collins.christopher@gmail.com>" $container
curl -sSL http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz \
-o /tmp/hello-2.10.tar.gz
tar xvzf src/hello-2.10.tar.gz -C ${mountpoint}/opt
pushd ${mountpoint}/opt/hello-2.10
./configure
make
make install DESTDIR=${mountpoint}
popd
chroot $mountpoint bash -c "/usr/local/bin/hello -v"
buildah config --entrypoint "/usr/local/bin/hello" $container
buildah commit --format docker $container hello
buildah unmount $container
请注意上面脚本中的几件事
-
curl
命令将 tarball 下载到主机,而不是镜像 -
tar
命令(从主机本身运行)将 tarball 中的源代码提取到容器内的/opt
中。 -
Configure
、make
和make install
都在挂载点内的目录中运行,挂载到主机而不是在容器本身内运行。 -
此处的
chroot
命令用于将根目录更改为挂载点本身,并测试 “hello” 是否正常工作,类似于上一个示例中使用的buildah run
命令。
此脚本更短,它使用了大多数 Linux 用户已经熟悉的工具,并且生成的镜像更小(没有 tarball,没有额外的软件包等)。您甚至可以使用主机系统的软件包管理器将软件安装到容器中。例如,假设您想将 NGINX 与 GNU Hello 一起安装到容器中(无论出于何种原因)
[chris@krang] $ mountpoint=$(sudo buildah mount ${container})
[chris@krang] $ sudo dnf install nginx --installroot $mountpoint
[chris@krang] $ sudo chroot $mountpoint nginx -v
nginx version: nginx/1.12.1
在上面的示例中,DNF 与 --installroot
标志一起使用,将 NGINX 安装到容器中,这可以使用 chroot 进行验证。
试试看!
Buildah 是一种轻量级且灵活的方式,无需在主机上运行完整的 Docker 守护进程即可创建容器镜像。除了为从 Dockerfile 构建提供开箱即用的支持外,Buildah 还易于与您选择的脚本或构建工具一起使用,并且可以帮助使用构建主机上的现有工具构建容器镜像。结果是更精简的镜像,它们使用更少的带宽来传输,需要更少的存储空间,并且具有更小的潜在攻击面。试试看!
[请参阅我们的相关报道,使用 Buildah 创建小型容器]
评论已关闭。