Orchestrating with Terraform

In my previous post we used Proxmox:

  • Created a Linux VM
  • Customized the Linux VM
  • Created a Template of the Linux VM
  • Used Terraform to deploy the Linux VM

That’s great, but what’s the point of using Terraform to deploy a single VM?

Well, the purpose is to create templates to reduce the workload; to create something that is easily repeatable with a single command line.  But true orchestration would be to be able to replicate that for an entire environment.

Let’s start with deploying multiple VMs from a single template.  The template is just the base line – it’s assigned 2 vCPU cores, and 2 GB of memory.

First – Check Resources.  When you type in ‘yes’ to apply your plan, are you going to break your server?  Do you have enough resource to deploy 5 or 10 or 20 VMs or Containers?

Assuming you do have the resources, let’s revisit our single deployment script:

File:  rockylinux.tf

resource “proxmox_virtual_environment_vm” “rocky-server” {
name = “terraform-rocky”
node_name = “proxmox4”

clone {
vm_id = 9000
}

cpu {
cores = 2
type = “x86-64-v2-AES”
}

memory {
dedicated = 2048
}

disk {
datastore_id = “local-lvm”
size = 20
interface = “scsi0”
}

network_device {
bridge = “vmbr0”
}

initialization {
ip_config {
ipv4 {
address = “dhcp”
}
}
user_account {
username = var.vm_admin
password = var.vm_password
keys = [var.ssh_public_key]
}
dns {
servers = var.dns_servers
domain = var.domain
}
}

provisioner “local-exec” {
command = “sleep 120” # Wait 2 minutes for cloud-init
}
}

Now we’ll add another variables.tf

variable “vms” {
type = map(object({
cores = number
memory = number
disk = number
template_id = number
}
)
)

default = {
web1 = {
cores = 2
memory = 4096
disk = 40
template_id = 9000
}
web2 = {
cores = 2
memory = 4096
disk = 40
template_id = 9000
}
db1 = {
cores = 4
memory = 16384
disk = 100
template_id = 9000
}
app1 = {
cores = 8
memory = 32768
disk = 80
template_id = 9001
}
}
}

We’re setting up different conditions and resource configurations for each server we’re deploying based on function.  A web server with 2 vCPU cores and 4 GG memory, or a db server with 4 cores and 16 GB memory.  Same template, so our cloud-init is the same for each server ensuring we can log in, the qemu agent is running, etc., but now each VM deployed has a different name designating it’s purpose.

Update the rockylinux.tf (or create a new file)

resource “proxmox_virtual_environment_vm” “servers” {
for_each = var.vms
name = each.key # Uses the map key as VM name
node_name = “proxmox4”
clone {
vm_id = each.value.template_id
}
cpu { cores = each.value.cores
type = “x86-64-v2-AES”
}
memory {
dedicated = each.value.memory
}
disk {
datastore_id = “pvs-zfs”
size = each.value.disk interface = “scsi0”
}
network_device {
bridge = “vmbr0”
}

initialization {
ip_config {
ipv4 {
address = “dhcp”
}
}
user_account {
username = var.vm_admin
password = var.vm_password
keys = [var.ssh_public_key]
}
dns {
servers = var.dns_servers
domain = var.domain
}
}

provisioner “local-exec” {
command = “sleep 120” # Wait 2 minutes for cloud-init
}
}

rocky-linux-template.tf
HCL
          resource "proxmox_virtual_environment_vm" "servers" {
	for_each = var.vms
		name = each.key # Uses the map key as VM name
		node_name = "proxmox4"
		
    clone {
			vm_id = each.value.template_id
		}
	
    cpu { 
        cores = each.value.cores
			type = "x86-64-v2-AES"
		}

    memory {
			dedicated = each.value.memory
		}

    disk {
			datastore_id = "pvs-zfs"
			size = each.value.disk interface = "scsi0"
		}

    network_device {
			bridge = "vmbr0"
		}

		initialization {
			ip_config {
				ipv4 {
					address = "dhcp"
				}
			}

    user_account {
			username = var.vm_admin
			password = var.vm_password
			keys = [var.ssh_public_key]
		}

    dns {
			servers = var.dns_servers
			domain = var.domain
		}
	}

	provisioner “local-exec” {
		command = "sleep 120" # Wait 2 minutes for cloud-init
	}
}
        

Privacy Preference Center