Kubespray KubeVirt 镜像构建器实战为 CI 构建并推送 KubeVirt 虚拟机磁盘镜像【免费下载链接】kubesprayDeploy a Production Ready Kubernetes Cluster项目地址: https://gitcode.com/GitHub_Trending/ku/kubespray本文基于 Kubespray 仓库中 test-infra/image-builder/README.md 展开系统讲解 Kubespray CI 使用的 KubeVirt 虚拟机磁盘镜像构建器它如何下载上游云镜像、转换为 qcow2、扩容并打包为容器镜像推送至镜像仓库。读完本篇你可以完整复现新增一个操作系统镜像、本地验证、构建推送的全流程并理解 Makefile 中各目标与 Ansible 角色参数之间的对应关系。工作原理KubeVirt Image Builder 位于 test-infra/image-builder/其定位是为 Kubespray CI 测试构建并推送 KubeVirt 虚拟机磁盘镜像。整体流程由 Makefile 驱动 Ansible playbook cluster.yml 完成playbook 会调用唯一的核心角色 kubevirt-images下载从上游源拉取各操作系统的 cloud image原始.img或.qcow2部分带.xz压缩转换非 qcow2 格式如 Ubuntu 的 raw.img通过qemu-img convert -O qcow2转为 qcow2扩容对每块镜像执行qemu-img resize 8G为 CI 中的系统安装与测试留出磁盘空间打包将 qcow2 文件作为cloud_image构建参数注入 Dockerfile基于kubevirt/registry-disk-v1alpha基础镜像构建容器镜像推送默认推送为quay.io/kubespray/vm-os-name:tag。受信 CI 任务可通过覆盖 registry 目标实现镜像的分阶段发布staged publishing。Dockerfile 模板极简见 templates/DockerfileFROM kubevirt/registry-disk-v1alpha ARG cloud_image LABEL org.opencontainers.image.authorsThe Kubespray Project kubespraygooglegroups.com COPY $cloud_image /disk即把转换好的磁盘文件直接拷入基础镜像的/diskKubeVirt 的 registry disk data volume 机制正是通过这种磁盘即容器镜像的方式给 VM 挂载磁盘。受信的分阶段发布路径使用 Cloud Build 认证并跳过docker loginmake push-single-staging image_nameubuntu-2404前置条件按 README 要求构建环境需要Docker、qemu-img来自 qemu 工具包、Ansible对 quay.io 上 kubespray 组织的推送权限robot 账号kubespraybuildvmimages。角色任务在开始构建前会实际校验这些依赖tasks/main.yml 中依次执行qemu-img --version必检与docker --version仅当kubevirt_container_builder docker时检查BuildKit 路径则额外探测buildctl-daemonless.sh/buildctlbuildkitd的可用性。镜像定义所有 OS 的单一事实来源所有操作系统镜像定义集中在 roles/kubevirt-images/defaults/main.yml。每个条目包含以下字段字段说明filename下载后的文件名url上游 cloud image 下载地址checksum用于下载校验的校验和sha256:或sha512:前缀converted源镜像已是 qcow2 时为true需要qemu-img convert时为falsetagDocker 镜像标签通常为latest当前定义覆盖 24 个镜像例如ubuntu-2404: filename: ubuntu-24.04-server-cloudimg-amd64.img url: https://cloud-images.ubuntu.com/releases/noble/release-20260826/ubuntu-24.04-server-cloudimg-amd64.img checksum: sha256:d0fe84bb5f80853425fa6be28e2c106f30104c3cfe8611933f2e65c9b63f0e30 converted: false tag: latest fedora-43: filename: Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2 url: https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2 checksum: sha256:846574c8a97cd2d8dc1f231062d73107cc85cbbbda56335e264a46e3a6c8ab2f converted: true tag: latest可以从字段取值看出几个实践要点Ubuntu 官方云镜像是 raw 格式的.img因此converted: false角色会执行qemu-img convertFedora、Rocky、openEuler 等已是 qcow2converted: true角色只做复制校验和前缀随上游提供格式而定Ubuntu/Fedora/Rocky/openEuler 用sha256:Debian 上游提供sha512:Flatcar 也是sha512:带.xz压缩的镜像如 Fedora CoreOS、openEuler会被角色中的unxz --force步骤自动解压解压后再按converted标志处理。使用方式构建并推送全部镜像cd test-infra/image-builder/ make docker_passwordquay-robot-tokenMakefile 中的deploy目标会调用ansible-playbook -i hosts.ini把docker_host、docker_login、docker_user、docker_password、docker_password、registry作为额外变量注入 cluster.yml。其中 hosts.ini 定义了一台远程构建主机image-builder-1 ansible_ssh_hostxxx.xxx.xxx.xxx [image-builder] image-builder-1playbook 通过hosts: {{ kubevirt_images_target_host | default(image-builder) }}指定目标因此这条deploy路径是面向远程 builder 主机的需要 SSH 可达。新增一个操作系统镜像在 defaults/main.yml 中添加条目new-os-name: filename: cloud-image-file.qcow2 url: https://example.com/cloud-image-file.qcow2 checksum: sha256:hash converted: true tag: latest构建并推送该镜像make docker_passwordquay-robot-token如果只想构建单个镜像用make push-single-docker image_namenew-os-name即可对应 Makefile 中通过kubevirt_images_selected过滤。提交包含defaults/main.yml变更的 PR使 CI 可以使用新镜像上游有真实示例 PR #12379 可供参考。Makefile 目标全解Makefile 顶部定义了默认变量理解它们是理解全部目标的关键docker_host ? quay.io docker_login ? true docker_user ? kubespraybuildvmimages registry ? quay.io/kubespray staging_registry ? us-central1-docker.pkg.dev/k8s-staging-images/kubespray各目标对应的行为目标执行方式用途deploy-i hosts.ini推送至远程 builder远程构建全部镜像并推送push-dockerlocalhost, -c localkubevirt_images_pushtruebuilderdocker本地构建全部镜像并推送push-single-docker同上 kubevirt_images_selected[$(image_name)]本地构建并推送单个镜像push-single-staging强制docker_hostus-central1-docker.pkg.dev、registry$(staging_registry)、docker_loginfalse受信分阶段发布到 Google Artifact Registry走 Cloud Build 认证、跳过 docker loginvalidate/validate-singlekubevirt_images_pushfalsebuilderbuildkit输出目录.image-builder/buildkit-outputCI 本地验证只构建不推送validate-docker/validate-single-dockerkubevirt_images_pushfalsebuilderdocker用 Docker 路径本地验证validate这条路径在本地运行并使用 BuildKit因此不依赖 SSH 访问远程构建主机也不依赖 Docker daemon——这正是 README 中 CI Validation 一节强调的特性cd test-infra/image-builder/ make validate # 仅构建全部镜像 make validate-single image_nameubuntu-2404 # 仅构建单个镜像从源码结构看不推送的实现是BuildKit 构建的输出从typeimage,...,pushtrue切换为typeoci,dest输出目录/vm-key-tag.tar见 tasks/main.yml即以 OCI tar 落地到本地目录完成验证。运行时变量三个决定行为模式的关键变量及其默认值定义于 defaults/main.ymlkubevirt_images_push默认true置为false时跳过 docker login/push/logoutkubevirt_images_selected默认[]要构建的镜像键列表空列表表示构建全部kubevirt_container_builder默认docker设为buildkit可在没有 Docker daemon 访问权限的本地 CI 中做验证。此外还有几个配套变量images_dir默认/images/base磁盘镜像的工作目录docker_user默认kubespraybuildvmimages、docker_host默认quay.io、docker_login默认true、registry默认quay.io/kubespraykubevirt_buildkit_output_dir默认{{ images_dir }}/buildkit-outputBuildKit 验证模式的 OCI tar 输出位置Makefile 的 validate 目标将其覆盖为$(CURDIR)/.image-builder/buildkit-output。角色开头有三道参数断言可以快速定位配置错误选中的镜像名必须能在images中找到否则报No matching images foundkubevirt_container_builder只能是docker或buildkitBuildKit 模式当前要求kubevirt_images_pushfalseBuildKit validation currently requires kubevirt_images_pushfalse。构建任务的执行细节角色任务 tasks/main.yml 的执行顺序值得逐条过一遍它能解释每个配置字段的实际用途过滤kubevirt_images_to_build依据kubevirt_images_selected是否为空来决定是取全部images还是community.general.keep_keys过滤后的子集——这就是单个镜像构建的底层实现依赖检查qemu-img --version、按 builder 检查 Docker 或 BuildKit下载get_url直接带checksum校验下载任何上游文件变化都会在此失败解压unxz --force仅当文件名以.xz结尾时执行转换或复制converted: false时执行qemu-img convert -O qcow2 源文件 镜像名.qcow2converted: true时直接cp为镜像名.qcow2。最终所有镜像统一以镜像键 .qcow2命名扩容qemu-img resize 镜像名.qcow2 8G构建容器镜像先渲染 Dockerfile 模板到images_dir/Dockerfile再按 builder 分支——Docker 路径执行docker build -t {{ registry }}/vm-key:tag --build-arg cloud_imagekey.qcow2BuildKit 路径优先使用buildctl-daemonless.shrootless 模式附加--rootless --oci-worker-no-process-sandbox --oci-worker-snapshotternative标志否则临时拉起buildkitd守护进程并通过独立 socket 执行构建失败时还会尝试回退到docker build未推送时以docker save落 tar推送仅当 builder 为docker且kubevirt_images_pushtrue时执行docker login→ 逐个docker push {{ registry }}/vm-key:tag→docker logout。一个值得注意的边界BuildKit 路径本身不会走 docker login/push 分支而 Makefile 的push-single-staging目标使用的仍是kubevirt_container_builder: docker——即分阶段发布依赖 Docker 客户端与 Artifact Registry 的直连认证而不是 BuildKit 推送。受信分阶段发布Staging Publishpush-single-staging目标的设计体现在 Makefilepush-single-staging: ansible-playbook -i localhost, -c local \ -e images_dir$(CURDIR)/.image-builder \ -e docker_hostus-central1-docker.pkg.dev \ -e registry$(staging_registry) \ -e {docker_login: false, kubevirt_images_push: true, kubevirt_container_builder: docker, kubevirt_images_target_host: localhost, kubevirt_images_selected: [$(image_name)]} \ cluster.yml要点是docker_host被硬切换为us-central1-docker.pkg.dev、registry 切换到staging_registry默认us-central1-docker.pkg.dev/k8s-staging-images/kubespray且docker_login: false——认证由 Cloud Build 环境自身提供的凭据完成。配套的 cloudbuild-staging.yaml 给出了受信任务的完整形态在 7200 秒超时内使用 GCB 的 docker-gcloud 基础镜像安装ansible-core qemu-img与community.generalcollection 后执行make -C test-infra/image-builder push-single-staging \ image_nameubuntu-2404 \ staging_registryus-central1-docker.pkg.dev/$PROJECT_ID/kubespray该配置的images字段声明了本次构建产出的制品us-central1-docker.pkg.dev/$PROJECT_ID/kubespray/vm-ubuntu-2404:latest即通过staging_registry变量把发布目标参数化到具体项目名下实现先发到 staging 命名空间、验证通过后再由有权任务发到 quay.io的分阶段发布流程。总结Kubespray 的 KubeVirt Image Builder 用一套非常薄的 Ansible 机制一个 playbook、一个角色、五个 Makefile 目标解决了 CI 的裸金属操作系统供给问题以 defaults/main.yml 为单一事实来源声明镜像清单qemu-img完成格式转换与扩容kubevirt/registry-disk-v1alpha把磁盘封装为容器镜像再由 Docker/BuildKit 双路径完成构建与推送。新增操作系统只需修改清单文件并走push-single-docker或 staging 通道本地开发则可用make validate-single在不依赖 Docker daemon 和远程主机的情况下完成端到端验证。【免费下载链接】kubesprayDeploy a Production Ready Kubernetes Cluster项目地址: https://gitcode.com/GitHub_Trending/ku/kubespray创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考