资讯动态

Buildah 入门实战:从 scratch 到 Dockerfile,构建可移植 OCI 镜像的完整工作流

发布时间:2026/9/25 17:54:17 来源:尧图企业网站定制
云原生【免费下载链接】buildahA tool that facilitates building OCI images.项目地址https://gitcode.com/gh_mirrors/bu/buildah点击查看免费下载本文基于 Buildah 官方入门教程docs/tutorials/01-intro.md整理并深入扩展带你完整走一遍 Buildah 构建 OCI 容器镜像的核心工作流安装与验证、基于现有镜像创建 working container、从scratch空镜像逐层填充内容、提交与配置元数据以及使用 Dockerfile/Containerfile 构建镜像。读完之后你将掌握 Buildah CLI 的典型操作序列并理解每个命令背后对应的源码实现与底层库containers/image、containers/storage的协作关系。一、Buildah 与 OCI 镜像规范Buildah 的目标是构建符合 OCI 镜像规范 的容器镜像。镜像既可以基于现有镜像扩展也可以完全从空白scratch开始还可以直接由 Dockerfile 驱动构建。Buildah 的镜像能力建立在两个基础库之上containers/image提供镜像的复制push、pull、检视inspect与签名sign机制containers/storage提供文件系统层layers、容器镜像以及容器本身的存储机制。Buildah 本身是一个 CLI它利用上述两个库来构建、移动和管理容器镜像与工作容器。由于产物严格遵循 OCI 标准用 Buildah 构建的镜像可以在 Docker 等其他容器环境中运行。需要明确的适用边界Buildah 支持多种 Linux 发行版但不支持 Windows 或 macOSBuildah 专注于构建OCI 镜像而 Podman 提供覆盖面更广的命令集维护、修改、运行镜像与容器。二者同属 containers 生态定位互补。二、安装 Buildah官方入门教程以使用dnf包管理器的 Linux 发行版为前提安装步骤如下安装包需要 root 权限$ sudo -s # dnf -y install buildah仓库中的 install.md 给出了更多发行版的安装方式包括Debian/Ubuntusudo apt-get -y install buildahFedorasudo dnf -y install buildahCentOSsudo yum -y install buildahopenSUSEsudo zypper install buildahArch Linuxsudo pacman -S buildahGentoosudo emerge app-containers/buildah。除了发行版差异还有两个关键前提值得注意内核要求RHEL/CentOS 上要求 7.4 及以上内核其他发行版需要支持 OverlayFS 或 fuse-overlayfs 的内核runc 依赖buildah run执行命令、或buildah build遇到RUN指令时Buildah 依赖runc来真正运行进程。通过 yum/dnf/apt 安装 Buildah 时通常会顺带装好 runc。Rootless免 root运行如果计划以非 root 用户rootless user运行 Buildah系统管理员可能需要预先做额外配置。Buildah 对 rootless 用户的配置要求与 Podman 完全一致可参考 Podman 官方的 rootless tutorial。仓库中的 buildah-unshare.1.md 则说明了后文会用到的buildah unshare命令它用于创建并进入 user namespace 与 mount namespace。三、安装后验证images、containers 与 working container安装完成后先确认本地存储是空的。buildah images列出所有镜像buildah containers列出所有 working container# buildah images # buildah containers此时两条命令都应该没有输出。接下来创建第一个 working container# container$(buildah from fedora)这里有两点值得深入理解。第一buildah from的输出可以直接赋给 shell 变量。从源码看cmd/buildah/from.go 中fromCmd在成功构建Builder之后执行fmt.Printf(%s\n, builder.Container)把容器名打印到标准输出——这正是教程中container$(buildah from fedora)能够捕获名称的机制。第二working container 的命名规则。Buildah 默认会在基础镜像名后追加-working-container后缀来生成容器名例如fedora-working-container。命名逻辑位于 new.goname : working-container if options.ContainerSuffix ! { name options.ContainerSuffix } if options.Container ! { name options.Container } else { if imageSpec ! { name imageNamePrefix(imageSpec) - name } }其中imageNamePrefixnew.go会去掉镜像名中的 tag、digest截断到 12 位、与/部分只保留最后一段镜像名从而得到fedora这样的前缀。如果同名容器已存在findUnusedContainer会进一步追加编号避免冲突。查看变量内容并进入容器执行命令# echo $container fedora-working-container # buildah run $container bash执行后会看到一个新的 shell 提示符说明 bash 正在容器内运行。注意buildah run的定位主要用于调试和构建过程中的命令执行。如果要在生产环境长期运行容器更适合使用 Podman 或 CRI-O 这类完整的容器运行时。buildah run中的--分隔符退出容器后教程演示了容器内缺软件再装软件的场景# buildah run $container java容器里没装 Java会看到类似这样的报错runc create failed: unable to start start container process: exec: java: executable file not found in $PATH于是需要在容器里安装 Java# buildah run $container -- dnf -y install java这里的--语法告诉 Buildah其后不再解析buildah run自身的选项--之后的所有内容都作为容器内命令的参数。当你要执行的容器内命令自身携带选项如dnf -y install时使用--是必要的可以防止选项被 Buildah 误吞。之后再次运行buildah run $container java将输出 Java 的标准Usage信息说明安装成功。四、从 scratch 构建真正从零的镜像Buildah 的一个重要能力是从空白构建镜像可以精确控制镜像内容剔除生产环境不需要的组件比如大多数生产镜像并不需要dnf这样的包管理器。4.1 创建空容器特殊的镜像名scratch告诉 Buildah 创建一个空容器——它只带有少量元数据没有任何实际的 Linux 内容# newcontainer$(buildah from scratch) # buildah containers输出类似CONTAINER ID BUILDER IMAGE ID IMAGE NAME CONTAINER NAME 82af3b9a9488 * 3d85fcda5754 docker.io/library/fedora:latest fedora-working-container ac8fa6be0f0a * scratch working-container注意两点空容器的默认名字就是working-container对应 new.go 中的默认值没有镜像名可作前缀运行buildah images时看不到名为scratch的镜像——scratch只是一个特殊值表示该 working container 并非基于任何镜像从 nothing 开始。此时在容器里执行buildah run $newcontainer bash会失败——容器里连 bash、dnf 都没有它本质上只是内核之上的一层空文件系统。4.2 用 buildah mount 暴露容器根文件系统要把内容塞进这个空容器需要buildah mount命令# scratchmnt$(buildah mount $newcontainer) # echo $scratchmnt /var/lib/containers/storage/overlay/b78d0e11957d15b5d1fe776293bd40a36c28825fb6cf76f407b4d0a95b2a200d/merged输出的路径是一个overlay 挂载点它就是容器使用的根文件系统。以 root 运行时overlay 挂载点位于/var/lib/containers/storage之下rootless 模式下则位于家目录的.local/share/containers/storage之下——这正体现了底层 containers/storage 库的存储布局。从源码看buildah mount最终调用 mount.go 中的Builder.Mountfunc (b *Builder) Mount(label string) (string, error) { mountpoint, err : b.store.Mount(b.ContainerID, label) if err ! nil { return , fmt.Errorf(mounting build container %q: %w, b.ContainerID, err) } b.MountPoint mountpoint err b.Save() if err ! nil { return , fmt.Errorf(saving updated state for build container %q: %w, b.ContainerID, err) } return mountpoint, nil }可以看到它委托给存储驱动b.store.Mount完成实际的 overlay 挂载并把挂载点持久化到 Builder 状态b.Save()供后续buildah unmount时清理。rootless 注意事项rootless 模式下直接执行buildah mount会失败因为挂载容器必须在你自己拥有的 mount namespace 中进行。正确的做法是先用buildah unshare创建并进入 user namespace 与 mount namespace再执行 mount并且由于 shell 环境变了需要把变量导出$ export newcontainer $ buildah unshare # scratchmnt$(buildah mount $newcontainer)4.3 用 dnf installroot 向容器填充软件拿到挂载点之后就可以在宿主机上直接装包进容器。教程以安装bash与coreutils为例换成nginx等任何需要的包也一样# dnf install --installroot $scratchmnt --releasever 42 bash coreutils --use-host-config --setopt *.countmefalse --setopt installweak_depsfalse -y关键参数是--installroot $scratchmnt让 dnf 把包装进挂载目录而不是宿主机。教程特别提示示例中的--releasever 42对应 Fedora 42这个版本值必须对宿主机上的 dnf 有效——例如在 RHEL 平台上应写--releasever 8.1之类的有效版本。若希望容器最终基于某个特定发行版可把buildah from scratch换成buildah from fedora并使用该平台的版本值。验证一下容器内确实有了/usr/bin# buildah run $newcontainer sh sh-5.1# cd /usr/bin sh-5.1# ls sh-5.1# exit4.4 copy、config、commit完成第一张镜像在宿主机上创建一个可执行脚本runecho.sh#!/usr/bin/env bash for i in seq 0 9; do echo This is a new container from ipbabble [ $i ] done# chmod x runecho.sh然后三步完成镜像# buildah copy $newcontainer ./runecho.sh /usr/bin/ # buildah config --cmd /usr/bin/runecho.sh $newcontainer # buildah commit $newcontainer newimage这一步值得理解buildah run与podman run的本质区别教程给出的类比非常准确buildah run等价于 Dockerfile 中的RUN它永远需要你显式告诉它要运行什么命令podman run等价于docker run它可以读取镜像配置即上一步buildah config --cmd写入的默认命令来决定运行什么。先用 Buildah 直接指定命令验证脚本可执行# buildah run $newcontainer /usr/bin/runecho.sh This is a new container from ipbabble [ 0 ] This is a new container from ipbabble [ 1 ] ... This is a new container from ipbabble [ 9 ]再用 Podman 基于新镜像起一个全新容器不指定命令它会自动执行镜像配置里的--cmd# dnf -y install podman # 先安装 # podman run --rm newimage This is a new container from ipbabble [ 0 ] ... This is a new container from ipbabble [ 9 ]输出一致说明这个从 scratch 构建的镜像完全可用。4.5 元数据、二次 commit 与清理继续为工作容器补充元数据# buildah config --created-by ipbabble $newcontainer # buildah config --author wgh at redhat.com ipbabble --label namefedora42-bashecho $newcontainer # buildah inspect $newcontainer注意一个容易踩的坑元数据修改发生在上一次 commit 之后所以必须再次 commit 才能得到包含新元数据的镜像# buildah unmount $newcontainer # buildah commit $newcontainer fedora-bashecho # buildah images此时会看到新镜像localhost/fedora-bashecho:latest。检查镜像元数据用--typeimage# buildah inspect --typeimage fedora-bashecho之后每次需要基于该镜像起容器直接buildah from fedora-bashecho即可。工作容器已完成使命可以删除按变量或按名字等价# buildah rm $newcontainer # buildah rm working-container五、可移植性把镜像推给 Docker daemon教程用一个实验证明 Buildah 产出的 OCI 镜像是标准、可移植的安装并启动 Docker然后把镜像从 containers/storage 的存储区复制到 Docker daemon 的存储区/var/lib/docker# dnf -y install docker # systemctl start docker # buildah push fedora-bashecho docker-daemon:fedora-bashecho:latest # docker run --rm fedora-bashecho This is a new container from ipbabble [ 0 ] ... This is a new container from ipbabble [ 9 ]几个要点docker-daemon:是显式的 transport 前缀。docker://默认指向 Registry HTTP API V2、docker-daemon:指向本地 Docker daemon 的内部存储、dir:、oci:、oci-archive:、docker-archive:等 transport 的完整定义见 buildah-from.1.md 与 buildah-push.1.md底层机制containers/image 库调用 containers/storage 库从 Buildah 的存储位置读出镜像内容发送给本地 Docker daemon 写入其存储。教程提醒这一步通常用不到——用 Buildah 的人多半不用 Docker这里仅作可移植性演示架构差异Docker 必须依赖一个常驻 daemon 进程才能执行任何客户端命令Buildah 与 Podman 则没有 daemon 依赖命令直接操作存储与命名空间。演示完成后可以dnf -y remove docker收尾。六、使用 Containerfile/Dockerfile 构建镜像如果你已有现成的 Dockerfile 资产Buildah 可以无缝复用build命令接受 Dockerfile 作为输入产出 OCI 镜像。教程给出的示例 Dockerfile 如下# Base on the most recently released Fedora FROM fedora:latest MAINTAINER ipbabble email buildahboyredhat.com # not a real email # Install updates and httpd RUN echo Updating all fedora packages; dnf -y update; dnf -y clean all RUN echo Installing httpd; dnf -y install httpd dnf -y clean all # Expose the default httpd port 80 EXPOSE 80 # Run the httpd CMD [/usr/sbin/httpd, -DFOREGROUND]执行构建# buildah build -f Dockerfile -t fedora-httpd .由于buildah build默认使用当前目录下的Dockerfile并以当前目录作为构建上下文上式可以简写为# buildah build -t fedora-httpd构建过程中你会看到 Dockerfile 的每一步依次执行FROM会先创建一个以镜像名-working-container命名的工作容器RUN指令经由 runc 在容器内执行——这与前面buildah run的机制同源完成后buildah images中出现新镜像。用 Podman 起容器验证服务并做端口映射# podman run --rm -p 8123:80 fedora-httpd另开一个 shell# curl localhost:8123看到标准的 Apache 欢迎页即验证成功。教程最后的开放练习修改 Dockerfile不安装 httpd改用ADD指令引入前面的runecho.sh并把它设为CMD再走一遍构建流程。仓库的 tests/ 目录中有大量围绕 Dockerfile 行为的集成测试如 tests/bud.bats 及各tests/bud/子目录的测试用例可以结合源码进一步理解buildah build对COPY、ADD、多阶段构建、ARG/ENV等指令的具体处理逻辑。七、小结一条完整的 Buildah 心智模型把上面的操作串起来Buildah 的核心工作模型是四步buildah from image|scratch创建 working container源码入口 cmd/buildah/from.go命名规则见 new.go填充内容buildah run在容器内执行命令、buildah copy拷入文件、buildah mount 宿主工具直接操作根文件系统实现见 mount.gobuildah config写入元数据cmd、label、author 等buildah commit把工作容器的变更固化为 OCI 镜像之后可通过buildah push发送到 registry、Docker daemon 等任意 transport。所有产物严格遵循 OCI 规范因此天然可移植。若想继续深入建议按序阅读 docs/tutorials/ 下的后续教程镜像仓库交互、ONBUILD 机制、把 Buildah 作为库集成进自有构建工具、rootless OpenShift 构建以及各命令的 man pagedocs/buildah-run.1.md、docs/buildah-commit.1.md、docs/buildah-mount.1.md、docs/buildah-config.1.md、docs/buildah-push.1.md 等它们覆盖了本教程未展开的全部命令行参数。赞分享云原生【免费下载链接】buildahA tool that facilitates building OCI images.项目地址https://gitcode.com/gh_mirrors/bu/buildah点击查看免费下载相关推荐container构建系统详解从Dockerfile到OCI镜像的完整流程container构建系统详解从Dockerfile到OCI镜像的完整流程 container构建系统是专门为Mac平台优化的Linux容器构建工具采用SwCLI虚拟化容器运行时云原生Buildah: OCI镜像构建工具Buildah: OCI镜像构建工具 1. 项目介绍 Buildah是一个开源命令行工具用于构建Open Container Initiative OCI 容云原生终极指南Docker构建工具链如何从Dockerfile到OCI镜像的完整流程终极指南Docker构建工具链如何从Dockerfile到OCI镜像的完整流程 Docker构建工具链是现代容器化开发的核心它通过Dockerfile指令逐云原生容器运行时虚拟化容器编排上一篇Apache Pulsar 授权机制详解Authorization 配置、Superusers 与 Proxy Roles 实战指南下一篇Lynx 模板二进制编码中的 Style Object 解析与编码实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