news 2026/9/13 19:20:23

Kubespray KubeVirt 镜像构建器实战:为 CI 构建并推送 KubeVirt 虚拟机磁盘镜像

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kubespray KubeVirt 镜像构建器实战:为 CI 构建并推送 KubeVirt 虚拟机磁盘镜像

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:

  1. 下载:从上游源拉取各操作系统的 cloud image(原始.img.qcow2,部分带.xz压缩);
  2. 转换:非 qcow2 格式(如 Ubuntu 的 raw.img)通过qemu-img convert -O qcow2转为 qcow2;
  3. 扩容:对每块镜像执行qemu-img resize +8G,为 CI 中的系统安装与测试留出磁盘空间;
  4. 打包:将 qcow2 文件作为cloud_image构建参数注入 Dockerfile,基于kubevirt/registry-disk-v1alpha基础镜像构建容器镜像;
  5. 推送:默认推送为quay.io/kubespray/vm-<os-name>:<tag>。受信 CI 任务可通过覆盖 registry 目标实现镜像的分阶段发布(staged publishing)。

Dockerfile 模板极简,见 templates/Dockerfile:

FROM kubevirt/registry-disk-v1alpha ARG cloud_image LABEL org.opencontainers.image.authors="The Kubespray Project <kubespray@googlegroups.com>" COPY $cloud_image /disk

即把转换好的磁盘文件直接拷入基础镜像的/disk,KubeVirt 的 registry disk data volume 机制正是通过这种"磁盘即容器镜像"的方式给 VM 挂载磁盘。

受信的分阶段发布路径使用 Cloud Build 认证并跳过docker login

make push-single-staging image_name=ubuntu-2404

前置条件

按 README 要求,构建环境需要:

  • Docker、qemu-img(来自 qemu 工具包)、Ansible;
  • 对 quay.io 上 kubespray 组织的推送权限(robot 账号kubespray+buildvmimages)。

角色任务在开始构建前会实际校验这些依赖:tasks/main.yml 中依次执行qemu-img --version(必检)与docker --version(仅当kubevirt_container_builder == 'docker'时检查),BuildKit 路径则额外探测buildctl-daemonless.sh/buildctl+buildkitd的可用性。

镜像定义:所有 OS 的单一事实来源

所有操作系统镜像定义集中在 roles/kubevirt-images/defaults/main.yml。每个条目包含以下字段:

