在 Hyper-V 上运行 Linux 云镜像虚拟机

一些 Linux 发行版提供了云镜像,云镜像通常有更小的体积,可以更方便初始化配置,相较于传统的镜像更适合运行在虚拟机或虚拟化平台上,DebianFedoraUbuntuAlma Linux 等都提供了云镜像。

大多数的云镜像都是使用 cloud-init 进行初始化。下面将介绍如何在 Hyper-V 上运行 Debian 12 云镜像。

要解决的问题

镜像格式:Debian 并未提供 VHDX 格式的镜像,所以需使用 qemu-img 将 qcow2 镜像转换为 VHDX 才可用于 Hyper-V。

向虚拟机提供配置:可选择的方式很多,这里用文件系统的方式提供配置。后文将描述如何创建一个含有配置的 ISO 镜像。

将 qcow2 格式镜像转换为 VHDX 镜像

# 如果没有将 qemu 添加到环境变量中,可为其设置别名
Set-Alias qemu-img $env:ProgramFiles\qemu\qemu-img.exe

$cloudImage = 'C:\debian-12-genericcloud-amd64.qcow2'
qemu-img convert -f qcow2 $cloudImage -O vhdx C:\debian.1.vhdx

qume-img 转换出来的 VHDX 在文件系统中存储是松散的,通过命令 fsutil file layout C:\debian.1.vhdx 可知。Hyper-V 要求虚拟磁盘是非松散的,将该 VHDX 用于 Hyper-V 则会报错。最简单的解决方法是再复制一次:

cp C:\debian.1.vhdx C:\debian.vhdx
rm C:\debian.1.vhdx

创建配置提供者

cloud-init 有多种方法可以提供配置,其中一些配置只在首次初始化有效,有些则可以动态更新。这里将创建 ISO 文件来提供配置,创建一个分区名为 CIDATA 的 FAT32 分区也是可行的。

在 Windows 上创建 ISO 可以使用 libarchiveOscdimg。Oscdimg 需要先安装 Windows ADK,这里主要使用 libarchive。其实 libarchive 的 bsdtar 也已经预制在 Windows 中了,现有的 tar 命令就是这个。不过由于系统的版本可能比较陈旧不一定支持。

bsdtar 的命令行使用请参考 FreeBSD 的文档,和广为人知的 GNU Tar 不完全兼容。

cidata 目录中创建两个文件 meta-datauser-data

mkdir cidata
ni cidata\meta-data, cidata\user-data

然后分别写入如下内容(行尾最好使用 LF,未测试 CRLF 是否可行):

meta-data

instance-id: instance-0          # 实例 ID
local-hostname: food.example.com # 主机名

user-data

#cloud-config

user:
  name: foair
password: xR0V3MyFybfWiEeDyTub
chpasswd:
  expire: false
ssh:
  emit_keys_to_console: false
ssh_authorized_keys:
  - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEIwVXsuc2+oIoNtelRjlGXB5OSdKrBv488BXqt/RCUG
ssh_genkeytypes: [ed25519]
timezone: Asia/Shanghai

使用工具将两个文件封装在一个 ISO 镜像中,后续将用于虚拟机:

$metaDataIso = 'C:\metadata.iso'

# 设置别名避免使用 %SystemRoot%\System32\tar.exe
Set-Alias tar C:\libarchive\bin\bsdtar.exe
tar -C cidata --options volume-id=CIDATA -caf $metaDataIso --no-acls --no-fflags *

# oscdimg cidata $metaDataIso -j2 -lCIDATA

创建虚拟机

下面会使用 PowerShell 来创建虚拟机,也可以考虑在「Hyper-V 管理器」中用鼠标点点点。

# 虚拟机名称、已有的虚拟交换机名称
$VMName = 'Debian'
$virtualSwitchName = 'Default Switch'

# 新建一个虚拟机
New-VM $VMName -MemoryStartupBytes 8GB -VHDPath $vhdx -Generation 2 -SwitchName $virtualSwitchName
# 添加 cloud-init 配置 ISO
Add-VMDvdDrive -VMName $VMName -Path $metaDataIso
# 设置 UEFI 安全启动
Set-VMFirmware -VMName $VMName -SecureBootTemplate MicrosoftUEFICertificateAuthority
# 设置处理器数量
Set-VM -VMName $VMName -ProcessorCount 4

连接虚拟机

Start-VM $VMName
vmconnect localhost $VMName

参考资料

Re: qemu-img - vhdx compatibility with Hyper-V
https://www.mail-archive.com/qemu-discuss@nongnu.org/msg04963.html

MicrosoftDocs/Virtualization-Documentation
https://github.com/MicrosoftDocs/Virtualization-Documentation/blob/main/hyperv-samples/benarm-powershell/Ubuntu-VM-Build/BaseUbuntuBuild.ps1