好的,我会为你整理一份关于如何使用 Cloud-Init 初始化 KVM 虚拟机的中文文档,内容包括适用于 Windows 和 Linux 系统的配置差异、完整的 user-data 和 meta-data 范例、网络与 SSH 设置、以及如何通过 libvirt/virt-install 等方式将这些文件挂载到虚拟机中。 我整理好后会第一时间告诉你。

使用 Cloud-Init 初始化 KVM 虚拟机指南

在 KVM 环境中,通过 Cloud-Init 可以自动完成虚拟机实例的初始化配置,包括网络设置、用户和密码、SSH 密钥注入、主机名配置等。Cloud-Init 通常使用一个称为 NoCloud 的数据源(也称为 seed ISO 配置盘)将初始化数据提供给虚拟机 (第 4 章 配置 cloud-init | Red Hat Product Documentation) (第 4 章 配置 cloud-init | Red Hat Product Documentation)。以下将详细说明 Cloud-Init 的配置文件范例、Linux 与 Windows 系统的差异、常见初始化参数设置方法,以及如何使用 libvirt/virt-install/virsh 等工具将 Cloud-Init 配置挂载到 KVM 虚拟机中。最后提供一个完整的配置流程示例(包含使用 cloud-localds 创建 seed ISO 的方法),供系统管理员或运维人员参考。

Cloud-Init 配置文件范例(Linux 和 Windows)

Cloud-Init 使用两个主要的配置文件来传递初始化信息:

这两个文件会被打包到一个 ISO 镜像中并挂载给虚拟机。虚拟机启动时,Cloud-Init 服务会从挂载的介质(NoCloud 数据源)读取这些文件,从而应用相应的配置。

下面分别给出 LinuxWindows 云镜像的 Cloud-Init 配置示例。

Linux 系统 Cloud-Init 配置示例

user-data(Linux)示例:使用 cloud-config YAML 格式定义配置。该示例创建一个新用户并添加 SSH 密钥、设置主机名和安装软件包等:

#cloud-config
hostname: mylinux-vm                # 设置主机名
manage_etc_hosts: true             # 更新 /etc/hosts
users:
  - name: devops                   # 创建名为 devops 的用户
    gecos: DevOps User
    groups: [sudo]                 # 将用户添加到 sudo 组
    sudo: "ALL=(ALL) NOPASSWD:ALL" # 无需密码即可使用 sudo
    shell: /bin/bash
    ssh-authorized-keys:           # 注入 SSH 公钥用于无密码登录
      - ssh-rsa AAAAB3NzaC1yc2E...your_public_key_here... 
chpasswd:
  list: |
    devops:password123            # 为用户设置密码(明文将被加密保存)
  expire: false                   # 密码不过期
package_update: true              # 更新包索引
packages:
  - git
  - curl
runcmd:
  - [ "echo", "Cloud-Init setup complete." ]  # 引导后运行命令

上述 user-data 配置做了以下事项:设置主机名(hostname)、创建了一个 devops 用户并赋予sudo权限,设置了该用户密码和SSH公钥,安装了Git和Curl软件包,并在引导完成后输出一条消息作为验证。 (create a virtual machine with cloud image and cloud-init config using qemu/kvm | by Arian Fm | Feb, 2025 | Medium) (create a virtual machine with cloud image and cloud-init config using qemu/kvm | by Arian Fm | Feb, 2025 | Medium)。文件必须以#cloud-config开头并采用 YAML 格式 (在本地KVM中安装使用Cloud-init-腾讯云开发者社区-腾讯云)。

meta-data(Linux)示例:提供实例标识和主机名等元数据:

instance-id: i-00001
local-hostname: mylinux-vm

典型情况下,meta-data 至少包含一个唯一的实例ID(可任意指定)和本地主机名。Cloud-Init 会读取其中的 local-hostname 来设置虚拟机的主机名(如果未在 user-data 中另行指定) (NoCloud (seed.iso) cloud-init configuration for Amazon Linux 2023 on KVM and VMware - Amazon Linux 2023) (NoCloud (seed.iso) cloud-init configuration for Amazon Linux 2023 on KVM and VMware - Amazon Linux 2023)。上述示例将实例ID设为 i-00001,主机名设为 mylinux-vm

Windows 系统 Cloud-Init 配置示例

