首页
/ Kubernetes 测试镜像全流程指南:从修改、构建、测试到发布 e2e 测试镜像

Kubernetes 测试镜像全流程指南:从修改、构建、测试到发布 e2e 测试镜像

2026-09-07 16:58:28作者:柯茵沙

Kubernetes 的端到端(E2E)测试依赖一套独立于主仓库之外维护的测试镜像,用来验证各类集群特性与功能。本文以 test/images/README.md 为主线,系统讲解这些镜像的设计动机、版本管理机制,以及完整的"修改镜像 → 构建镜像 → 本地测试 → 晋升发布"工作流,并结合仓库内 Makefileimage-util.shcloudbuild.yaml 与镜像目录的源码实现展开说明。读完本文,你将掌握为 Kubernetes E2E 测试镜像添加功能、正确升版、构建多架构镜像、改写镜像仓库并最终将其合入官方测试工作流所需的全部技能。

镜像的定位与多架构发布模型

test/images/ 下所有镜像都服务于 Kubernetes 测试,用于确保集群各项特性与功能的正确性(见 test/images/README.md)。这些镜像并非单架构产物,而是以 manifest list(manifest 列表) 的形式构建并发布,从而支持 multiarch 与跨平台使用。

从仓库目录看,test/images/ 下每个子目录即一个镜像,例如 agnhostbusyboxkittennautilusresource-consumersample-apiservernginxperl 等。每个镜像目录通常包含:

  • VERSION:镜像版本号,构建时作为 tag 使用(如 agnhost/VERSION 当前为 2.66.1);
  • BASEIMAGE:列出各 os/arch 对应的基础镜像(见下文);
  • Dockerfile 与可选的 Dockerfile_windows:区分 Linux/Windows 构建;
  • Makefile(可选):负责在构建镜像前先编译 Go 二进制;
  • ALIAS(可选):用于为镜像指定别名(如 nginx-new 的案例)。

BASEIMAGE 文件:多架构的"路线图"

image-util.shBASEIMAGE 文件为构建依据:每一行是一个 <os>/<arch>[=<base image>]os/arch/os_version=base image 条目。以 agnhost 的 BASEIMAGE 为例:

linux/amd64=alpine:3.21
linux/arm64=arm64v8/alpine:3.21
linux/ppc64le=ppc64le/alpine:3.21
linux/s390x=s390x/alpine:3.21
windows/amd64/1809=REGISTRY/busybox:1.38.0-1-windows-amd64-1809
windows/amd64/ltsc2022=REGISTRY/busybox:1.38.0-1-windows-amd64-ltsc2022
windows/amd64/ltsc2025=REGISTRY/busybox:1.38.0-1-windows-amd64-ltsc2025
  • 若镜像目录 没有 BASEIMAGE 文件,构建脚本会回退到默认平台集合 linux/amd64、linux/arm64、linux/ppc64le、linux/s390x(定义于 image-util.sh);
  • 含 Windows 条目的格式是 os/arch/os_version 三段式,因为 Windows 需按 OS 版本(1809、ltsc2022、ltsc2025)分别构建;
  • 值中的 REGISTRY 占位符会在构建时被替换为真实的 REGISTRY 环境变量值(见 getBaseImage 中的 sed 替换逻辑)。

在构建每个平台时,脚本先把镜像目录拷贝到临时目录,若存在 Makefile 则先执行 make bin OS=... ARCH=... TARGET=... 调用 image-util.shbin() 函数,在容器内以 CGO_ENABLED=0 交叉编译 Go 二进制;随后按 os/arch 决定使用 Dockerfile 还是 Dockerfile_windows,最终通过 docker buildx build --platform <os>/<arch> 产出带 -<os>-<arch>[-<os_version>] 后缀的镜像 tag。push 阶段再通过 docker manifest create --amenddocker manifest annotate 把这些分平台镜像合并成 manifest list 并推送(其中 Windows 条目会额外标注 --os-version,以便 Windows 节点拉取与自身匹配的镜像,见 image-util.sh)。

环境准备:Linux 构建节点与 buildx

构建 Docker 测试镜像需要一个 Linux 节点,并安装 makedocker 以及 docker buildx——多架构镜像与 Windows 镜像都依赖 buildx 完成。为保证多架构与 Windows 镜像能被正确构建,还需要一次性的初始化(CI 中该初始化定义在 cloudbuild.yaml 内):

docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx create --name img-builder --use
docker buildx inspect --bootstrap
  • 第一条命令安装 QEMU binfmt 处理器,使 Linux 节点能执行非本机架构的构建步骤;
  • 后两条创建并引导名为 img-builder 的 buildx builder 实例。

另外,构建节点必须能够向目标镜像仓库推送镜像,因此请确保已通过目标 registry 的认证。

更新测试镜像的整体流程

