Buildah 入门

Buildah 提供了一种灵活的、可编写脚本的方式,使用您最喜欢的工具来创建精简、高效的容器镜像。
306 位读者喜欢这个。
3 mistakes to avoid when learning to code in Python

Opensource.com

Buildah 是一个命令行工具,用于快速轻松地构建与 开放容器倡议组织 (Open Container Initiative) 兼容(也即与 Docker 和 Kubernetes 兼容)的镜像。它可以作为 Docker 守护进程的 docker build 命令(即,使用传统的 Dockerfile 构建镜像)的直接替代品,但它足够灵活,允许您使用您喜欢的任何工具来构建镜像。Buildah 很容易集成到脚本和构建管道中,最棒的是,它不需要运行容器守护进程来构建其镜像。

docker build 的直接替代品

您可以立即开始使用 Buildah,将其放在当前使用 Dockerfile 和 docker build 构建镜像的地方。Buildah 的 build-using-dockerfilebud 参数使其行为方式与 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

请注意上面脚本中的几件事

  1. curl 命令将 tarball 下载到主机,而不是镜像

  2. tar 命令(从主机本身运行)将 tarball 中的源代码提取到容器内的 /opt 中。

  3. Configuremakemake install 都在挂载点内的目录中运行,挂载到主机而不是在容器本身内运行。

  4. 此处的 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 创建小型容器]

标签
Chris Collins
Chris Collins 是 Red Hat 的 SRE 和 OpenSource.com 的通讯员,热衷于自动化、容器编排及其周围的生态系统,并且喜欢在家中重新创建企业级技术以获得乐趣。

评论已关闭。

下载开放组织 IT 文化变革指南

开放原则和实践,以交付无与伦比的业务价值。

© . All rights reserved.