公司动态
代码深度解析:Universal Blue main 的 Containerfile 多阶段构建原理揭秘
代码深度解析Universal Blue main 的 Containerfile 多阶段构建原理揭秘【免费下载链接】mainOCI base images of Fedora with batteries included项目地址: https://gitcode.com/gh_mirrors/main9/main想给 Fedora 定制一套开箱即用的镜像Universal Blue main 项目给出了一个堪称教科书级别的答案。它是一个基于 Fedora 的 OCI 基础镜像构建项目核心资产就是仓库根目录下那份仅有 45 行的 Containerfile。别看它短里面几乎用尽了容器构建的高级技巧多阶段构建、BuildKit 挂载缓存、内核 RPM 替换、签名校验一应俱全。这篇文章就用通俗的语言把这份 Containerfile 的多阶段构建原理一层层拆开给你看。多阶段构建的总体架构四个阶段各司其职普通 Dockerfile 通常只有一个 FROM而这里的 Containerfile 一口气写了四个 FROM这就是多阶段构建的核心每个 FROM 都是一个独立的构建阶段各自产出中间产物最终阶段再按需取用用完即弃互不污染。ctx 阶段打包仓库里的脚本和配置作为构建素材akmods 阶段提供预先编译好的内核模块 RPMakmods_nvidia 阶段提供 NVIDIA 显卡驱动模块 RPM最终阶段基于 Fedora 官方镜像组装出最终产品第一阶段ctx 上下文阶段把构建脚本装进镜像开头的三行 FROM scratch 很反直觉从一个空镜像出发然后用 COPY 把仓库里的 build_files/ 和 sys_files/ 目录原封不动塞进去顺便带上 packages.json。FROM scratch AS ctx COPY /sys_files /sys_files COPY /build_files / COPY packages.json /这个阶段不装任何软件它的唯一使命是给后续阶段提供一个文件挂载源。多阶段构建里别的阶段可以把这个阶段直接 bind 挂载进自己的文件系统等于把脚本送进构建现场。第二、三阶段akmods 内核模块仓库从哪来接下来两个 FROM 指向 Universal Blue 预先构建好的模块仓库FROM ${IMAGE_REGISTRY}/akmods:main-${FEDORA_MAJOR_VERSION}${AKMODS_DIGEST:${AKMODS_DIGEST}} AS akmods FROM ${IMAGE_REGISTRY}/akmods-nvidia-open:main-${FEDORA_MAJOR_VERSION}${AKMODS_NVIDIA_DIGEST:${AKMODS_NVIDIA_DIGEST}} AS akmods_nvidia这两行值得注意的细节是${AKMODS_DIGEST:${AKMODS_DIGEST}}这种参数展开语法如果构建时传入了摘要值就拼上sha256:...锁定镜像版本不传就退回到普通 tag。配合 image-versions.yaml 中固化的摘要保证每次构建用的都是同一份已验证过的模块这是可复现构建的关键一环。最终阶段RUN 指令里的高级挂载技巧真正的主角是最终阶段的 RUN 指令它一口气用了四种 BuildKit 挂载RUN --mounttypebind,fromctx,src/,dst/ctx \ --mounttypecache,target/var/cache \ --mounttypecache,target/var/log \ --mounttypetmpfs,target/tmp \ --mounttypebind,fromakmods,src/rpms/ublue-os,dst/tmp/akmods-rpms \ --mounttypebind,fromakmods,src/kernel-rpms,dst/tmp/kernel-rpms \ --mounttypebind,fromakmods_nvidia,src/rpms,dst/tmp/akmods-nv-rpms \ ...bind 挂载fromctx / fromakmods把前面阶段生成的脚本和 RPM 临时插入构建环境用完不留痕cache 挂载把/var/cache和/var/log变成持久缓存多次构建之间复用 dnf 下载缓存大幅提速tmpfs 挂载/tmp放在内存里又快又干净紧接着执行一串脚本接力先 install.sh 安装软件包、initramfs.sh 重新生成 initramfs、post-install.sh 做系统清理最后用bootc container lint做合规检查。构建脚本链三步接力组装系统挂在/ctx下的三个脚本是整个构建的灵魂各有分工install.sh启用 COPR 仓库、安装基础软件包、卸载 Fedora 自带内核、再从 akmods 挂载点安装签名内核 RPM最后dnf5 versionlock锁死内核版本防止意外升级initramfs.sh用 dracut 以可复现模式生成 initramfs 镜像补上 ostree 支持post-install.sh清理版本锁、启用自动更新定时器、删掉临时文件和/usr/etc最后执行ostree container commit把容器层固化软件包清单则集中管理在 packages.json由 packages.sh 用 jq 动态解析同一个清单根据IMAGE_NAMEsilverblue / kinoite / base和 Fedora 版本号生成不同的安装与排除列表这就是一个模板、多种变体的秘诀。可复现构建摘要锁定与签名校验细心的读者会发现Justfile 的 build 任务在真正执行podman build之前做了大量准备工作从 image-versions.yaml 读出三个上游镜像的 digest用 cosign 逐一校验签名再把 digest 作为 build-arg 传进构建。这样即使上游 tag 被覆盖构建产物依然可以逐字节复现这也是为什么项目里专门放了 cosign.pub 公钥文件。总结Universal Blue main 这份 Containerfile 把多阶段构建玩到了极致用FROM scratch做上下文传递、用预构建镜像做模块仓库、用 bind/cache/tmpfs 挂载优化构建性能、用 digest 锁定保证可复现、用 cosign 签名保证供应链安全。对想深度定制 Fedora 镜像的开发者来说它是一份值得逐行研读的绝佳范本——45 行代码藏着现代容器构建的全部精髓。如果你也想动手实践可以git clone https://gitcode.com/gh_mirrors/main9/main把仓库拉下来直接阅读 Containerfile 与 build_files/ 目录下的脚本边读边验证本文的分析。【免费下载链接】mainOCI base images of Fedora with batteries included项目地址: https://gitcode.com/gh_mirrors/main9/main创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考