Windows 虚拟机需要使用 Cloudbase-Init(Cloud-Init 的 Windows 实现)来支持类似功能 (Cloud-Init Support - Proxmox VE)。在准备 Windows 云镜像时,需要预先在镜像中安装并配置 Cloudbase-Init 服务,否则 Cloud-Init 配置数据将不会被处理 (Installing and Configuring Cloudbase-Init_Image Management Service_Huawei Cloud)。Cloudbase-Init 能解析 NoCloud 配置盘中的数据,但其支持的 cloud-config 指令略有不同,且功能上有所限制(不支持Linux特有功能) (Userdata — cloudbase-init 1.1.7 documentation) (Cloud-Init Support - Proxmox VE)。例如,Linux 中的软件包安装指令在 Windows 上不适用,但账户、密码、主机名、SSH密钥注入等常用配置仍受支持。

user-data(Windows)示例:使用 Cloudbase-Init 解析的 cloud-config YAML,创建/配置用户并设置主机名等:

#cloud-config
users:
  - name: Administrator           # 指定要配置的用户(内置管理员账户)
    groups: [Administrators]      # 确保属于管理员组
    passwd: "P@ssw0rd!"           # 设置登录密码(Windows 下需明文)
    ssh_authorized_keys:
      - ssh-rsa AAAAB3NzaC1yc2E...your_public_key_here...
set_hostname: win-vm              # 设置主机名
runcmd:
  - cmd.exe /c echo Cloudbase-Init OK > C:\cloud-init-result.txt

上述 user-data 将内置的 Administrator 用户密码设置为 "P@ssw0rd!" 并添加一个 SSH 公钥(如果 Windows 安装了 OpenSSH 服务器,则可用于密钥登录)。同时设置主机名为 win-vm,并通过 runcmd 执行了一条简单命令在 C:盘写入文件,作为初始化完成的标识。

**注意:**Cloudbase-Init 在处理 users 部分时,对于 Windows 用户密码需要明文提供;而 Linux 中通常使用加密哈希 (Userdata — cloudbase-init 1.1.7 documentation)。如果未提供密码,Cloudbase-Init 会为该用户随机生成密码 (Userdata — cloudbase-init 1.1.7 documentation)。另外,改变 Windows 主机名通常需要重启才能生效,Cloudbase-Init 会在必要时执行此操作 (Userdata — cloudbase-init 1.1.7 documentation)。

meta-data(Windows)示例:Windows 的 meta-data 文件格式与 Linux 相同,也可如下:

instance-id: i-00002
local-hostname: win-vm

对于 Windows 虚拟机,Cloudbase-Init 同样会读取 local-hostname 来设置计算机名(如果未在 user-data 中使用 set_hostname) (Installing and Configuring Cloudbase-Init_Image Management Service_Huawei Cloud) (Installing and Configuring Cloudbase-Init_Image Management Service_Huawei Cloud)。instance-id 用于标识实例,可用任意唯一值。

Linux 与 Windows Cloud-Init 支持差异

虽然 Linux 和 Windows 都可以利用 Cloud-Init 框架完成初始化配置,但二者在支持范围和实现方式上存在一些差异:

**小结:**总体而言,如果使用官方的云镜像,Linux 平台的 Cloud-Init 开箱即用,而 Windows 则需确保 Cloudbase-Init 安装配置正确 (Installing and Configuring Cloudbase-Init_Image Management Service_Huawei Cloud)。Linux Cloud-Init 功能更全面,Windows Cloudbase-Init 提供核心必要功能。管理上要注意两者在密码和网络等配置上的差异,合理地编写 user-data 脚本以兼容对应操作系统。

常见初始化参数的配置方法

利用 Cloud-Init,我们可以在虚拟机首次引导时定制各种参数。以下列出常见初始化项在 Cloud-Init(主要指 NoCloud cloud-config)中的配置方式:

综上,运维人员可以根据需求,在 Cloud-Init 的配置文件中组合以上模块,实现对虚拟机初始化环境的全面定制。在编写配置时请遵循 YAML 语法,注意缩进和格式正确,并参考相关发行版的 Cloud-Init 文档获取支持的所有字段选项 (NoCloud (seed.iso) cloud-init configuration for Amazon Linux 2023 on KVM and VMware - Amazon Linux 2023)。

使用 libvirt/virt-install/virsh 挂载 Cloud-Init 配置盘

