如何使用 Buildah 构建符合 OCI 标准的容器镜像?

来源:苹果APP网作者:清原小日向头衔:网络博主
导读:本期聚焦于小伙伴创作的《如何使用 Buildah 构建符合 OCI 标准的容器镜像?》,敬请观看详情。传统 Docker 构建依赖守护进程与 Dockerfile,在 CI 隔离环境常遇权限冲突。Buildah 作为无守护进程工具,直接调用内核功能生成符合 OCI 规范的镜像。它支持从零创建基础镜像、提交容器为镜像及挂载修改文件系统。相比完整容器运行时,Buildah 仅专注构建,镜像层结构更透明。通过 buildah from、buildah run 等指令,可在无 root 权限下完成软件包安装与配置,最终用 buildah commit 输出可推送至任意仓库的 tar 包或 OCI 目录,适配 Kubernetes 与 Podman 生态。

Buildah 是一个用于构建 OCI(Open Container Initiative)格式容器镜像的命令行工具,它的设计目标和传统 Docker 构建方式有明显区别。Docker 构建通常依赖一个长期运行的守护进程以及 Dockerfile 来描述构建步骤,而 Buildah 不需要守护进程,直接利用 Linux 内核的 user namespace、overlay 文件系统等技术来组装镜像。这种方式让镜像构建过程可以更精细地控制每一层的内容,也更容易在不需要特权的持续集成环境中运行。

如何使用 Buildah 构建符合 OCI 标准的容器镜像?

Buildah 的核心工作机制与 OCI 规范对应关系

OCI 镜像规范定义了镜像的配置、清单以及层文件的格式,目标是让不同工具生成的镜像可以被任意兼容运行时拉起。Buildah 在内部严格按照这一规范组织数据:每一个通过 buildah run 产生的文件系统变更都会被记录为一个层,层的元数据写入 OCI 的 config 文件,而最终镜像的索引信息则对应 manifest。理解这一点有助于我们在排查镜像体积或兼容性问题时,直接查看 Buildah 工作目录中的 OCI 布局。

与 Docker 的镜像格式相比,Buildah 输出的 OCI 镜像去掉了 Docker 特有的历史注释与额外字段,因此更为精简。我们可以通过 buildah inspect 查看某个容器的配置,它会返回符合 OCI 描述的 JSON 结构,其中包含环境变量、入口命令以及层差异计算方式。这种透明性使得安全审计人员能够逐层比对基础镜像中被植入的软件包,而不必依赖厂商提供的黑盒构建日志。

在权限模型上,Buildah 利用 user namespace 将容器内的 root 映射到宿主机的普通用户,从而允许非特权用户执行 apt-get install 这类需要 root 的操作。示例代码如下,展示以普通用户身份从空镜像开始安装软件:

# 使用普通用户创建 scratch 基础容器
buildah from scratch
cnt=$(buildah from scratch)
# 挂载容器文件系统
mnt=$(buildah mount $cnt)
# 复制本地编译好的二进制
cp /home/user/app $mnt/app
# 配置入口
buildah config --entrypoint "/app" $cnt
buildah commit $cnt oci-app:latest

从零构建与基于基础镜像构建的两种实践路径

第一种路径是从 scratch 开始完全自制镜像。这种方式适合交付单一静态二进制程序的场景,比如 Go 语言编译出的无依赖可执行文件。由于不包含包管理器与 shell,镜像体积可以控制在几 MB 以内,并且攻击面极小。在 Buildah 中只需 buildah from scratch 得到一个空容器,挂载后复制文件并提交即可,不需要编写 Dockerfile,所有步骤都能用脚本精确编排。

第二种路径是基于官方基础镜像,如 buildah from docker://ubuntu:22.04 拉取并创建可写容器。随后用 buildah run 执行命令,等价于在容器内执行但不会产生临时镜像层之外的副作用。我们可以在单次运行中更新软件源并安装依赖,然后通过 buildah commit 生成新镜像。相较于多行 Dockerfile,这种命令式构建在调试阶段可以不断进入容器状态检查,避免反复重写 Dockerfile 带来的缓存失效。

下面的例子演示基于 Ubuntu 基础镜像安装 Python 并清理缓存,以减小最终 OCI 镜像体积:

cnt=$(buildah from docker://ubuntu:22.04)
buildah run $cnt apt-get update
buildah run $cnt apt-get install -y python3-minimal
buildah run $cnt apt-get clean
buildah run $cnt rm -rf /var/lib/apt/lists/*
buildah config --cmd "python3 -V" $cnt
buildah commit $cnt my-python:oci

对比两种路径,从零构建更轻量但要求开发者清楚程序的所有依赖;基于基础镜像更通用,却容易因忘记清理包管理器缓存而导致层膨胀。在 CI 流水线中,通常结合两者:基础依赖做成一个内部 OCI 镜像,业务二进制再用 scratch 方式叠加。

镜像导出、推送与在 Kubernetes 环境中的验证

Buildah 构建出的镜像默认存储在本地存储库,可通过 buildah push 推送到支持 OCI 的镜像仓库。它支持 docker:// 与 oci:// 两种目标协议,前者兼容旧版仓库接口,后者直接写符合 OCI 布局的目录或压缩包。如果需要在离线环境交付,可以使用 buildah push 到本地 tar 文件,再由另一集群节点加载。

在 Kubernetes 中验证 Buildah 产物是否合规,最简单的方式是用 Podman 或 CRI-O 直接拉起。由于 CRI-O 原生支持 OCI 规范,Buildah 生成的镜像不需要任何转换即可被识别。我们可以在一个测试节点上执行 podman run --rm oci-app:latest 观察输出,确认入口点与环境变量符合预期。若使用 containerd,也可以通过 ctr images import 加载 Buildah 导出的 oci 目录。

以下脚本展示如何将本地镜像导出为 OCI 目录并重新导入:

# 导出为 OCI 布局目录
buildah push my-python:oci oci:/tmp/my-python-oci
# 在另一台机器上推送至内部仓库
buildah push oci:/tmp/my-python-oci docker://registry.ipipp.com/base/my-python:oci

值得注意的是,Buildah 不负责镜像签名与漏洞扫描,这些需要在构建后接入 Notary 或 Trivy 等工具。但因为它暴露了完整的 OCI 层结构,扫描器可以直接读取每层 diff_id,而不必解压整个镜像,从而提升安全检测效率。对于需要符合等保或行业合规要求的团队,这种可控的构建链路比封闭的商业构建服务更容易通过审计。

BuildahOCI镜像容器构建修改时间:2026-08-14 09:15:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。