Kubernetes E2E 测试数以千计,但并非全部镜像都被每次 PR 触发使用(尤其是不属于 Conformance 测试的部分)。为了防止镜像回归导致测试任务失败,任何对镜像本身或其内置二进制的改动,都必须同步提升镜像版本号;若发生无法立即修复的回归,则会将 E2E 测试中使用的镜像版本回退到最后一个已知稳定版本。

E2E 测试套件中的大多数测试使用 agnhost 镜像。它包含若干子命令,用于校验不同的 Kubernetes 行为(详见 agnhost/README.md)。官方建议:当需要测试新功能时,先考虑把它实现为 agnhost 的一个子命令,而不是另起一个全新的测试镜像

更新镜像的完整流程分为四步,下文逐一展开:

  1. 对镜像做修改
  2. 构建镜像
  3. 测试改动
  4. 晋升发布改动

完成这四步后,你的镜像改动才会真正进入 e2e 测试。此外,对于全新镜像Windows 测试镜像还有额外注意事项。

agnhost:跨平台行为一致的瑞士军刀

由于 Linux 与 Windows 在行为与信息获取方式上存在显著差异(例如 DNS 后缀列表在 Linux 上位于 /etc/resolv.conf,Windows 上则没有该文件),agnhost(agnostic + host 的合成词)被设计成一个可扩展、行为与输出不随底层操作系统变化的 CLI。它的镜像同时覆盖 Linux 与 Windows 容器(Windows 版基于 busybox,而 busybox 又基于 nanoserver),从源码结构看,其子命令大多位于 agnhost/ 下的独立包中(如 dns/net/webhook/mounttest/fakeregistryserver/ 等)。

镜像内同时打包了大量测试常用工具(iperfcurl、包含 dig 的 dns-tools、CoreDNS),并预置了测试所需的监听端口(80/8080/8081/9376/5000,见 Dockerfile)以及 TLS 证书(localhost.crt/localhost.key)。值得一提的是,Dockerfile 还创建了 uid=1000 的用户与 gid=50000 的用户组,供 SupplementalGroups 相关 E2E 用例使用——这正是"测试镜像为具体用例服务"的典型证据。

创建并晋升全新镜像

首先请与 SIG Testing 沟通,确认能否先用 agnhost 满足需求(包括为其新增功能)。整合镜像的好处包括:

  • 减少打补丁的负担(依赖、基础镜像、Go 版本等只需在一处维护);
  • 降低运行时拉取镜像的依赖,从而加快测试速度;
  • 简化离线(airgap)测试环境——需要镜像/同步的镜像更少。

Kubernetes 社区正努力减少镜像总数。如果你确认需要增加一个完全独立的镜像,仍需与 SIG Testing 确认,并让它能被 Image Builder 自动构建——为此你需要在 kubernetes/test-infra 仓库中为它定义 postsubmit Prow job(官方通过运行 k8s-staging-e2e-test-images.sh 脚本来生成)。

Windows 测试镜像注意事项

理想情况下,同一个 Dockerfile 应能同时构建 Windows 与 Linux 镜像,但并非总能如此。若某个镜像需要独立的 Windows Dockerfile,应命名为 Dockerfile_windows;构建时 image-util.sh 会优先在 Windows 构建中检查该文件。

