自动化运维之Cloud-Init
一、前言
在PVE中进行测试或者部署集群时,经常需要一次性启动大量虚拟机,如果一台一台手动安装费时费力还容易出错。有没有什么法子可以自动化进行安装?有的有的,cloud-init负责配置虚拟机,terraform负责实现一键部署虚拟机。
本文使用环境配置为:
- 虚拟化平台:
PVE 9.0.6 - 自动化运维工具:
terraform - 系统初始化工具:
cloud-init - 虚拟机系统:
Debian 13
参考文章:
二、什么是Cloud-Init
在生产环境,尤其是云服务供应商的大规模生产环境中,如何快速启动一个已初始化的虚拟机是个很重要的问题。针对此需求,cloud-init应运而生,该方案可以快速启动多个虚拟机且同时完成IP、软件源、用户等等配置,开箱即用无需手动一台台安装虚拟机。
使用clolud-init需要有两个先决条件:
- 虚拟机的系统镜像支持
cloud-init且未启动过,即首次启动过程中会查找是否有数据源并进行自动配置 - 虚拟机有可访问的配置数据源,将按配置初始化系统
1. 系统镜像
绝大多数发行版官方提供云镜像,或者可以使用普通的镜像手动安装cloud-init使其成为云镜像。虽然自行封装的云镜像自定义化程度更高,但是为了向后兼容性和可维护性还是推荐从基础镜像开始,一切初始化都通过cloud-init的配置实现。
在此就以Debian 13的qcow2云镜像为例,将其下载到PVE主机上:
1 | wget https://cloud.debian.org/images/cloud/trixie/20250924-2245/debian-13-genericcloud-amd64-20250924-2245.qcow2 |
创建虚拟机:
1 | qm create 9000 --name ci-vm |
PS: 其实这里虚拟机的配置不重要,后面具体配置都是通过terraform进行申明。
2. 数据源配置
cloud-init数据源由一系列配置文件组成:
user-data.yml: 主要的配置文件network-config.yml: 关于网络如ip/nameserver/dns等的定义meta-data.yml: 一般包含instance id,唯一的一个机器标识符vendor-data.yml: 由供应商(云)定义,类似user-data的数据,可为空
如何让虚拟机在启动过程中访问到cloud-init数据源是关键问题,不同的云供应商有不同的方式,但是基本可归结为以下几种:
本地驱动器挂载
- 将一系列配置文件打包为
ISO文件并在启动前挂载到虚拟机上 - 通过软盘驱动器挂载
- 将一系列配置文件打包为
远程HTTP、FTP等配置获取
- 预先在云镜像的
/etc/cloud/cloud.cfg或/etc/cloud/cloud.cfg.d/内配置好数据源URL - 内置了某些的云服务商(AWS、AliYun等)的数据源地址
- 预先在云镜像的
虽然获取配置方式多种多样,但是殊途同归,最终目标就是让虚拟机得到cloud-init的配置文件。
cloud-init 的可配置项目非常丰富,可以查阅官方的examples,贴出一个常用的user-data.yml文件:
1 | #cloud-config |
使用genisoimage命令将cloud-init 配置文件打包成一个ISO文件:
1 | genisoimage -output cloud-init-data.iso -volid cidata -joliet -rock user-data meta-data network-config |
3. 测试
首先要将生成的cloud-init-data.iso挂载到虚拟机:
1 | qm importdisk 9000 cloud-init-data.iso local-lvm |
开机验证配置是否正确。这部分简单说明,只是为了了解cloud-init是如何实现的,具体的参考基于Cloud-init定制化虚拟机,作者写的非常好。并且我这里没有加入网络相关的配置,所以虚拟机是没有IP的,network-config.yml用来储存网络相关配置,但是网卡名字是启动后系统自行设置的,具体规则几何还待研究。
三、基础设施即代码Terraform
Terraform官方口号为基础设施即代码,所以理念也很清楚就是使用代码来定义一切,甚至可以一键部署上百台虚拟机。
简单来说,通过编写Terraform配置文件并Apply即可完成各种基础设施的操作,它通过Provider支持了各个云服务商、PVE等虚拟化平台、K8S等容器编排工具的操作,功能包括但不限于创建虚拟机、上传文件、开关机。
对于Terraform配置文件,简单来说分为以下几个组建:
provider提供操作基础设施的能力resource定义一个资源,如PVE中的虚拟机- 模版渲染、SSH操作、文件读写等其他辅助功能
Terraform的好处显而易见,将一切的图形化、脚本化操作转变为了配置,并且可持久化跟踪资源状态(支持本地、数据库、对象存储等作为状态存储),实现基础设施的幂等、统一管理等功能特性。
1. 创建PVE用户
创建在PVE中创建用户并设置合适的权限,以供Terraform PVE Provider使用:
1 | pveum role add TerraformProv -privs "Datastore.AllocateSpace Datastore.AllocateTemplate Datastore.Audit Pool.Allocate Sys.Audit Sys.Console Sys.Modify VM.Allocate VM.Audit VM.Clone VM.Config.CDROM VM.Config.Cloudinit VM.Config.CPU VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Migrate VM.PowerMgmt SDN.Use" |
- 由于测试环境为PVE 9.0,官方移除了
VM.Monitor权限,这里也移除 - 安全起见使用Token而不是密码,因此不设置用户密码
为terraform-prov@pve生成Token:
1 | pveum user token add terraform-prov@pve mytokenXXX |
记录下返回的token_id和token_secret,类似于:
1 | token_id = "terraform-prov@pve!mytokenXXX" |
2. Terraform创建
cloud-init 配置分割为两部分:
user-data.yml: 储存较为固定的通用配置,需要上传到PVE的某个目录里resource "proxmox_vm_qemu"中ipconfig0和nameserver: 网络配置
首先需要有虚拟机模版:
1 | qm template 9000 |
资源定义如下:
1 | terraform { |
执行terraform apply即可观察虚拟机创建。
四、其他
hostname定义在user-data.yml中,无法直接在Terraform中修改,可以考虑针对每个虚拟机创建各自的user-data.yml并使用Terraform的terraform-data上传至PVE主机- 使用
genericcloud模板镜像对dkms支持有问题,如果需要完整功能请用类似debian-13-generic-amd64-20250924-2245.qcow2的镜像。


