Cilium 容器镜像构建实战:从开发镜像到官方发布镜像的完整机制解析
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
本文围绕 Cilium 官方开发文档《Building Container Images》(Documentation/contributing/development/images.rst)展开,系统讲解如何在本地基于当前检出的代码分支构建 cilium-agent 与 cilium-operator 的开发者镜像、如何构建官方发布镜像,以及 cilium-builder/cilium-runtime 两个基础镜像的完整更新流程。读完本文,你将能够独立完成 Cilium 容器镜像的本地构建、推送,并深入理解镜像仓库划分、多平台构建、镜像摘要钉扎(digest pinning)与 CI 镜像生命周期管理的源码级实现细节。
一、Cilium 官方镜像仓库体系
Cilium 团队的镜像仓库遵循统一的构建与发布规范:所有镜像均通过 GitHub Actions 从对应的 GitHub 仓库自动构建,且全部是多平台镜像(multi-platform),同时支持linux/amd64与linux/arm64两种架构。
各 GitHub 仓库与镜像仓库的对应关系如下(继承自官方文档):
| GitHub 仓库 | Dockerfile | 容器镜像仓库 |
|---|---|---|
| github.com/cilium/cilium | images/builder/Dockerfile | quay.io/cilium/cilium-builder |
| images/cilium/Dockerfile | [quay|docker].io/cilium/cilium | |
| images/clustermesh-apiserver/Dockerfile | [quay|docker].io/cilium/clustermesh-apiserver | |
| images/hubble-relay/Dockerfile | [quay|docker].io/cilium/hubble-relay | |
| images/operator/Dockerfile | [quay|docker].io/cilium/operator | |
| [quay|docker].io/cilium/operator-alibabacloud | ||
| [quay|docker].io/cilium/operator-aws | ||
| [quay|docker].io/cilium/operator-azure | ||
| [quay|docker].io/cilium/operator-generic | ||
| images/runtime/Dockerfile | quay.io/cilium/cilium-runtime | |
| github.com/cilium/cilium-cli | Dockerfile | quay.io/cilium/cilium-cli |
| github.com/cilium/image-tools | images/bpftool/Dockerfile | quay.io/cilium/cilium-bpftool |
| images/compilers/Dockerfile | quay.io/cilium/image-compilers | |
| images/llvm/Dockerfile | quay.io/cilium/cilium-llvm | |
| images/maker/Dockerfile | quay.io/cilium/image-maker | |
| images/startup-script/Dockerfile | quay.io/cilium/startup-script | |
| github.com/cilium/proxy | Dockerfile.builder | quay.io/cilium/cilium-envoy-builder |
| Dockerfile | quay.io/cilium/cilium-envoy |
其中 builder、runtime、cilium、operator、hubble-relay 这几个核心镜像的定义文件与说明文档就在本仓库中,各镜像的职责描述见 images/README.md:
- builder 镜像:基于 Ubuntu,提供
protoc及插件、Go 工具链、交叉编译工具链,以及用于编译 BPF 数据面的clang编译器(来自 cilium-llvm 镜像); - runtime 镜像:提供
cilium-agent运行所需的全部用户态依赖——网络工具(iproute2、iptables、ipset、kmod)、clang/llc工具链、bpftool(两者均来自 cilium/image-tools),以及 CNI loopback 插件;另含gops与 Ubuntu 用户态环境用于排障; - cilium 镜像:包含
cilium-agent及其他二进制(cilium-dbg、envoy、cilium-health、hubble-cli),基于 runtime 镜像; - operator 镜像:只包含
cilium-operator二进制与 CA 证书,不引入其他二进制或库。同一个 Dockerfile 依据OPERATOR_VARIANT构建参数的取值构建 alibabacloud、aws、azure、generic 等变体; - hubble-relay 镜像:只包含
hubble-relay二进制与 CA 证书。
镜像依赖树
镜像之间并非彼此独立,官方文档给出了清晰的依赖结构:
cilium/cilium ├── cilium/cilium-builder │ └── cilium/cilium-llvm └── cilium/cilium-runtime ├── cilium/cilium-bpftool └── cilium/cilium-llvm cilium/cilium-envoy └── cilium/cilium-envoy-builder cilium/operator └── cilium/cilium-builder └── cilium/cilium-llvm也就是说,最终的cilium/cilium与cilium/operator应用镜像分别依赖cilium-builder与cilium-runtime两个"底座"镜像,而这两个底座又共享cilium-llvm、cilium-bpftool等更底层的工具链镜像。理解这棵依赖树是理解后续"更新基础镜像"流程的关键。
二、构建本地开发者镜像(Developer Images)
仓库提供了两个 make 目标,可以基于本地检出的分支自动构建包含你本地改动的容器镜像。
构建 cilium-agent 镜像
运行make dev-docker-image构建包含本地变更的 cilium-agent Docker 镜像:
ARCH=amd64 DOCKER_DEV_ACCOUNT=quay.io/myaccount DOCKER_IMAGE_TAG=jane-developer-my-fix make dev-docker-image构建 cilium-operator 镜像
运行make docker-operator-generic-image(或对应的docker-operator-aws-image、docker-operator-azure-image)构建 cilium-operator Docker 镜像:
ARCH=amd64 DOCKER_DEV_ACCOUNT=quay.io/myaccount DOCKER_IMAGE_TAG=jane-developer-my-fix make docker-operator-generic-image以上命令假定你在quay.io上的用户名是myaccount。
环境变量在源码中的解析逻辑
这些环境变量的处理逻辑可以直接在 Makefile.docker 中找到:
DOCKER_REGISTRY ?= quay.io ifeq ($(findstring /,$(DOCKER_DEV_ACCOUNT)),/) # DOCKER_DEV_ACCOUNT already contains '/', assume it specifies a registry IMAGE_REPOSITORY := $(DOCKER_DEV_ACCOUNT) else IMAGE_REPOSITORY := $(DOCKER_REGISTRY)/$(DOCKER_DEV_ACCOUNT) endifDOCKER_DEV_ACCOUNT:若值中包含/,则被整体视为"registry/用户名"形式的镜像仓库前缀;否则自动拼接默认 registryquay.io。这就是为什么示例中要写成quay.io/myaccount;DOCKER_IMAGE_TAG:镜像 tag,示例中的jane-developer-my-fix便于区分不同开发者的构建;ARCH:控制构建平台。当指定ARCH时,Makefile.docker 会走 docker buildx 的多平台路径:
ifdef ARCH # Default to multi-arch builds, always create the builder for all the platforms we support DOCKER_PLATFORMS := linux/arm64,linux/amd64 ... # Override default for a single platform ifneq ($(ARCH),multi) DOCKER_PLATFORMS := linux/$(ARCH) endif DOCKER_FLAGS += --push --platform $(DOCKER_PLATFORMS)即指定ARCH=amd64只构建 amd64 单平台并推送;ARCH=multi(或配合支持双平台的 builder)则同时构建linux/arm64,linux/amd64;不指定ARCH时,构建回落到--load模式——只在本机加载镜像、不推送,模拟普通docker build的行为。
每个镜像目标由统一的模板DOCKER_IMAGE_TEMPLATE生成,模板会注入以下构建参数:
CILIUM_SHA:当前 git 版本;MODIFIERS:把NOSTRIP、NOOPT、LOCKDEBUG、RACE、V等构建修饰符透传给容器内的 make;OPERATOR_VARIANT:operator 镜像的变体标识;--target:release 或 debug 两种构建目标(见下文 cilium 镜像的 debug 阶段)。
模板还定义了-unstripped变体(NOSTRIP=1+-unstripped后缀),用于保留完整调试符号的镜像,例如dev-docker-image-unstripped。
重定向基础镜像的拉取源
设置BASE_IMAGE_REGISTRY可以重定向基础镜像(cilium-builder、cilium-runtime、cilium-envoy)的拉取地址。这样既能保持 Dockerfile 中的 tag/digest 钉扎不变,又可以在构建时使用自定义 registry:
$(if $(BASE_IMAGE),--build-arg BASE_IMAGE=$(BASE_IMAGE),)带竞态检测的镜像
若需要构建开启 Go 竞态检测的镜像,参考官方文档中 compile Cilium with race detection 一节的做法,通过构建修饰符传入RACE=1即可(与源码make RACE=1等价)。
三、构建官方发布镜像(Official Release Images)
任何人都可以使用下面的 make 目标构建官方发布镜像:
DOCKER_IMAGE_TAG=v1.4.0 make docker-images-all从 Makefile.docker 可以看到docker-images-all实际展开为:
docker-images-all: docker-cilium-image docker-hubble-relay-image \ docker-clustermesh-apiserver-image docker-operator-images-all \ docker-standalone-dns-proxy-image docker-operator-images-all: docker-operator-image docker-operator-aws-image \ docker-operator-azure-image docker-operator-alibabacloud-image \ docker-operator-generic-image也就是说,docker-images-all一次性覆盖 cilium、hubble-relay、clustermesh-apiserver、standalone-dns-proxy 以及全部 5 个 operator 变体,这正是 CI 使用的目标(注释标明docker-*-all targets are mainly used from the CI)。
四、核心 Dockerfile 的多平台构建机制
cilium 镜像:builder 增量构建 + 调试符号分离
images/cilium/Dockerfile 开头钉扎了三个基础镜像,tag 与 sha256 digest 同时锁定:
ARG CILIUM_BUILDER_IMAGE=quay.io/cilium/cilium-builder:be12da3a...@sha256:969449d0bc... ARG CILIUM_RUNTIME_IMAGE=quay.io/cilium/cilium-runtime:c9cad76d...@sha256:d05d3500fc... ARG CILIUM_ENVOY_IMAGE=quay.io/cilium/cilium-envoy:v1.38.4-...@sha256:1b958363...构建流程分为几个关键阶段:
- builder 阶段(
FROM --platform=${BUILDPLATFORM}):在构建机本征平台上挂载仓库源码与 BuildKit 缓存,执行make GOARCH=${TARGETARCH} ... build-container install-container-binary,实现一次构建、跨架构安装; - 调试符号提取:所有可执行文件先用
objcopy --only-keep-debug抽取.debug符号文件到/tmp/debug,随后在NOSTRIP未设置时执行--strip-all并回写--add-gnu-debuglink; - release 阶段:
FROM ${CILIUM_RUNTIME_IMAGE},从 builder 拷贝安装产物,设置HUBBLE_SERVER=unix:///var/run/cilium/hubble.sock(容器内 Hubble CLI 走本地 unix socket 而非 Relay),CMD为cilium-dbg; - debug 阶段:在 release 镜像之上安装 delve,并用
debug-wrapper脚本包装cilium-agent,在专用端口自动挂载调试器,供dev-docker-image-debug等-debug目标使用。
runtime 镜像:用户态依赖的"最小完整集"
images/runtime/Dockerfile 基于 Ubuntu 26.04 与 golang 1.27.1,从cilium-llvm:21.1.8与cilium-bpftool:7.7.0镜像中提取编译器与 bpftool:
ENV FORCE_BUILD=4 # Change the number to force the generation of a new git-tree SHA. Useful when # we want to re-run 'apt-get upgrade' for stale images.其中FORCE_BUILD变量值得注意:runtime 镜像以目录的git tree hash作为 tag,目录内容不变时 tree hash 也不变、缓存不会失效。当需要强制重新执行apt-get upgrade刷新过时的系统包时,只需手工修改FORCE_BUILD的数值,使 tree hash 变化即可触发全量重建。此外该镜像还构建了gops、CNI loopback 插件与iptables-wrapper(首次调用时自动探测宿主机的 legacy/nft iptables 后端并重置符号链接)。
builder 镜像:编译工具链的"全家桶"
images/builder/Dockerfile 安装了 amd64/arm64 双向交叉编译工具链、Go 工具链、protoc及插件、delve,并从 cilium-llvm 镜像只拷贝clang、llvm-objcopy、llvm-strip(注释说明 BPF 构建是 clang-only,verifier 测试从 cilium-llvm 镜像提取工具链而非此镜像)。镜像构建还接入了container-structure-test(test阶段)做结构校验,测试清单见 images/builder/test/spec.yaml。
五、更新 cilium-builder 与 cilium-runtime 镜像的标准流程
这是官方文档中操作性最强的章节,完整继承其七步流程,并补充源码层面的机制说明。
前提:流程的起点是一个"更新镜像版本号"的本地提交(即把新镜像的 tag/digest 写入各 Dockerfile),完成下述步骤后会生成第二个提交,包含所有随镜像更新需要联动的代码库变更。官方明确要求两个提交必须保持分离,以便日后 backport。若只是想让这两个镜像内的软件包升级,可以手工修改 images/runtime/Dockerfile 中的FORCE_BUILD变量为不同的值,然后按相同步骤走。
提交变更并在 cilium/cilium 上创建 PR:
$ git commit -sam "images: update cilium-{runtime,builder}"请 team/build 成员批准:PR 提交后,GitHub Actions 的 "Base Image Release Build" 工作流会自动构建基础镜像,需要该团队成员批准。
等待构建完成:若 PR 来自外部 fork,构建在推送镜像时会失败——这是预期行为。
外部 fork 场景:本地回写镜像引用并重新推送:
$ make -C images/ update-runtime-image $ git commit -sam "images: update cilium-{runtime,builder}" --amend $ make -C images/ update-builder-image $ git commit -sam "images: update cilium-{runtime,builder}" --amend主仓库场景:构建会自动生成一个提交并推送到你的分支,包含仓库内所有文件的联动修改。
运行完整 CI 并确保通过。
合并 PR。
更新脚本的源码机制
上一步的update-runtime-image/update-builder-image目标定义在 images/Makefile 中:
update-runtime-image: scripts/update-cilium-runtime-image.sh $(RUNTIME_IMAGE) $(RUNTIME_DIRECTORY) update-builder-image: scripts/update-cilium-builder-image.sh以 runtime 为例,images/scripts/update-cilium-runtime-image.sh 做了三件事:
- 通过
make-image-tag.sh为images/runtime目录计算新的git tree hash作为 tag; - 调用
get-image-digest.sh从 registry 拉取该镜像的 sha256 摘要,拼成image:tag@sha256:...形式; - 把完整的引用回写给 images/runtime/update-cilium-runtime-image.sh,后者用
sed批量替换所有引用CILIUM_RUNTIME_IMAGE=的 Dockerfile 及 GitHub Actions 文件:
used_by=($(git grep -l "${image}:" .github/actions/; find . -type f -name 'Dockerfile*' -print0 \ | xargs -0 git grep -l CILIUM_RUNTIME_IMAGE= | sort -u)) for i in "${used_by[@]}" ; do sed -E "s#${image}:.*#${image_full}#" "${i}" > "${i}.sedtmp" && mv "${i}.sedtmp" "${i}" donebuilder 侧的 images/builder/update-cilium-builder-image.sh 同理,额外覆盖.devcontainer/devcontainer.json中的镜像引用。
tag 生成规则:tree hash、-dev 与 -wip
images/scripts/make-image-tag.sh 实现了两套打标策略,值得单独说明:
- 子目录镜像(runtime、builder):使用
git ls-tree --full-tree HEAD -- <dir>得到的tree hash作为 tag。这样做的好处是——用git show <tree-hash>可以直接看到构建该镜像时的目录内容,消除"这个镜像到底用了什么输入构建"的疑问; - 全树镜像:优先使用符合
vX.Y.Z格式的版本 tag;否则用短 commit hash。若当前提交不在origin/main祖先链上(开发分支),追加-dev后缀;若工作区有未提交改动,追加-wip后缀,明确标识非权威构建。
另外,images/Makefile还提供check-runtime-image/check-builder-image目标(CHECK=true模式):脚本会执行git diff --exit-code校验各 Dockerfile 中的引用是否与 registry 实际镜像一致,不一致即报错提示参考本流程——这是 CI 中防止"镜像引用漂移"的守门检查。
六、CI 中的镜像构建与生命周期管理
所有镜像由 GitHub Actionbuild-images自动创建:
- 该 Action 对所有Pull Request 自动运行,包括来自 fork 仓库的 PR;
- 构建产物推送到
quay.io/cilium/*-ci命名空间; - 这些 CI 镜像保留 1 周,之后由
ci-images-garbage-collect工作流清理; - 镜像被清理后,开发者必须重新推送 PR(如 push 一个空提交),以触发新的镜像构建。
这套机制保证了评审过程中任何时刻使用的镜像都是"PR 当时代码"对应的产物,且不会无限占用 registry 空间。
七、本地直接构建底座镜像(images 子目录)
除了顶层make dev-docker-image,也可以在images/子目录内直接构建与推送底座镜像,其目标是独立的一套(见 images/Makefile 与 images/README.md):
# 构建 runtime 镜像(linux/amd64 + linux/arm64) make -C images runtime-image # 推送到指定 registry make -C images runtime-image PUSH=true REGISTRIES=docker.io/<username>make -C images all-images会依次完成 lint、runtime-image、builder-image、cilium-image、operator-image、hubble-relay-image 的全量构建。需要注意:新构建的 runtime/builder 镜像若要被 cilium 镜像消费,必须按第五节的流程把 images/cilium/Dockerfile 中的CILIUM_RUNTIME_IMAGE/CILIUM_BUILDER_IMAGE引用更新为新 tag+digest(或借助 update 脚本自动完成)。
八、小结
Cilium 的容器镜像体系可以归纳为三层:
- 底座层:
cilium-llvm、cilium-bpftool(来自 cilium/image-tools 仓库)提供编译工具链; - 平台层:
cilium-builder(编译环境)与cilium-runtime(运行依赖),以 git tree hash 打标、digest 钉扎,通过 update 脚本与CHECK=true校验保证全仓库引用一致; - 应用层:
cilium、cilium/operator*、hubble-relay、clustermesh-apiserver、standalone-dns-proxy,由 Makefile.docker 的统一模板驱动,支持多平台构建、release/debug 双目标与竞态检测等构建修饰符。
掌握这套机制后,无论是日常开发中的make dev-docker-image、发布流程中的DOCKER_IMAGE_TAG=vX.Y.Z make docker-images-all,还是基础镜像的例行升级,都有了清晰可操作的命令入口与源码级依据。
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考