在之前的 Proxmox VE + Ceph 集群搭建 一文中,完成了 PVE 集群的搭建,在虚拟化平台的日常使用中,经常需要创建新的虚拟机。
通常的交付流程是:确定所需配置,创建虚拟机,安装操作系统,配置网络,安装必要的软件,最后交付使用。
如果每次都按照这个流程来,既耗时又容易出错。为了提高效率,可以使用模板虚拟机来快速创建新的虚拟机实例。
本文将介绍一种基于 Cloud-init 的虚拟机模板的创建和使用方法。
获取支持 Cloud-init 镜像
Cloud-init 是一个用于自动化配置云实例的工具,许多 Linux 发行版都提供了支持 Cloud-init 的镜像。
虽然可以使用普通的 ISO 镜像安装系统,然后安装 cloud-init 软件包,但直接使用官方提供的 cloud-init 的镜像会更干净。
收集到的一些常用发行版的 cloud-init 镜像下载地址如下:
- Debian 12: https://cdimage.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
- Debian 13: https://cdimage.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2
- Ubuntu 22.04: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
- Ubuntu 24.04: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
- CentOS 7 最终版: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2
- CentOS 8.4 最终版: https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2
- CentOS Stream 8 最终版: https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2
使用 Cloud-init 镜像创建虚拟机
下载到的 cloud-init 镜像通常是 QCOW2 格式的磁盘镜像文件,是 qcow2 或 img 后缀,可以在 PVE 的 shell 中使用命令创建虚拟机:
1 | qm create 200 \ |
在 scsi0 参数中,import-from 指定了下载好的 cloud-init 镜像文件路径,data:0 表示使用存储池 data 创建虚拟机磁盘,需要根据实际情况修改。
创建完成的虚拟机:
刚创建完成的虚拟机还不能直接使用,可以看到虚拟机磁盘大小只有 3G,需要扩大磁盘大小:
调整完成后,在 Cloud-init 选项卡中,设置用户名密码网络等信息:
调整完成后,开机登录进入系统,可以确认到以上设置已经生效,并且 hostname 也对应在 PVE 设置的虚拟机名字:
但现在只是使用了官方提供的原始系统,如果需要更加方便快捷的创建交付,还需要对虚拟机进行定制。
定制 Cloud-init 模板虚拟机
登录 PVE 的 shell,后续命令都需要在 PVE shell 中执行。
安装定制工具:
1 | apt install libguestfs-tools qemu-utils -y |
以刚才使用的 Debian 13 为例,首先检查下载的镜像文件分区情况:
1 | virt-df -h debian-13-genericcloud-amd64.qcow2 |

可以看到分区情况,/dev/sda1 只有 2.8G,需要扩大分区以完成之后的定制步骤。
1 | # 首先创建一个新的 32G 的 qcow2 空白磁盘文件 |

确保分区空间充足后,可以开始接下来的定制步骤,创建定制脚本 custom-commands.txt,内容如下:
1 | # 在调整磁盘大小后,需要重新安装 grub |
这个定制脚本里并不是 shell 语法,而是 virt-customize 的选项,可以参考官方文档了解更多用法。
脚本创建完成后,执行以下命令进行定制:
1 | virt-customize -a debian-13-32g-custom.img --commands-from-file custom-commands.txt |
执行过程:
virt-customize 会使用 qemu 挂载 debian-13-32g-custom.img 镜像,并执行脚本中的命令完成定制。
定制完成后,可以使用定制完成的 debian-13-32g-custom.img 文件,按照之前创建虚拟机的步骤,创建新的虚拟机即可。
自动化
上面的定制步骤比较繁杂,可以编写一个自动化脚本来完成这些步骤,适配不同操作系统。
自动化脚本示例:pve-img-maker,使用方法:
1 | # 安装依赖 |
脚本会提示选择操作系统和定制脚本,确定后会自动完成下载镜像、扩展分区、定制镜像等步骤,最后在 output 目录生成定制完成的 qcow2 镜像文件。
如果需要添加其他系统支持,可以在 script 目录下创建对应操作系统的文件夹和配置脚本,base 和 clean 是默认启用的初始化和清理脚本,可以参考现有脚本编写。
还需要在 build.py 里 BASE_IMAGE_URLS 添加对应的镜像下载连接。
在集群环境中,可配合 pvesh 命令完成虚拟机的批量创建和交付,进一步提高效率:
# 将 vmid 200 的虚拟机转换成模板
qm template 200
# 从 200 模板批量创建虚拟机 201-210
for vmid in {201..210}; do
qm clone 200 $vmid --name "vm-$vmid"
# 设置 Cloud-init 配置,不设置密码只使用 ssh key 登录
qm set $vmid \
--ipconfig0 ip=192.168.233.$vmid/24,gw=192.168.233.1 \
--net0 virtio,bridge=vmbr233,mtu=1 \
--cores 16 --sockets 2 --memory 16384 \
--ciuser username --sshkeys /root/.ssh/ssh-key.pub
# 调整磁盘大小
qm resize $vmid scsi0 +32G
# 迁移到指定节点(如果需要)
# qm migrate $vmid pve2
# qm 只能操作本机已有的虚拟机,集群内的其他虚拟机需要使用 pvesh 指定节点操作
# 使用 pvesh 启动虚拟机
pvesh create /nodes/pve2/qemu/$vmid/status/start
# 使用 pvesh 设置虚拟机 DNS
pvesh set /nodes/pve2/qemu/$vmid/config --nameserver 223.5.5.5,114.114.114.114
done