将编写好的 Cloud-Init 配置提供给 KVM 虚拟机的常用方法,是生成一个 种子ISO镜像(seed ISO)配置驱动盘 并将其作为光驱或额外磁盘附加到虚拟机。下面介绍使用 libvirt 工具集(包括 virt-installvirsh)实现这一过程的几种方式:

  1. 使用 cloud-localds 工具创建种子镜像: cloud-localds 是 Cloud-Init 提供的便捷工具,可以根据给定的 user-data 和 meta-data 文件生成合规的 ISO 镜像文件(卷标为 cidata,Cloud-Init 会自动识别此卷) (NoCloud (seed.iso) cloud-init configuration for Amazon Linux 2023 on KVM and VMware - Amazon Linux 2023)。首先确保安装了该工具(通常在包 cloud-utilscloud-image-utils 中)。使用示例:

    # 安装cloud-localds (如未安装)
    sudo apt-get install -y cloud-image-utils
    
    # 生成seed ISO镜像
    cloud-localds seed.iso user-data meta-data
    

    上述命令将当前目录下的 user-datameta-data 文件打包进 seed.isocloud-localds 会自动添加必要的卷标和目录结构,使得生成的 ISO 符合 NoCloud 数据源要求 (create a virtual machine with cloud image and cloud-init config using qemu/kvm | by Arian Fm | Feb, 2025 | Medium)。若需要包括网络配置文件,可使用类似命令:
    cloud-localds seed.iso --network-config=network-config user-data meta-data,或直接将 network-config 文件也作为参数提供(具体取决于 cloud-localds 版本)。生成的 ISO 可以认为是一个配置光盘

    除了 cloud-localds,也可以使用通用的工具如 mkisofs/genisoimage 手动创建。例如:

    genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data
    

    该命令与 cloud-localds 效果类似,-volid cidata 指定卷名为 cidata (第 4 章 配置 cloud-init | Red Hat Product Documentation)。无论采用哪种方式,确保 ISO 内包含正确命名的 user-datameta-data 文件(以及可选的 network-config)。

  2. 在定义虚拟机时附加配置 ISO: 可以在 VM 创建或启动前,将上一步生成的 seed.iso 附加为光驱(CD-ROM)设备。使用 virt-install 创建虚拟机时,可以直接指定附加 ISO,例如:

    virt-install --name myvm --memory 2048 --vcpus 2 --cpu host \
        --disk path=/var/lib/libvirt/images/myvm.qcow2,format=qcow2 \
        --disk path=/path/to/seed.iso,device=cdrom,readonly=on \
        --import --os-type linux --os-variant ubuntu20.04 \
        --network network=default,model=virtio --graphics none
    

    上述命令假设已有一个准备好的系统磁盘 myvm.qcow2(例如从云镜像获取),使用--disk第二次指定时附加了我们生成的 seed.iso 作为只读光驱。--import 选项表示直接导入现有镜像而不走安装流程。这样,虚拟机引导时会检测到附加的光盘,并由 cloud-init 将其中配置应用于系统。**注意:**需要保证虚拟机模板中已安装 Cloud-Init/Cloudbase-Init 服务,否则附加配置盘也不会被处理。

    如果使用 virsh 定义或编辑已存在的虚拟机,也可以通过修改XML添加光驱设备。例如,在域XML的<devices>下添加:

    <disk type='file' device='cdrom'>
        <driver name='qemu' type='raw'/>
        <source file='/path/to/seed.iso'/>
        <target dev='hdd' bus='ide'/>
        <readonly/>
    </disk>
    

    这会将 seed.iso 作为IDE总线的光盘设备附加(许多云镜像预配置cloud-init会检查IDE光驱)。或者按照上一示例,也可用 <target dev='vdX' bus='virtio'/> 将其作为VirtIO磁盘附加 (在本地KVM中安装使用Cloud-init-腾讯云开发者社区-腾讯云)——Cloud-Init 同样能够在VirtIO磁盘上识别 cidata 卷。 (在本地KVM中安装使用Cloud-init-腾讯云开发者社区-腾讯云)附加后,使用 virsh start myvm 启动虚拟机。

    **小提示:**如果使用 Virt-Manager 图形界面管理 KVM,也可以在“添加硬件”中选择添加光盘,指向 seed.iso 文件。

  3. virt-install 的 --cloud-init 简化选项: 新版本的 virt-install 提供了 --cloud-init 参数,可以自动生成并附加 NoCloud 配置盘,无需手动调用 cloud-localds (virt-install --cloud-init support | Cole Robinson)。例如:

    virt-install --name demo --memory 1024 --disk size=10,backing_store=cloudimg.qcow2 \
        --cloud-init user-data=./user-data,meta-data=./meta-data
    

    virt-install 将根据提供的 user-data/meta-data 内容自动创建临时 ISO,并在首次引导时使用 (virt-install --cloud-init support | Cole Robinson) (virt-install --cloud-init support | Cole Robinson)。还可以通过 --cloud-init ssh-key=<pubkey> 等子选项快速注入SSH密钥或指定自定义密码等 (virt-install --cloud-init support | Cole Robinson)。这个方法适合快速测试,但在不了解 virt-install 版本支持的情况下,手动生成 ISO 更通用。

