-proxmox - vm's - vm - virtualization - terraform
Terraform with Proxmox¶
References¶
The complete terraform api reference for proxmox, find every variable you can set for the proxmox_vm_qemu provider: https://github.com/Telmate/terraform-provider-proxmox/blob/master/proxmox/resource_vm_qemu.go
Requirements:¶
- Proxmox
- Cloud-Init Optional but EXTREMELY RECOMMENDED
- A VM, I'm using a cloud-init Alpine VM for this test.
Set up Proxmox User and API Key¶
There are many articles on this step already, https://registry.terraform.io/providers/Telmate/proxmox/latest/docs is a good one.
Set up C&C¶
In the VM you need to install terraform.
Alpine:
apk add terraform --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community
Create some files¶
You need at bare minimum from my (minimal, cursory) understanding, vars.tf and main.tf files.
- main.tf : This file contains the main definition of your vm's
- vars.tf : Specify the variables you want to be more easily set without having to dig through the entirety of main.tf to do so.
Examples:
vars.tf¶
#Set your public SSH key here
variable "ssh_key" {
default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBi7A81T7smfUrtyqDjg8kRjiuNu6KmS/CGVBMOn0WAPg/k5D4uAZT3CsO/MrpwFyx5Zx+wFd82Y+e68WRzqV2gsNszCUiG+7BEWD+ArDMUf/zbj7vafR4xzm8f9bPVRmV9PPqjnauZadAcwEP7rGHa8n8Eun8khB/cyfkRU3K/ziE7vhVCku82ECsYr5vsHs9+M+Q6j/IXoKFD9blBdqVgwUR6NjvKmpIo2kqe2f64mKrE0x2F95KWsWKjVu0ugwjYrpwmLmQFJYr4xBa+XAlwL9K99rJQrcKWUskiupbtYs0OgQPEnYamqQjLgB0qe4DD9bB4N/6NZMioVA24oXx deadc0de@deadc0de-PC"
}
variable "hostname" {
default = "terraform-test"
}
#Establish which Proxmox host you'd like to spin a VM up on
variable "proxmox_host" {
default = "hpve"
}
#Specify which template name you'd like to use
variable "template_name" {
default = "10GB-Alpine-Cloud"
}
#Establish which nic you would like to utilize
variable "nic_name" {
default = "vmbr0"
}
#Establish the VLAN you'd like to use
variable "vlan_num" {
default = "1"
}
#Provide the url of the host you would like the API to communicate on.
#It is safe to default to setting this as the URL for what you used
#as your `proxmox_host`, although they can be different
variable "api_url" {
default = "https://pve.centerionware.com:8006/api2/json"
}
#Blank var for use by terraform.tfvars
variable "token_secret" {
default = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
#Blank var for use by terraform.tfvars
variable "token_id" {
default = "EXAMPLE@pve!terraform_api_token"
}
main.tf¶
terraform {
required_providers {
proxmox = {
source = "telmate/proxmox"
#latest version as of Nov 30 2022
version = "2.9.11"
}
}
}
provider "proxmox" {
# References our vars.tf file to plug in the api_url
pm_api_url = var.api_url
# References our secrets.tfvars file to plug in our token_id
pm_api_token_id = var.token_id
# References our secrets.tfvars to plug in our token_secret
pm_api_token_secret = var.token_secret
# Default to `true` unless you have TLS working within your pve setup
pm_tls_insecure = true
}
#data "template_file" "user_data" {
# template = file("cloud-init.yml")
#}
resource "proxmox_vm_qemu" "proxmox_vm" {
count = 1
name = "${var.hostname}-${count.index}"
target_node = var.proxmox_host
clone = var.template_name
os_type = "cloud-init"
cores = 1
sockets = "1"
cpu = "host"
full_clone = false
agent = 1
memory = 2048
scsihw = "virtio-scsi-pci"
bootdisk = "virtio0"
# cicustom = data.template_file.user_data.rendered
disk {
slot = "0"
size = "10G"
type = "virtio"
storage = "local-zfs"
iothread = 1
}
network {
# id = "0"
model = "virtio"
bridge = "vmbr0"
}
lifecycle {
ignore_changes = [
network,
]
}
cicustom = "user=cloud-inits:snippets/gitlab-runner-user.yml,network=cloud-inits:snippets/gitlab-runner-network.yml,vendor=cloud-inits:snippets/gitlab-runner-install.yml"
}
WIP¶
main.tf is a WIP. Currently it uses cloud-init snippets stored in a directory volume named 'cloud-inits' on the proxmox hosts. Future versions will login via ssh to the proxmox server and upload these files using terraforms built in providers to do exactly that. An example (from: https://yetiops.net/posts/proxmox-terraform-cloudinit-saltstack-prometheus/)
(This would be modified to the desired configuration and added to main.tf, probably near the top, for each of the cloud-init files that need to be uploaded.)
# Source the Cloud Init Config file
data "template_file" "cloud_init_deb10_vm-01" {
template = "${file("${path.module}/files/cloud_init_deb10.cloud_config")}"
vars = {
ssh_key = file("~/.ssh/id_rsa.pub")
hostname = "vm-01"
domain = "yetiops.lab"
}
}
# Create a local copy of the file, to transfer to Proxmox
resource "local_file" "cloud_init_deb10_vm-01" {
content = data.template_file.cloud_init_deb10_vm-01.rendered
filename = "${path.module}/files/user_data_cloud_init_deb10_vm-01.cfg"
}
# Transfer the file to the Proxmox Host
resource "null_resource" "cloud_init_deb10_vm-01" {
connection {
type = "ssh"
user = "root"
private_key = file("~/.ssh/id_rsa")
host = "10.15.31.7"
}
provisioner "file" {
source = local_file.cloud_init_deb10_vm-01.filename
destination = "/var/lib/vz/snippets/cloud_init_deb10_vm-01.yml"
}
}
Running terraform¶
Init¶
Now with vars.tf and main.tf in place, and terraform installed, terraform can be initialized.
terraform init
Plan¶
Run terraform in plan mode to visualize the changes to be made
terraform plan -out plan
Apply¶
Once the plan is approved you can apply it.
terraform apply plan
If you need to cancel, control+c twice can leave dirty VM's, let things play out. I tried it to see what would happen while it was creating a vm, and it did still make the vm, but then terraform was unable to destroy it and I had to manually do that. Just be careful here.
Destroy¶
If you're done with your VM and ready to destroy it
terraform destroy