vHost 镜像配方
镜像配方用于构建一个已经安装好软件、可供 vHost 启动的操作系统磁盘镜像。
本页统一说明 recipe.toml 的字段、provision.yml 的写法和二者之间传递的变量。
构建器先用 QEMU 启动基础镜像,通过 SSH 连接这台临时虚拟机,再运行 Ansible 安装软件。安装完成并关机后,它的磁盘就是镜像产物;按配方声明复制出来的内核、 软件清单等文件与磁盘一起保存。
provision 中的 CPU、内存和加速方式用于这台临时构建虚拟机。
以后启动仿真时使用的 CPU、内存、启动参数和磁盘总线由拓扑中的 vhost 决定。
配方标识
目录就是配方标识,也是平台与软件版本的唯一事实源:
resources/images/recipes/
<发行版>/<发行版版本>/<架构>/<软件>/<软件版本>/
例如 ubuntu/24.04/x86_64/rocm/7.0 表示带 ROCm 7.0 的 Ubuntu 24.04
x86_64 镜像。不要在 recipe.toml 中重复这五项信息。
解析器接受的架构名称为 x86_64、aarch64 和 riscv64;实际构建还需要
对应的基础镜像、QEMU 和安装步骤。
配方中的文件
recipe.toml声明基础镜像、构建入口、构建变量以及成功构建后导出的文件。
provision.ymlAnsible 安装文件;playbook 是 Ansible 对一组安装、配置步骤的称呼。 其路径由
provision.playbook指定。files/playbook 复制进镜像的脚本、服务和配置。
安装和开机初始化是两个阶段:provision.yml 在构建镜像时安装软件,
也可以复制 initialize 脚本并启用 systemd 服务,让以后启动的 vHost 自动执行
初始化。当前 GPU 初始化顺序见 客户机参数。
recipe.toml 字段
recipe.toml 的三个配置段分别是:base 指定基础镜像;provision 描述
如何准备构建虚拟机并执行安装;result 声明需要导出的文件。
顶层的 schema 是必填整数,表示配方文件的格式版本,当前值为 2。
当前主要用它明确拒绝旧格式:解析器只接受 2,不自动迁移旧配方。
新增 vHost、发行版或软件版本,以及调整模板中的配置值,都不需要修改 schema。
只有配方字段结构发生不兼容变化时,才需要考虑更新格式版本,并迁移受影响的配方。
base、provision 和 result 三个表都必须存在;未知字段会报错。
下文中的必填字段没有隐式默认值。
基础镜像:base
字段 |
类型 / 必填 |
含义与约束 |
|---|---|---|
|
字符串 / 是 |
下载基础磁盘镜像的 HTTPS 地址。基础系统需要能够通过 SSH 接受安装操作; 当前共享构建模板使用 cloud-init 配置临时登录密钥。 |
|
字符串 / 是 |
基础镜像的 SHA-256,64 个小写十六进制字符,不带 |
|
字符串 / 是 |
基础磁盘格式: |
构建和安装:provision
字段 |
类型 / 必填 |
含义与约束 |
|---|---|---|
|
字符串 / 是 |
Packer 构建阶段的虚拟机和磁盘文件名称;最终发布的磁盘统一命名为 |
|
字符串 / 是 |
构建磁盘容量,交给 Packer 解释,例如 |
|
字符串 / 是 |
产出磁盘格式: |
|
整数 / 是 |
临时构建虚拟机的 vCPU 数量,至少为 |
|
整数 / 是 |
临时构建虚拟机的内存,单位 MiB,至少为 |
|
字符串 / 是 |
Packer 和 Ansible 连接临时构建虚拟机时使用的用户。 |
|
字符串 / 是 |
QEMU 加速方式: |
|
字符串 / 是 |
构建虚拟机的 QEMU 机器类型,例如 |
|
字符串 / 是 |
构建虚拟机的 QEMU CPU 模型,例如 |
|
字符串 / 是 |
安装文件相对配方目录的路径,通常为 |
|
表 / 是 |
安装变量,见下节;没有变量时保留空的 |
|
表 / 是 |
需要从配方目录以外读取的安装文件,见下节;没有文件时保留空的
|
安装变量与文件
[provision.variables] 的键是配方自己定义的变量名,值必须是字符串。
Ansible 通过 cosim_recipe_variables.<变量名> 读取它们。软件包版本、内核版本
等安装参数放在这里;目录已经表达的软件版本通过 cosim_recipe.software_release
读取。
[provision.files] 的键是文件别名,值是相对仓库工作区根目录的文件路径,
例如 firmware = "third_party/example/firmware.bin"。路径不能是绝对路径,
不能包含 ..,构建输入也不能通过符号链接逃出工作区。
构建器将它转换为绝对路径,以 cosim_provision_files.firmware 传给 Ansible。
声明文件只是让构建器检查并记录输入,实际复制到哪里由 playbook 的 copy 步骤决定。
配方自带的脚本、服务和配置直接放在 files/,通过
{{ playbook_dir }}/files/<文件名> 引用。构建器会记录配方源文件和声明输入的内容,
输入变化后重新判断已有镜像是否可以复用。
仓库中的 ROCm 7.0 配方通过 [provision.files] 引用
third_party/gem5-resources/src/x86-ubuntu-gpu-ml/files/ 下的
mi200.rom、mi300.rom、mi300_discovery 和 mi350_discovery。
这些文件由 gem5-resources 子模块提供,配方负责声明输入和安装位置。
MI300X 设备模板、ROM 测试和回归记录使用同一份子模块中的 mi300.rom。
just build-disk、just build-rocm-assets 和 just test-cosim-vfio-user
会先初始化该子模块;just build-gpu-app 也从其中读取 GPU 程序源码。
导出文件:result
已安装的磁盘自动产出,无需在 result.files 中声明。这个列表只声明需要额外
从镜像里复制出来的文件。[result] 可以为空;未声明 files 时默认为空列表。
字段 |
类型 / 必填 |
含义与约束 |
|---|---|---|
|
字符串 / 否 |
用作直接启动内核的导出文件名,必须对应某个 |
|
对象列表 / 否 |
用 |
|
字符串 / 每项必填 |
导出后的文件名,所有项之间唯一,只能使用 ASCII 字母、数字、 |
|
字符串 / 每项必填 |
临时构建虚拟机内的源文件绝对路径,不能包含 |
在 TOML 中声明导出文件后,playbook 还需要执行 fetch 步骤,见后面的例子。
构建器会检查声明的文件是否全部取回,再验证并发布结果。
TOML 结构示例
下面只展示字段组织方式;URL、校验值和外部文件路径需要替换为实际输入:
schema = 2
[base]
url = "https://example.invalid/base.qcow2"
sha256 = "0000000000000000000000000000000000000000000000000000000000000000"
format = "qcow2"
[provision]
image_name = "example"
disk_size = "40000M"
disk_format = "qcow2"
cpus = 4
memory_mb = 8192
ssh_username = "ubuntu"
accelerator = "kvm"
machine_type = "q35"
cpu_model = "host"
playbook = "provision.yml"
[provision.variables]
package_name = "bash"
[provision.files]
firmware = "third_party/example/firmware.bin"
[result]
[[result.files]]
name = "image-os-release"
guest_path = "/etc/os-release"
provision.yml 写法与字段
这个文件使用 Ansible 的 YAML 格式。下面示例安装软件并导出 TOML 中声明的文件; 具体的软件包、驱动和配置步骤由各个配方决定:
- name: Install the image contents
hosts: default
become: true
gather_facts: true
tasks:
- name: Install the selected package
ansible.builtin.package:
name: "{{ cosim_recipe_variables.package_name }}"
state: present
- name: Fetch declared result files
ansible.builtin.fetch:
src: "{{ item.guest_path }}"
dest: "{{ cosim_result_directory }}/{{ item.name }}"
flat: true
loop: "{{ cosim_result_files }}"
安装文件的外层字段
字段 |
本项目中的含义 |
|---|---|
|
这一组操作的可读名称,显示在构建日志中。 |
|
操作目标。共享构建器使用 |
|
|
|
|
|
按顺序执行的安装、配置和文件导出步骤。 |
这些是 Ansible 的字段;完整定义见 Ansible playbook 关键字。
安装步骤中的常用字段
每个步骤用 name 说明目的,再选择一个 Ansible 模块执行操作。
当前配方常用 package 或 apt 安装软件,file 创建目录,
copy 复制文件,systemd_service 启用开机服务,fetch 导出文件。
模块参数按模块自己的定义填写,不是 recipe 增加的另一套字段。
字段或参数 |
含义 |
|---|---|
|
软件包名与目标状态;例如 |
|
操作的路径和目标状态;例如 |
|
本机源文件和虚拟机内的安装路径; |
|
服务名、是否启用开机启动、是否重新加载服务配置;启用服务与立即启动服务是两回事。 |
|
创建用户时设置其默认登录 shell,例如 |
|
要执行的程序和参数列表,例如 |
|
通过 shell 执行命令字符串,用于确实需要 |
|
对列表逐项执行当前步骤, |
|
将步骤的执行结果存入指定变量,后续步骤可以读取 |
|
指定何时把步骤报告为发生了修改;不会自动跳过命令,也不会替代失败检查。 |
|
指定步骤的失败条件; |
|
把步骤分组;组内任务失败时进入 |
普通命令优先使用 command.argv;需要 shell 语法时使用 shell.cmd。
具体行为见 Ansible command 模块。
项目传入的变量
这些变量由构建器生成;配方读取它们,不另写一份重复配置。
变量 |
来源和用途 |
|---|---|
|
目录推导出的 |
|
|
|
|
|
|
|
本次构建在本机暂存导出文件的目录,供 |
|
Ansible 提供的变量,指向安装文件所在目录;构建时配方会被复制到临时目录, 因此配方自带文件应相对这个变量定位。 |
文件路径与复制方向
写法 |
所在位置 |
用途 |
|---|---|---|
|
|
声明外部安装输入。 |
|
运行构建器的本机 |
|
|
本机暂存的配方目录 |
|
|
临时构建虚拟机内部 |
前者是安装目标,后者对应 |
|
运行构建器的本机 |
|
示例中的 flat: true 让 fetch 按指定名称保存,
避免额外添加目标机器名称和原始目录层级;行为见
Ansible fetch 模块。
使用镜像
vHost 直接选择配方:
vhost:
use: vhost-x86
image: ubuntu/24.04/x86_64/rocm/7.0
cmdline: console=ttyS0 root=/dev/vda1 rw
root_bus: virtio
运行时,启动器解析已验证的配方产物;如果声明了 result.kernel,就用对应文件
直接启动,并将镜像磁盘作为 root 磁盘挂载。未导出内核时由 QEMU 使用磁盘启动流程。
不使用配方的 vHost 也可以直接声明 kernel、initrd、cmdline 和 disks。
使用 cmdline 时需要直接启动内核。完整运行字段见 拓扑 YAML schema。
命令
just ci-rocm-assets list
just ci-rocm-assets inspect <配方标识>
just ci-rocm-assets validate <配方标识>
just ci-rocm-assets build <配方标识>
inspect 读取当前配置和缓存状态;validate 检查 Packer 与 Ansible 配置;
build 构建镜像,或复用通过输入和完整性检查的现有镜像。
构建结果位于 build/images/<配方标识>/:disk 是已安装的磁盘,
其他导出文件沿用 result.files[].name,manifest.json 是构建器生成的记录,
保存配方标识、输入指纹及产物的大小和 SHA-256。它们都不属于源码。
相关页面
新增配方流程:新增 vHost 镜像配方
运行机器字段:拓扑 YAML schema
开机后的 GPU 初始化:客户机参数
文件和产物路径:产物、路径与源码地图