VM 1. The better way (cloud-init) 2. What if I told you it can be reduced to this 3. Enter Terraform 1. Initialization 2. Upload base image 3. Create cloud-init config 1. Cloud-init dependencies 4. Creating a VM with Terraform 5. VM Configurations
Proxmox VE 2. In the UI, create a VM and specify configurations ISO image CPU Memory Disk size 3. Boot a VM and set configurations Username Password Public key Packages Workloads Problems with this setup You have to go through the installation process every time Unless you create a template off existing VM (which is a system image) This means if you have a lot of templates, it would require more of disk space
lot of configurations Notice that you have to provision your own public key Imagine you have 100 VMs to manage and you don’t want to reuse the keys… With cloud-init, you can have configuration templates, no system images required apt-get install cloud-init wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img qm create 9000 --memory 2048 --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci qm set 9000 --scsi0 local-lvm:0,import-from=/path/to/bionic-server-cloudimg-amd64.img qm set 9000 --ide2 local-lvm:cloudinit qm set 9000 --boot order=scsi0 qm set 9000 --serial0 socket --vga serial0 qm template 9000 qm clone 9000 123 --name ubuntu2 qm set 123 --sshkey ~/.ssh/id_rsa.pub qm set 123 --ipconfig0 ip=10.0.10.123/24,gw=10.0.10.1
this locals.tf then Obviously you need more terraform resource blocks, but when you have to spin up a VM this would be only thing you have to do locals { vms = { foo = { id = 100 # starts at 100 on_boot = true template = "base" # "docker", "kubernetes" -- cloud-init templates cpu = 1 memory = 512 disk = 8 } } } terraform apply
these two look promising: Telmate and bpg Telmate has more stars, but it is very buggy and slow, I encountered a lot of issues with it So far I’ve been using bpg for over a year without issues
it’s safer to upload it manually through the web console You can do this with terraform via resource "proxmox_virtual_environment_file" "iso" { content_type = "iso" datastore_id = "local" node_name = var.node_name source_file { path = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" } }
need to bake in public key) You also need to enable snippets: Under Datacenter > Storage local , add snippets to storage content type resource "proxmox_virtual_environment_file" "this" { for_each = toset(keys(local.vms)) content_type = "snippets" datastore_id = "local" node_name = var.node_name source_raw { data = templatefile("${path.module}/templates/${local.vms[each.key].template}.cloud-config.yaml.tftpl", { vm_name = each.key public_key = trimspace(tls_private_key.ecdsa[each.key].public_key_openssh) }) file_name = "${each.key}.cloud-config.yaml" } }
so you can use it to SSH into the VM locals { vms = { foo = { id = 100 # starts at 100 on_boot = true template = "base" # "docker", "kubernetes" cpu = 1 memory = 512 disk = 8 } } } resource "local_file" "vm_key" { for_each = toset(keys(local.vms)) content = trimspace(tls_private_key.ecdsa[each.key].private_key_pem) filename = "generated/keys/${each.key}.pem" depends_on = [tls_private_key.ecdsa] }
you to configure everything every time Unless you create a system image off it There’s cloud-init, but you need to apply more configurations Terraform can help you reduce steps to spin up a VM Plus you can track VM configurations as code At the end, you only have to create a single map block to specify VM configuration