Cloning VM templates in Proxmox with TerraForm

October 24, 2024

Terraform Cloning

Cloning with Terraform

Whilst cloning of virtual machines and templates is supported in Proxmox, and much customisation can be achieved with Cloud-Init, TerraForm allows you to take things to the next level.

When used together, Cloud-Init and TerraForm (or OpenTofu) allow you to customise the the configuration of machines during the deployment process, rather than doing so after as you may have to do with a straightforward cloning.

TerraForm / OpenTofu bring the added benefit of Infrastructure as Code, allowing the user to drive their infrastrucure from a code base defined as code.

To get started on Proxmox, you should first install and configure Cloud-Init as described here.

You will then need to install TerraForm or OpenTofu as per your your workstation or Infrastructure as Code staging machine OS.

Create or copy the main.tf to use with your project - an example can be found here (and is used in the video below): https://github.com/HouseOfLogicGH/ProxmoxPVE/blob/main/TerraformOpenTofuCloudInit

# Provider configuration (provider.tf)
terraform {
  required_providers {
    proxmox = {
      source = "telmate/proxmox"
      version = "3.0.1-rc4"
    }
  }
}

provider "proxmox" {
  pm_api_url = "https://proxmoxhostnameorip:8006/api2/json"
#  username and password options for security
#  pm_user    = "root@pam"
#  pm_password = "YourPasswordHere"

  # insecure unless using signed certificates
  pm_tls_insecure = true
  
  # api token id is in the form of: <username>@pam!<tokenId>
  pm_api_token_id = "root@pam!YourTokenId"

  # this is the full secret wrapped in quotes:
  pm_api_token_secret = "token-secret-here"

}

resource "proxmox_vm_qemu" "cloudinit-test" {
    name = "terraform-test-vm"
    desc = "A test for using terraform and cloudinit"

    # Node name has to be the same name as within the cluster
    # this might not include the FQDN
    target_node = "proxmoxnodename"

    # The destination resource pool for the new VM
#    pool = "pool0"

    # The template name to clone this vm from
    clone = "VM 9000"

    # Activate QEMU agent for this VM
    agent = 1

    os_type = "cloud-init"
    cores = 2
    sockets = 1
    vcpus = 0
    cpu = "host"
    memory = 2048
    scsihw = "virtio-scsi-pci"

    # Setup the disk
    disks {
        ide {
            ide2 {
                cloudinit {
                    storage = "local-lvm"
                }
            }
        }
        scsi {
            scsi0 {
                disk {
                    size            = 32
                    cache           = "writeback"
                    storage         = "local-lvm"
                    #storage_type    = "rbd"
                    #iothread        = true
                    #discard         = true
                    replicate       = true
                }
            }
        }
    }

    # Setup the network interface and assign a vlan tag: 256
    network {
        model = "virtio"
        bridge = "vmbr0"
        #tag = 256
    }

    # Setup the ip address using cloud-init.
    boot = "order=scsi0"
    # Keep in mind to use the CIDR notation for the ip.
    #ipconfig0 = "ip=192.168.10.20/24,gw=192.168.10.1"
    ipconfig0 = "ip=dhcp"
    #sshkeys = <<EOF
    #ssh-rsa 9182739187293817293817293871== user@pc
    #EOF
    serial {
      id   = 0
      type = "socket"
    }
    
    ciuser = "youusername"
    cipassword = "yourpassword"

}

Note the following for the TF file:

  • The base image should be referenced (which should have seen setup using cloud-init)
  • The hardware configuration of the TF file should reflect the hardware Proxmox base VM image - eg same disk types for example.
  • The host node should be referenced where the cloned VM will be provisioned to.
  • Credentials / tokens for Proxmox should be referenced in the tf or vars.tf file or the deployment will not work.
  • cloud-init details such as ciusername and cipassword and ip address details can be specified.
  • SSH keys are not required by default, but may be needed for additional configuration by other tools (eg Ansible) that need to connect to the VM.

Depending on whether you are running TerraForm or OpenTofu, you can then run either to apply the configuration and clone the VM:

terraform init
terraform apply

or

tofu init
tofu apply

When the deployment is complete, note that any changes you make to the tf files can be applied to the live vm using the relevant “apply” command. Example changes would be such things as adding extra disks, or perhaps changing the VLAN of the machine.

A video demonstration of the setup and deployment can be found here: