在 PVE 上用 Cloud-Init 制作 Ubuntu 24.04 模板

本文译自 UntouchedWagons 的英文文档,原文链接见文末。

用 Cloud-Init 做一个 Ubuntu 24.04 模板,以后要新虚拟机时直接克隆,开机就自动配好用户、SSH 公钥和网络,不用每次从头装系统。

本文的前提:

  • 虚拟机用 UEFI 引导(不是 BIOS)
  • PVE 节点的主存储是 local-zfs
  • 系统镜像用 Ubuntu 24.04 Cloud Image
  • 当前用户的 ~/.ssh/authorized_keys 里已经有可用的 SSH 公钥

开启 Snippets

后面要用自定义的 Cloud-Init 配置文件,需要先让存储支持 Snippets:

  1. 登录 PVE 网页管理界面
  2. 依次进入 Datacenter → Storage,选中 local
  3. 点 Edit,在内容里勾上 Snippets,点 OK

下载并扩容镜像

在 PVE 节点上执行:

1
2
wget -q https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
qemu-img resize noble-server-cloudimg-amd64.img 32G

镜像是稀疏文件,下载下来约 2GB,扩到 32G 也不会真的占满 32G。大小按需改成 20G、40G、80G 都行。

创建虚拟机

1
2
3
4
5
6
7
sudo qm create 8001 --name "ubuntu-2404-cloudinit-template" --ostype l26 \
--memory 1024 \
--agent 1 \
--bios ovmf --machine q35 --efidisk0 local-zfs:0,pre-enrolled-keys=0 \
--cpu host --socket 1 --cores 1 \
--vga serial0 --serial0 socket \
--net0 virtio,bridge=vmbr0
  • 8001 是虚拟机 ID,可以换,但后面的命令要跟着改
  • --agent 1 启用 QEMU Guest Agent
  • --vga serial0 用串口当控制台,方便复制粘贴
  • --net0 接到默认网桥 vmbr0,要用 VLAN 就写成 bridge=vmbr0,tag=XX

导入系统盘并设置启动

1
2
3
4
5
6
7
8
# 导入下载的镜像
sudo qm importdisk 8001 noble-server-cloudimg-amd64.img local-zfs
# 挂成 virtio 磁盘
sudo qm set 8001 --scsihw virtio-scsi-pci --virtio0 local-zfs:vm-8001-disk-1,discard=on
# 从这块盘启动
sudo qm set 8001 --boot order=virtio0
# 加上 Cloud-Init 用的虚拟光驱
sudo qm set 8001 --scsi1 local-zfs:cloudinit

编写 vendor.yaml

1
2
3
4
5
6
7
8
9
10
sudo mkdir -p /var/lib/vz/snippets
cat << EOF | sudo tee /var/lib/vz/snippets/vendor.yaml
#cloud-config
runcmd:
- apt update
- apt install -y qemu-guest-agent
- systemctl start qemu-guest-agent
- reboot
# 来源:https://forum.proxmox.com/threads/combining-custom-cloud-init-with-auto-generated.59008/page-3#post-428772
EOF

这段配置会在首次开机时安装并启动 QEMU Guest Agent,然后重启一次,用来解决 Cloud-Init 初始化晚于网络服务、导致连不上 SSH 的问题。

设置 Cloud-Init 参数

1
2
3
4
5
6
sudo qm set 8001 --cicustom "vendor=local:snippets/vendor.yaml"
sudo qm set 8001 --tags ubuntu-template,24.04,cloudinit
sudo qm set 8001 --ciuser yourusername
sudo qm set 8001 --cipassword $(openssl passwd -6 'yourplaintextpassword')
sudo qm set 8001 --sshkeys ~/.ssh/authorized_keys
sudo qm set 8001 --ipconfig0 ip=dhcp
  • --cicustom:使用上面写的 vendor.yaml
  • --ciuser / --cipassword:默认用户和密码,密码先用 openssl 生成哈希再传入
  • --sshkeys:注入 SSH 公钥
  • --ipconfig0 ip=dhcp:用 DHCP 获取 IP(默认就是这样,写出来更直观)

转成模板

1
sudo qm template 8001

模板就做好了。以后克隆一台、开机,Cloud-Init 会自动创建用户、装好 Guest Agent 并重启一次,重启完就能 SSH 登录了。

原文还附了一套脚本,把上面的步骤自动化了,脚本开头有两个变量要按自己的 PVE 环境修改,需要的话去原文仓库里取。

参考

原文版权归原作者所有,译文仅供学习参考。原作者在文中感谢了论坛用户 ilude 提供设置密码的命令。