无论采用上述哪种方式,成功附加配置盘后,Cloud-Init 在虚拟机 首次启动 时应该能够检测到 cidata 卷并加载其中的配置。Proxmox 等平台也是类似的原理:为启用 Cloud-Init 的VM自动创建并挂载一个ISO。 (Cloud-Init Support - Proxmox VE)

验证挂载: 如果希望确认配置盘内容是否被正确挂载,可在引导后的虚拟机内检查。例如Linux虚拟机中,可能会看到 /dev/sr0(光驱)或 /dev/vdb 等设备作为 cidata 盘。可以尝试挂载该设备到某目录查看里面的 user-data 是否与预期一致。如果 Cloud-Init 正常执行,配置盘不需要人工挂载,Cloud-Init 已经读取并应用了配置。同时,Cloud-Init 会在日志(如 /var/log/cloud-init.log)中记录数据源检测和应用的详情,可查阅以诊断问题。

示例:Cloud-Init 初始化 KVM 虚拟机的完整流程

本节通过一个具体示例演示如何使用 Cloud-Init 配置一个基于云镜像的 KVM 虚拟机,从准备配置文件到成功登录配置完成的系统。

**环境假设:**KVM 已安装并运行在宿主机上,宿主机已安装 libvirt 和相关工具(virt-install/virsh 等),网络使用 libvirt 默认的 NAT 网络。目标虚拟机操作系统为 Ubuntu Server 22.04 (Jammy) 云镜像。我们希望虚拟机启动后自动配置一个用户并通过SSH公钥登录。

步骤 1:下载云镜像 – 获取 Ubuntu 官方云镜像(QCOW2 格式):

wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img -O ubuntu-22.04-cloudimg.qcow2

Ubuntu 提供了预装 Cloud-Init 的标准镜像。下载后得到 ubuntu-22.04-cloudimg.qcow2

步骤 2:准备虚拟机磁盘 – 基于下载的镜像创建虚拟机的磁盘映像文件。为了不破坏原始镜像,我们创建一个增量QCOW2(backing file):

qemu-img create -f qcow2 -b ubuntu-22.04-cloudimg.qcow2 -F qcow2 myvm.qcow2 10G

上述命令创建了一个名为 myvm.qcow2 的 10GB 增量磁盘,它以下载的 cloudimg 作为后端。 (create a virtual machine with cloud image and cloud-init config using qemu/kvm | by Arian Fm | Feb, 2025 | Medium)这样我们的虚拟机磁盘既包含基础系统,又有自己的写入空间,大小上限为10GB。(如果不熟悉增量盘,也可以简单地 cp 一份镜像文件并使用 qemu-img resize 调整大小)。

步骤 3:编写 Cloud-Init 配置文件 – 新建两个文件 user-datameta-data

  • user-data 文件内容:

    #cloud-config
    hostname: example-vm
    ssh_pwauth: false
    users:
      - name: devops
        groups: sudo
        sudo: "ALL=(ALL) NOPASSWD:ALL"
        ssh_authorized_keys:
          - ssh-rsa AAAAB3NzaC1yc2EAAAADA...example_key...
    

    说明:将主机名设为 "example-vm",关闭SSH密码登录,仅创建用户 devops(属于sudo组)并注入预先指定的公钥(替换为你的实际公钥)。这里不设置密码,表示该用户仅能通过密钥认证登录,提高安全性。

  • meta-data 文件内容:

    instance-id: iid-12345
    local-hostname: example-vm
    

    说明:指定一个实例ID(任意唯一字符串即可)以及本地主机名,与 user-data 中的 hostname 保持一致。

确保这两个文件编码为纯文本UTF-8,无BOM,缩进正确。编写完成后,可以使用YAML工具验证 user-data 的格式无误。

步骤 4:生成 Cloud-Init 配置种子镜像(seed ISO) – 使用 cloud-localds 工具:

sudo apt-get install -y cloud-image-utils    # 如果尚未安装
cloud-localds seed.iso user-data meta-data

执行后将在当前目录生成一个 seed.iso 文件 (create a virtual machine with cloud image and cloud-init config using qemu/kvm | by Arian Fm | Feb, 2025 | Medium)。这就是 NoCloud 数据源的镜像,里面包含我们刚才的 user-data 和 meta-data(可以使用 isoinfo -i seed.iso -R -l 检查其内容,应该能看到两个文件)。

