Blog

Proxmox VMs and Terraform

By Jay

Jul 5, 2023 | 4 minutes read

Series: HomeLab

Tags: blog, tech, terraform, proxmox

In the last post I provided a bash script that can be used to build proxmox templates for all of the current Ubuntu LTS releases. Today, I’m going to be using those templates as part of a terraform workflow to deploy VMs onto my Proxmox infrastructure.

There are a number of terraform providers for Proxmox, but for my purposes I chose to use the Telmate Proxmox provider. I did not put a lot of research into this process, so there is a good chance that there may be a better solution; I based my choice primarily on the download stats.

With that out of the way, on to the use case. I need to spin up anywhere from one to six VMs for my work, which ranges from needing a host running Docker to connect to with DevPod or Docker’s Devcontainers to standing up a set of systems to run Kubernetes. There are also some one-off tasks, such as my current work digging into PrivateGPT . Once spun up, these systems have a limited lifetime, and I want to easily be able to tear them down when I am done.

Here are the current scripts; bear in mind that these are still in very early Alpha/WIP status.

terraform {
  required_providers {
    proxmox = {
      source  = "Telmate/proxmox"
      version = "2.9.10"
    }
  }
}

variable "pm_api_url" {
  description = "The API URL for the Proxmox provider."
  type        = string
}

variable "pm_user" {
  description = "The user for the Proxmox provider."
  type        = string
}

variable "pm_password" {
  description = "The password for the Proxmox provider."
  type        = string
  sensitive   = true
}

variable "pm_tls_insecure" {
  description = "Whether to disable TLS verification for the Proxmox provider."
  type        = string
}

provider "proxmox" {
  pm_api_url      = var.pm_api_url
  pm_user         = var.pm_user
  pm_password     = var.pm_password
  pm_tls_insecure = var.pm_tls_insecure
}

variable "storage" {
  description = "The storage to use for the VMs."
  type        = string
}

variable "name_prefix" {
  description = "The prefix for the name of the VMs."
  type        = string
}

variable "node" {
  description = "The node where you want the VMs to be created at."
  type        = list(string)
}

variable "vm_count" {
  description = "The number of VMs to create."
  type        = number
}

variable "template" {
  description = "The template to use for creating the VMs."
  type        = string
}

variable "ssh_keys" {
  description = "The SSH keys to use for the VMs."
  type        = string
}


resource "proxmox_vm_qemu" "proxmox_vm" {
  count       = var.vm_count
  name        = "${var.name_prefix}${count.index}"
  clone       = var.template
  os_type     = "cloud-init"
  target_node = var.node[count.index % length(var.node)]
  cores       = "4"
  sockets     = "1"
  cpu         = "host"
  memory      = 8192
  scsihw      = "virtio-scsi-pci"
  bootdisk    = "scsi0"
  agent       = 1

  disk {
    size     = "130G"
    type     = "scsi"
    storage  = var.storage
    iothread = 0
  }

  network {
    model  = "virtio"
    bridge = "vmbr0"
  }

  lifecycle {
    ignore_changes = [
      network,
    ]
  }

  sshkeys = var.ssh_keys
}
pm_api_url      = "https://your_proxmox_api_url"
pm_user         = "your_proxmox_user"
pm_password     = "your_proxmox_password"
pm_tls_insecure = "true_or_false"
node            = ["node1", "node2"]
vm_count        = 4
template        = "your_template_name"
ssh_keys        = "your_ssh_public_key"
name_prefix     = "your_name_prefix"
storage         = "your_storage_name"

To run, you simply update the variables file with your parameters and then do the normal “terraform plan / terraform apply” dance, being sure to pass the variables file along:

$ terraform plan -var-file="variables.tfvars"
$ terraform apply -var-file="variables.tfvars"

When you are done, you can simply remove your deployed infrastructure with:

$ terraform destroy -var-file="variables.tfvars"
  1. Depending on the speed of your Proxmox hardware, it is possible to cause weird race conditions when deploying multiple VMs to the same node. If this happens you will need to manually destroy the partially completed infrastructure.
  2. This currently works for VMs, but I also have a terraform script for building out containers that I will post in the future.
  3. Since I know that cutting/pasting out of a blog post is suboptimal, I also have these and other scripts that I use for building out my development infrastructure in GitHub. Be aware that these scripts are under pretty heavy development (which is a nice way of saying I’ll be making mistakes, breaking things, fixing things, etc in that repo).