外观
用 Terraform / OpenTofu 管理 PVE
写一份配置文件描述"我要几台什么样的虚拟机",交给 Terraform(或它的开源分支 OpenTofu)去创建、修改、销毁,而不是每次都在 Web UI 里点。适合需要反复搭建/拆除一批环境的场景:测试环境、课程实验、CI 里临时起的机器。
provider 不是 Proxmox 官方产品
Terraform/OpenTofu 对 PVE 的支持来自社区维护的 provider,不在 Proxmox 官方支持范围内。资源名、参数名和支持的功能以对应仓库/Registry 当前文档为准,本文的示例只用来说明形状,跨版本升级前先看一眼对方的更新日志。
为什么需要它
- 一次描述、多次复现:同一份配置能在测试环境和另一台机器上建出一样的东西。
- 有"计划-确认-执行"的中间步骤(
plan),比脚本直接调 API 更容易在动手前发现问题。 - 天然记录"当前应该有什么",配合版本控制能看到环境是怎么一步步变化的。
它不管客户机内部装什么软件——那是 Ansible 的活。
开始之前
- 了解 Terraform 的基本概念:配置文件(
.tf)、plan(预览将要做的改动)、apply(执行)、state(记录当前受管资源的状态文件)。 - 一个专门给自动化用的 API Token,权限限定在需要的范围内,不要用 root 密码。
- 一台已经转成模板的客户机(通常配合 Cloud-Init),克隆会比全新安装快得多,见 Cloud-Init:十秒钟开一台配好的虚拟机。
- 想清楚要在哪个 VMID 段或哪个资源池里试验,不要一上来就对着现有的生产客户机写配置。
两个主流 provider:先选一个
社区目前有两个活跃的 Proxmox provider,覆盖面和维护节奏不一样:
| Provider | 维护方 | 特点 |
|---|---|---|
| bpg/proxmox | 社区维护者 bpg,fork 自早期已停止维护的 danitso/terraform-provider-proxmox | 资源和数据源覆盖面广,更新活跃,社区目前更常推荐;Terraform Registry 和 OpenTofu Registry 都有收录 |
| Telmate/proxmox | 社区维护者 Telmate | 历史更久,但长期停留在预发布(release candidate)版本,功能覆盖不如 bpg/proxmox |
具体版本号自己去 Registry 查
两个 provider 都更新频繁,版本号写在这里很快就会过时。写配置前去对应的 Registry 页面确认当前版本和参数:bpg/proxmox、Telmate/proxmox。本文以 bpg/proxmox 为例,因为它目前功能更全。
配置 provider
hcl
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "~> 0.114" # 具体版本号去 Terraform Registry 上查当前值,这里只是示例
}
}
}
provider "proxmox" {
endpoint = "https://<pve-host>:8006/"
api_token = "<token用户>@<认证域>!<token-id>=<token-secret>" # 占位符,换成你自己的,不要提交进仓库
insecure = true # 自签证书环境下临时使用;正式环境建议换成受信任证书后去掉这行
}endpoint 不要加 /api2/json 后缀。api_token 的格式和直接调 REST API 时的 Authorization 头是同一套。
给 Token 配的权限
新建一个专门的用户和角色,只给需要的权限路径,而不是直接用 root@pam 或 Administrator 角色:
sh
# 宿主机 shell(或任何装了 pveum 客户端环境的机器),以有权限的账号执行
pveum user add terraform@pve
pveum role add Terraform -privs "VM.Allocate,VM.Clone,VM.Config.Disk,VM.Config.CPU,VM.Config.Memory,VM.Config.Network,VM.Config.Options,VM.Audit,VM.PowerMgmt,Datastore.AllocateSpace,Datastore.Audit,SDN.Audit"
pveum aclmod /vms -user terraform@pve -role Terraform
pveum aclmod /storage -user terraform@pve -role Terraform
pveum user token add terraform@pve provider --privsep=1这份权限列表只是起点
不同版本的 provider 需要的权限不完全一样(PVE 9.0 之后部分权限名也发生过变化),跟着 provider 报错逐条加更安全,不要图省事直接给一个过大的角色。SDN.Audit 这类权限缺失时,报错往往不会直接说"权限不够",而是表现为"读不到网桥列表"之类看似无关的问题。
一个最小示例
hcl
resource "proxmox_virtual_environment_vm" "test" {
name = "tf-test"
node_name = "<pve-node>"
clone {
vm_id = <模板vmid>
}
initialization {
ip_config {
ipv4 {
address = "dhcp"
}
}
}
}字段名和嵌套结构以你安装的 provider 版本文档为准——不同大版本之间调整过。真正开始写之前,去 provider 文档的资源页面对照参数名。
部分操作需要额外的 SSH 通道
bpg/proxmox provider 的少数功能(比如上传 snippets、某些磁盘导入方式)需要额外配置 SSH 连到节点执行命令,而不只是走 REST API。如果用到这些功能,需要给对应节点配好免密登录,并且只授权具体需要的命令,不要把整个 qm/pvesm 开放免密 sudo——这两个命令本身就等价于 root 权限。
工作流
terraform init:下载 provider。terraform plan:预览将要发生的改动,这一步不会真的改动任何东西。- 确认无误后
terraform apply。 - 不再需要时
terraform destroy,会删除这份配置管理的全部资源。
state 文件记录着"Terraform 认为自己在管理哪些资源",它和数据库一样重要:不要提交到会公开的 Git 仓库(里面可能包含配置细节甚至敏感信息),团队协作要用远程 backend 而不是本地文件互相覆盖。
apply 和 destroy 会直接改动或删除客户机
terraform apply 会让实际状态向配置文件靠拢:配置里删掉一个资源块,下次 apply 就会销毁对应的虚拟机和它的磁盘。如果 state 和实际情况对不上(比如有人手动在 Web UI 里改了东西又没有 terraform import),apply 可能做出意料之外的销毁动作。
影响范围:这份配置和 state 文件覆盖到的所有客户机,包括它们的磁盘。
前置条件:
- 先在测试用的 VMID 段或单独的资源池里试,不要一开始就指向生产客户机。
apply前一定完整看一遍plan的输出,留意有没有意料之外的销毁(-)动作。- 给 state 文件本身做备份或使用带版本历史的远程 backend。
如何回退:从最近一次 state 备份恢复;或者把被意外销毁的客户机当作新客户机重建,terraform import 重新纳入管理后再对齐配置。销毁掉的磁盘数据本身无法通过 Terraform 找回,只能依赖客户机自己的备份。
检查结果
terraform plan在没有手动改动的情况下应该显示"无变更"。- 去 Web UI 确认新建的客户机存在、配置和
.tf文件描述的一致。 terraform state list能看到所有受管资源,和你预期的数量对得上。
常见问题
apply 报权限不足。 对照 API 文档查看器 或 provider 报错信息,给 Token 补上缺的权限路径,而不是直接换成 root@pam。
克隆到别的节点很慢,或者报错找不到存储。 源客户机用了本地(非共享)存储时,跨节点克隆需要先在源节点克隆完,再整体迁移过去,耗时和磁盘大小相关。确认目标节点上有同名存储可用。
SSH 相关的操作报权限或连接错误。 检查 SSH 用户名是否正确配置、目标节点是否配了免密登录,以及该用户是否有对应命令的免密 sudo 规则。
升级 provider 后配置报字段不存在。 provider 版本更新可能重命名或重组参数块,升级前看一遍它的 CHANGELOG,不要盲目升级正在管理生产资源的项目。