提示:cloud-localds 默认会给镜像设置卷标 cidata 并遵循 NoCloud 格式要求 (NoCloud (seed.iso) cloud-init configuration for Amazon Linux 2023 on KVM and VMware - Amazon Linux 2023)。如果没有 cloud-localds,可用 genisoimage 命令替代,效果相同。

步骤 5:创建并启动虚拟机 – 使用 virt-install 基于已有磁盘和 seed.iso 创建虚拟机:

virt-install \
    --name example-vm \
    --ram 2048 --vcpus 2 --cpu host \
    --disk path=./myvm.qcow2,format=qcow2 \
    --disk path=./seed.iso,device=cdrom,readonly=on \
    --import --os-variant ubuntu22.04 \
    --network network=default,model=virtio \
    --graphics none --console pty,target_type=serial

参数说明:

  • --name 指定虚拟机名称为 example-vm
  • --ram 2048 --vcpus 2 分配2GB内存和2个CPU。
  • 第一处 --disk 将我们准备的系统盘 myvm.qcow2 加入虚拟机。
  • 第二处 --disk 加入 seed.iso 作为光驱(只读)。 (Cloud-Init Support - Proxmox VE)
  • --import 表示直接使用现有盘启动(而非通过ISO安装操作系统)。
  • --os-variant 提供操作系统类型信息以优化配置(Ubuntu 22.04)。
  • --network network=default 连接到默认虚拟网络(NAT)。
  • --graphics none 禁用图形输出,--console pty,target_type=serial 启用一个tty控制台,方便查看输出(云镜像通常使用串行控制台)。

运行上述命令后,virt-install 会创建并启动虚拟机。如果未禁止控制台输出,终端可能会附着到虚拟机的串行控制台,您可以看到 Ubuntu 引导日志。Cloud-Init 在首次启动时会运行配置,此过程可能耗时数秒到几十秒。在日志中可以留意 Cloud-Init 的消息,例如 “Applying networking” 或 “Running modules for final” 等。

步骤 6:验证初始化结果 – 待虚拟机启动完成后,我们来验证 Cloud-Init 是否按预期工作:

  • 尝试使用我们创建的用户通过 SSH 登录虚拟机。例如:

    ssh devops@<宿主机IP> -p 2222
    

    (如果在 virt-install 时未映射端口,可以改用 virsh 控制台或直接登录宿主机网络中 IP。上述命令假设做了 hostfwd 将2222端口转发到来宾22端口,如没有请调整登录方式。)

    使用SSH公钥认证应能够直接登录而无需密码。如果成功登录,说明用户和SSH密钥注入生效。

  • 登录后检查主机名:运行 hostname 应显示 example-vm,与配置一致。

  • 检查 Cloud-Init 日志:sudo cat /var/log/cloud-init.log | grep -i "Finished",应该看到 cloud-init 完成各阶段的日志记录,没有错误。

  • 如有需要,可以Mount光驱查看内容:在虚拟机内执行:

    sudo mount /dev/sr0 /mnt
    ls /mnt
    

    预期应列出 user-datameta-data 文件 (在本地KVM中安装使用Cloud-init-腾讯云开发者社区-腾讯云)。这进一步证明我们的配置盘已成功挂载并可被读取(Cloud-Init 已经自动读取过了)。

如果以上验证都通过,那么恭喜您,Cloud-Init 已成功为虚拟机应用初始化配置!以后对于批量部署多个类似虚拟机,只需准备不同的 user-data/meta-data(比如修改主机名、用户密钥等),即可重复这一流程快速创建。


至此,我们完成了在 KVM 环境下使用 Cloud-Init 初始化虚拟机的全过程。从编写配置文件到挂载 seed ISO,再到虚拟机引导应用配置,每一步都至关重要。在实际运维中,建议妥善保存常用的 Cloud-Init 配置模板,根据不同操作系统调整细节(例如 Windows 需安装 Cloudbase-Init 且密码明文等差异 (Userdata — cloudbase-init 1.1.7 documentation)),并在部署前进行测试验证。

通过 Cloud-Init 的自动化初始化,可以极大提高批量部署虚拟机的效率和一致性,为后续配置管理打下良好基础 (Cloud-Init Support - Proxmox VE)。有关 Cloud-Init 更详细的配置选项和高级用法,可参考官方文档和各发行版的说明 (NoCloud (seed.iso) cloud-init configuration for Amazon Linux 2023 on KVM and VMware - Amazon Linux 2023)。希望本指南能帮助您顺利地在 KVM 中运用 Cloud-Init 完成虚拟机初始化配置。 (完)

参考资料: