Buildah 提供一种灵活、可脚本编程的方式,来使用你熟悉的工具创建精简、高效的容器镜像。
Buildah 是一个命令行工具,可以方便、快捷的构建与 开放容器标准 Open Container Initiative (OCI)兼容的容器镜像,这意味着其构建的镜像与 Docker 和 Kubernetes 兼容。该工具可作为 Docker 守护进程 docker build
命令(即使用传统的 Dockerfile 构建镜像)的一种 简单 drop-in 替换,而且更加灵活,允许构建镜像时使用你擅长的工具。Buildah 可以轻松与脚本集成并生成 流水线 pipeline ,最好之处在于构建镜像不再需要运行容器守护进程(LCTT 译注:这里主要是指 Docker 守护进程)。
docker build 的简单替换 目前你可能使用 Dockerfile 和 docker build
命令构建镜像,那么你可以马上使用 Buildah 进行替代。Buildah 的 build-using-dockerfile
(或 bud
)子命令与 docker build
基本等价,因此可以轻松的与已有脚本结合或构建流水线。
类似我的上一篇关于 Buildah 的文章 ,我也将以使用源码安装 “GNU Hello” 为例进行说明,对应的 Dockerfile 文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 从 Dockerfile 构建镜像也很简单,使用 buildah bud -t hello .
替换 docker build -t hello .
即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [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 signaturesSTEP 2: LABEL maintainer Chris Collins <collins.christopher@gmail.com>STEP 3: RUN dnf install -y tar gzip gcc make && dnf clean all <考虑篇幅,略去后续输出>
镜像构建完毕后,可以使用 buildah images
命令查看这个新镜像:
1 2 3 4 5 [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
可以很容易的完成推送操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [chris@krang ] $ sudo buildah push hello:latest docker-daemon:hello:latest Getting image source signatures Copying blob sha256 :72 fcdba8 cff9 f105 a61370 d930 d7 f184702 eeea634 ac986 da0105 d8422 a17028 247.02 MiB / 247.02 MiB [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ] 2 s Copying blob sha256 :e567905 cf805891 b514 af250400 cc 75 db3 cb47 d61219750e0 db047 c 5308 bd916 144.75 MiB / 144.75 MiB [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ] 1 s Copying config sha256 :6 d54 bef73e638 f2e2 dd8 b7 bf1 c 4 dfa26e7 ed1188 f1113 ee787893e23151 ff3 ff 1.59 KiB / 1.59 KiB [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ] 0 s Writing manifest to image destination Storing signatures [chris@krang ] $ sudo docker images | head -n2 REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/hello latest 6 d54 bef73e63 2 minutes ago 398 MB [chris@krang ] $ sudo docker run -t hello:latest Hello, world!
若干差异 与 Docker build 不同,Buildah 不会自动的将 Dockerfile 中的每条指令产生的变更提到新的 分层 layer 中,只是简单的每次从头到尾执行构建。类似于 自动化 automation 和 流水线构建 build pipeline ,这种 无缓存构建 non-cached 方式的好处是可以提高构建速度,在指令较多时尤为明显。从 自动部署 automated deployment 或 持续交付 continuous delivery 的视角来看,使用这种方式可以快速的将新变更落实到生产环境中。
但从实际角度出发,缓存机制的缺乏对镜像开发不利,毕竟缓存层可以避免一遍遍的执行构建,从而显著的节省时间。自动分层只在 build-using-dockerfile
命令中生效。但我们在下面会看到,Buildah 原生命令允许我们选择将变更提交到硬盘的时间,提高了开发的灵活性。
Buildah 原生命令 Buildah 真正 有趣之处在于它的原生命令,你可以在容器构建过程中使用这些命令进行交互。相比与使用 build-using-dockerfile/bud
命令执行每次构建,Buildah 提供命令让你可以与构建过程中的临时容器进行交互。(Docker 也使用临时或 中间 intermediate 容器,但你无法在镜像构建过程中与其交互。)
还是使用 “GNU Hello” 为例,考虑使用如下 Buildah 命令构建的镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 set -o errexit container=$(buildah from fedora:28 ) buildah config --label maintainer="Chris Collins <collins.christopher@gmail.com>" $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 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 buildah config --entrypoint /usr/local/bin/hello $container buildah commit --format docker $container hello:latest
我们可以一眼看出这是一个 Bash 脚本而不是 Dockerfile。基于 Buildah 的原生命令,可以轻易的使用任何脚本语言或你擅长的自动化工具编写脚本。形式可以是 makefile、Python 脚本或其它你擅长的类型。
这个脚本做了哪些工作呢?首先,Buildah 命令 container=$(buildah from fedora:28)
基于 fedora:28 镜像创建了一个正在运行的容器,将容器名(buildah from
命令的返回值)保存到变量中,便于后续使用。后续所有命令都是有 $container
变量指明需要操作的容器。这些命令的功能大多可以从名称看出:buildah copy
将文件拷贝至容器,buildah run
会在容器中执行命令。可以很容易的将上述命令与 Dockerfile 中的指令对应起来。
最后一条命令 buildah commit
将容器提交到硬盘上的镜像中。当不使用 Dockerfile 而是使用 Buildah 命令构建镜像时,你可以使用 commit
命令决定何时保存变更。在上例中,所有的变更是一起提交的;但也可以增加中间提交,让你可以选择作为起点的 缓存点 cache point 。(例如,执行完 dnf install
命令后将变更缓存到硬盘是特别有意义的,一方面因为该操作耗时较长,另一方面每次执行的结果也确实相同。)
挂载点,安装目录以及 chroot 另一个可以大大增加构建镜像灵活性的 Buildah 命令是 buildah mount
,可以将容器的根目录挂载到你主机的一个挂载点上。例如:
1 2 3 4 5 6 7 8 9 10 [chris@krang ] $ container=$( sudo buildah from fedora: 28 ) [chris@krang ] $ mountpoint=$( sudo buildah mount ${ container}) [chris@krang ] $ echo $mountpoint /var/lib /containers/storage /overlay2/ 463e da71ec74713d8cebbe41ee07da5f6df41c636f65139a7bd17b24a0e845e3/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”。如果使用挂载点,我仍使用同样的工具进行构建,但下载的压缩包和 tar、Gzip 等 RPM 包都在主机而不是容器和生成的镜像内:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/usr/bin/env bash set -o errexit 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} /optpushd ${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
命令将压缩包下载到主机中,而不是镜像中;
(主机中的) tar
命令将压缩包中的源代码解压到容器的 /opt
目录;
configure
,make
和 make install
命令都在主机的挂载点目录中执行,而不是在容器内;
这里的 chroot
命令用于将挂载点本身当作根路径并测试 “hello” 是否正常工作;类似于前面例子中用到的 buildah run
命令。
这个脚本更加短小,使用大多数 Linux 爱好者都很熟悉的工具,最后生成的镜像也更小(没有 tar 包,没有额外的软件包等)。你甚至可以使用主机系统上的包管理器为容器安装软件。例如,(出于某种原因)你希望安装 GNU Hello 的同时在容器中安装 NGINX :
1 2 3 4 5 [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 生成的容器体积更小,更便于网络传输,占用更小的存储空间,而且潜在的受攻击面更小。快来试试吧!
[阅读相关的故事,使用 Buildah 创建小体积的容器 ]
via: https://opensource.com/article/18/6/getting-started-buildah
作者:Chris Collins 选题:lujun9972 译者:pinewall 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出