构建过程虽然都用 docker buildx,但 Windows 镜像存在若干已知限制(这些限制也解释了仓库内 Dockerfile_windows 为何采用特定写法):

  • Dockerfile 可以包含多阶段,但 Windows 阶段不能有任何 RUN 命令(参见 agnhost 的 Dockerfile_windows:所有依赖 RUN 的准备工作——下载并解压 CoreDNS、iperf、coreutils——都在 linux/$BUILDARCH 的 prep 阶段完成,再用 COPY --from= 拷入 Windows 阶段);
  • Windows 阶段不能有 WORKDIR(docker/buildx issue #378);
  • 向 Windows 镜像拷贝 symlink 时,buildx 会改写 symlink 目标并加 Files\ 前缀(docker/buildx issue #373)。规避方式是使用相对路径的 symlink 目标并在对应位置存在目标副本(参见 busybox 的 Dockerfile_windows);
  • docker buildx 会把镜像的 PATH 环境变量覆盖成 Linux 风格,这在 Windows 上无法正常工作(moby/buildkit issue #1560),因此 agnhost 的 Dockerfile_windowsENV PATH=... 显式写回 Windows 风格 PATH;
  • 所有 Windows 镜像的基础镜像是 nanoserver,它比 Windows Servercore 小约 10 倍。大多数二进制可直接运行,但少数因缺少依赖而无法工作(注意:即使加入的二进制无法运行,镜像依然能构建成功)。例如 coredns.exe 依赖 netapi32.dll,nanoserver 中没有该 DLL,需从 servercore 镜像中拷贝(见 Dockerfile_windows,其来源镜像即 windows-servercore-cache)。经验法则:优先选用 64 位应用(依赖更少),并用宿主机上的 procmon.exe(使用进程隔离而非 Hyper-V 隔离)排查缺失依赖。

由于 buildx 对 Windows 阶段 RUN 的限制,构建 Windows 镜像需要一个 Windows helper 镜像(否则需要 Windows 构建节点)。该 helper 镜像位于 e2eteam/powershell-helper:6.2.7,其构建细节见 windows/README.md,对应的 Dockerfile 位于 test/images/windows/powershell-helper/

最后,Windows 上若要启动进程隔离容器,容器 OS 版本需与宿主机 OS 版本高度匹配。因此测试镜像为多个 Windows OS 版本分别构建:1809(Windows Server 2019)、ltsc2022(Windows Server 2022)、ltsc2025(Windows Server 2025)。若要支持新的 Windows OS 版本,需要先在 windows-servercore-cachebusybox 镜像中为该版本新增条目(这两个镜像被其他 E2E 测试镜像用作缓存/基础镜像),再推广到其余镜像。

修改镜像与版本管理

修改镜像功能以满足测试用例需求后,必须更新版本号。版本号只需修改镜像目录下的 test/images/${IMAGE_NAME}/VERSION 文件,构建时该值会作为镜像 tag 使用(见 image-util.sh)。

注意镜像间的父子依赖:部分测试镜像(如 agnhost)会被用作其他镜像(如 kittennautilus)的基础镜像。看 kitten/BASEIMAGE 可发现其条目指向 REGISTRY/agnhost:2.66.1-...,即引用了 agnhost 的分平台镜像 tag。因此:

  • 若父镜像(如 agnhost)的 VERSION 被提升,必须同步提升子镜像(kitten、nautilus 等)BASEIMAGE 文件中的版本引用,否则子镜像无法反映父镜像的改动。

同时要意识到:Kubernetes CI 在镜像晋升发布之前不会使用你的改动。因此建议先把镜像构建并推送到自己的仓库,用真实测试验证通过,再进入发布流程。

构建镜像

测试镜像统一通过 make 构建,入口是 test/images/Makefile。由于部分镜像(如 agnhost)是其他镜像的基础,若涉及这类镜像建议优先构建它们

构建单个镜像:

make all WHAT=agnhost

构建并推送镜像:

make all-push WHAT=agnhost

Makefile 可以看到两者的实现差异:all 只调用 image-util.sh build ... "docker"(输出到本地 docker daemon);all-push 则先以 "registry" 作为 output type 构建、再执行 push(输出直接进 registry 并用 manifest list 合并)。因此本地 make all 只构建 Linux 平台(Windows 容器镜像必须推送到 registry,见 image-util.shdocker 输出类型会跳过 Windows 的逻辑)。

默认情况下,镜像会被打 tag 并推送到 registry.k8s.io/e2e-test-images 仓库(REGISTRY 变量的默认值,定义在 Makefile)。如需使用自定义仓库:

REGISTRY=foo_registry make all-push WHAT=agnhost

(面向 gcr.io 测试镜像发布者):部分测试(如 "should serve a basic image on each replica with a private image")要求 agnhost 镜像同时发布到一个经过认证的私有仓库,因此需要分两次推送:

REGISTRY=registry.k8s.io/e2e-test-images make all-push WHAT=agnhost
REGISTRY=gcr.io/k8s-authenticated-test make all-push WHAT=agnhost

此外,WHAT=all-conformance 用于构建/推送 E2E Conformance 测试中最常用的镜像子集。从 image-util.sh 可见,该目标只会处理 8 个镜像:busyboxagnhostglibc-dns-testingkittennautilusnonewprivsresource-consumersample-apiserver——因为完整构建 test/images/ 下所有镜像耗时极长,且部分镜像极少使用。CI 侧,cloudbuild.yaml 通过 $_WHAT$_REGISTRY$_PULL_BASE_SHA 等 substitution 调用 make all-build-and-push,将镜像发布到 staging 仓库 gcr.io/k8s-staging-e2e-test-images

构建细节层面,每个平台镜像都会携带构建元数据 label:image_version=<TAG>commit_id=<GIT_COMMIT_ID>git_url=...(见 image-util.sh),便于追溯镜像来源;同时构建使用 --no-cache --pull 保证可复现性。

测试镜像改动

镜像构建并推送到了可访问的仓库之后,就可以用指向该仓库的 E2E 测试来验证改动。方法是在运行相关测试前设置环境变量:

export KUBE_TEST_REPO_LIST=/path/to/repo_list.yaml

repo_list.yaml 是 E2E 测试读取的仓库重定向配置。其字段由 manifest.go 中的 RegistryList 结构体定义(YAML 字段与结构体 tag 一一对应),包括 promoterE2eRegistrybuildImageRegistryinvalidRegistrygcEtcdRegistrygcRegistrysigStorageRegistryprivateRegistrydockerLibraryRegistrycloudProviderGcpRegistry 等。示例文件只需给出你要覆盖的仓库:

promoterE2eRegistry: your-awesome-registry
gcRegistry: your-awesome-registry
sampleRegistry: your-awesome-registry

readRepoList 会读取该 YAML 并覆盖默认 registry 配置(也支持以 http(s):// 开头的 URL 形式),随后通过 initImageConfigs 生成每个镜像的 {registry, name, version} 映射;当 KUBE_TEST_REPO_LIST 未设置时则回退到 manifest.go 中的内置默认 registry。由于 imageConfigs 在包初始化阶段(var ... = readRepoList(...))就已从环境变量读取,该环境变量必须在测试进程启动前就设置好。

要留意的是,一个测试可能使用多个镜像,所以最好把相关镜像一并构建并推送。例如从 manifest.go 可见,仅 agnhost 一族就被拆成了 Agnhost(默认 2.66.1)、AgnhostPrev2.55,供滚动升级类测试使用)与 AgnhostPrivate(私有认证仓库 agnhost:2.6)三个配置项。

让 E2E 测试使用新版本镜像

即便构建推送完成,E2E 测试真正引用的镜像 tag 仍硬编码在 test/utils/image/manifest.go 中(如 configs[Agnhost] = Config{list.PromoterE2eRegistry, "agnhost", "2.66.1"})。因此还需要修改该文件中的镜像版本,并重新编译测试二进制:

./build/run.sh make WHAT=test/e2e/e2e.test

之后即可运行期望的测试来验证改动是否生效。

晋升发布(Promoting Images)

在本地完成改动与测试后,即可通过如下多步骤流程把改动分享出去(这也是改动真正进入官方 E2E 测试的最后环节):

  1. 在同一 PR 中提升镜像版本:每个测试镜像目录下都有 VERSION 文件,例如 agnhost 的版本文件在 test/images/agnhost/VERSION。这一步与"修改镜像"阶段同步完成。

  2. 等待自动 postsubmit job 构建:PR 被批准并合并后,会自动触发 postsubmit job 构建发生改动的镜像。例如改动在 test/images/agnhost,会触发 post-kubernetes-push-e2e-agnhost-test-images job,把镜像推送到 staging 仓库 gcr.io/k8s-staging-e2e-test-images。你可以用 staging 仓库的镜像做更多测试。所有镜像的 postsubmit job 及其日志可在 testgrid 的 sig-testing-images 面板查看,便于排查问题。注意:这些 staging 镜像与 E2E job 实际使用的镜像不同,仍需晋升到最终仓库。

  3. 晋升到最终仓库:在 kubernetes/k8s.io 仓库的 registry.k8s.io/images/k8s-staging-e2e-test-images/images.yaml 中增加一行,把镜像晋升到 registry.k8s.io/e2e-test-images。晋升需要镜像 manifest list 的 digest,可用 manifest-tool 获取:

    manifest-tool inspect --raw gcr.io/k8s-staging-e2e-test-images/${IMAGE_NAME}:${VERSION} | jq '.[0].Digest'
    
  4. 更新 E2E 测试引用:最后开一个 PR,更新 test/utils/image/manifest.go 中镜像 tag,让 E2E 测试改用新晋升的镜像。

完成以上步骤后,你的改动就会被 E2E 测试正式采用。

已知问题与规避手段

docker manifest create 因权限问题失败:错误表现为在 /etc/docker/certs.d/gcr.io 上 permission denied。解决方式是放开 /etc/docker 的执行权限:

sudo chmod o+x /etc/docker

同 SHA 无法重复推送busyboxnginxnginx-newperl 等镜像从 dockerhub 镜像到 gcr.io/k8s-staging-e2e-test-images 后,只保留了一个 noop Dockerfile。由于 test-infra 的已知问题,同一 SHA 不能重复推送;对这些镜像做一次小改动以产生新的 SHA,才能重新推送并晋升。

小结

测试镜像是 Kubernetes E2E 质量保障体系中容易被忽视却至关重要的一环。其核心机制可归纳为四点:VERSION + BASEIMAGE 驱动的多架构构建模型agnhost 为优先复用对象的镜像整合策略manifest.go 为唯一事实来源的镜像引用管理,以及 staging → 最终仓库的两段式晋升流程。理解并遵守这套流程,既能避免镜像回归拖垮海量 E2E 任务,也能让新特性以标准化方式进入官方测试体系。若需深入研究,建议继续阅读 agnhost 子命令文档镜像构建脚本E2E 镜像引用配置

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391