字段说明
filename下载后的文件名
url上游 cloud image 下载地址
checksum用于下载校验的校验和(sha256:sha512:前缀)
converted源镜像已是 qcow2 时为true,需要qemu-img convert时为false
tagDocker 镜像标签(通常为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 convert;Fedora、Rocky、openEuler 等已是 qcow2,converted: true,角色只做复制;
  • 校验和前缀随上游提供格式而定:Ubuntu/Fedora/Rocky/openEuler 用sha256:,Debian 上游提供sha512:,Flatcar 也是sha512:
  • .xz压缩的镜像(如 Fedora CoreOS、openEuler)会被角色中的unxz --force步骤自动解压,解压后再按converted标志处理。

使用方式

构建并推送全部镜像

cd test-infra/image-builder/ make docker_password=<quay-robot-token>

Makefile 中的deploy目标会调用ansible-playbook -i hosts.ini,把docker_hostdocker_logindocker_userdocker_passworddocker_passwordregistry作为额外变量注入 cluster.yml。其中 hosts.ini 定义了一台远程构建主机:

image-builder-1 ansible_ssh_host=xxx.xxx.xxx.xxx [image-builder] image-builder-1

playbook 通过hosts: "{{ kubevirt_images_target_host | default('image-builder') }}"指定目标,因此这条deploy路径是面向远程 builder 主机的(需要 SSH 可达)。

新增一个操作系统镜像

  1. 在 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"
  2. 构建并推送该镜像:

    make docker_password=<quay-robot-token>

    如果只想构建单个镜像,用make push-single-docker image_name=new-os-name即可(对应 Makefile 中通过kubevirt_images_selected过滤)。

  3. 提交包含defaults/main.yml变更的 PR,使 CI 可以使用新镜像(上游有真实示例 PR #12379 可供参考)。

Makefile 目标全解

Makefile 顶部定义了默认变量,理解它们是理解全部目标的关键:

docker_host ?= quay.io docker_login ?= true docker_user ?= kubespray+buildvmimages 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_push=true,builder=docker本地构建全部镜像并推送
push-single-docker同上 +kubevirt_images_selected=["$(image_name)"]本地构建并推送单个镜像
push-single-staging强制docker_host=us-central1-docker.pkg.devregistry=$(staging_registry)docker_login=false受信分阶段发布到 Google Artifact Registry,走 Cloud Build 认证、跳过 docker login
validate/validate-singlekubevirt_images_push=false,builder=buildkit,输出目录.image-builder/buildkit-outputCI 本地验证(只构建,不推送)
validate-docker/validate-single-dockerkubevirt_images_push=false,builder=docker用 Docker 路径本地验证

validate这条路径在本地运行并使用 BuildKit,因此不依赖 SSH 访问远程构建主机,也不依赖 Docker daemon——这正是 README 中 "CI Validation" 一节强调的特性:

cd test-infra/image-builder/ make validate # 仅构建全部镜像 make validate-single image_name=ubuntu-2404 # 仅构建单个镜像

从源码结构看,"不推送"的实现是:BuildKit 构建的输出从type=image,...,push=true切换为type=oci,dest=<输出目录>/vm-<key>-<tag>.tar(见 tasks/main.yml),即以 OCI tar 落地到本地目录完成验证。

运行时变量

三个决定行为模式的关键变量及其默认值(定义于 defaults/main.yml):

  • kubevirt_images_push(默认true):置为false时跳过 docker login/push/logout;
  • kubevirt_images_selected(默认[]):要构建的镜像键列表,空列表表示构建全部;
  • kubevirt_container_builder(默认docker):设为buildkit可在没有 Docker daemon 访问权限的本地 CI 中做验证。

此外还有几个配套变量:

  • images_dir(默认/images/base):磁盘镜像的工作目录;
  • docker_user(默认kubespray+buildvmimages)、docker_host(默认quay.io)、docker_login(默认true)、registry(默认quay.io/kubespray);
  • kubevirt_buildkit_output_dir(默认{{ images_dir }}/buildkit-output):BuildKit 验证模式的 OCI tar 输出位置,Makefile 的 validate 目标将其覆盖为$(CURDIR)/.image-builder/buildkit-output

角色开头有三道参数断言,可以快速定位配置错误:

  1. 选中的镜像名必须能在images中找到,否则报No matching images found
  2. kubevirt_container_builder只能是dockerbuildkit
  3. BuildKit 模式当前要求kubevirt_images_push=false("BuildKit validation currently requires kubevirt_images_push=false")。

构建任务的执行细节

角色任务 tasks/main.yml 的执行顺序值得逐条过一遍,它能解释每个配置字段的实际用途:

  1. 过滤kubevirt_images_to_build依据kubevirt_images_selected是否为空来决定是取全部images还是community.general.keep_keys过滤后的子集——这就是单个镜像构建的底层实现;
  2. 依赖检查qemu-img --version、按 builder 检查 Docker 或 BuildKit;
  3. 下载get_url直接带checksum校验下载,任何上游文件变化都会在此失败;
  4. 解压unxz --force,仅当文件名以.xz结尾时执行;
  5. 转换或复制converted: false时执行qemu-img convert -O qcow2 <源文件> <镜像名>.qcow2converted: true时直接cp<镜像名>.qcow2。最终所有镜像统一以"镜像键 + .qcow2"命名;
  6. 扩容qemu-img resize <镜像名>.qcow2 +8G
  7. 构建容器镜像:先渲染 Dockerfile 模板到images_dir/Dockerfile,再按 builder 分支——Docker 路径执行docker build -t {{ registry }}/vm-<key>:<tag> --build-arg cloud_image=<key>.qcow2;BuildKit 路径优先使用buildctl-daemonless.sh(rootless 模式附加--rootless --oci-worker-no-process-sandbox --oci-worker-snapshotter=native标志),否则临时拉起buildkitd守护进程并通过独立 socket 执行构建,失败时还会尝试回退到docker build(未推送时以docker save落 tar);
  8. 推送:仅当 builder 为dockerkubevirt_images_push=true时执行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 Publish)

push-single-staging目标的设计体现在 Makefile:

push-single-staging: ansible-playbook -i localhost, -c local \ -e images_dir=$(CURDIR)/.image-builder \ -e docker_host=us-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-imgcommunity.generalcollection 后执行:

make -C test-infra/image-builder push-single-staging \ image_name=ubuntu-2404 \ staging_registry=us-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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 19:19:18

基于RT-Thread的激光雷达避障小车开发实战

简介&#xff1a;一套基于RT-Thread实时操作系统与STM32的激光雷达避障小车完整项目&#xff0c;来自高分通过的毕业设计/课程设计&#xff0c;面向计算机、电子、自动化等专业正在做毕设或需要项目实战练习的学生&#xff0c;也适用于教师、科研人员与公司开发者借鉴参考。项目…

作者头像 李华
网站建设 2026/9/13 19:19:17

WinApps 旧电脑部署指南:4GB 内存的 Linux 跑起 Windows 应用

WinApps 旧电脑部署指南&#xff1a;4GB 内存的 Linux 跑起 Windows 应用 【免费下载链接】winapps Run Windows apps such as Microsoft Office/Adobe in Linux (Ubuntu/Fedora) and GNOME/KDE as if they were a part of the native OS, including Nautilus integration. Ha…

作者头像 李华
网站建设 2026/9/13 19:18:49

STM32嵌入式AI编程:从手册查询到意图驱动的工作流重构

1. 这不是“AI写代码”&#xff0c;而是嵌入式工程师的新工作流重构最近在几个嵌入式开发群和论坛里&#xff0c;频繁看到有人发截图&#xff1a;VS Code里弹出 Claude Code 的侧边栏&#xff0c;输入“初始化STM32F407的USART1&#xff0c;波特率115200&#xff0c;8N1&#x…

作者头像 李华
网站建设 2026/9/13 19:15:52

WeKan 设计演进史:与 Trello、Jira 的功能借鉴对比与技术溯源

WeKan 设计演进史&#xff1a;与 Trello、Jira 的功能借鉴对比与技术溯源 【免费下载链接】wekan The Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR …

作者头像 李华
网站建设 2026/9/13 19:15:15

Vue 3豆瓣仿制项目:工程化实战与移动端适配全解析

简介&#xff1a;这是一份面向前端初学者与Vue.js入门学习者的豆瓣仿制网站实训项目源码&#xff0c;聚焦单页应用开发全流程实践&#xff0c;帮助开发者系统掌握Vue核心生态与工程化能力。资源共51个文件&#xff0c;包含11个功能完备的Vue组件&#xff08;如HomeView、Detail…

作者头像 李华