Dieser Artikel ist ein Einstieg in die Nutzung von Terraform mit Proxmox VE. Sie erfahren alle notwendigen Informationen - von der Installation von Terraform bis hin zum ersten Deployment einer Proxmox-Ressource (VM).
Der grundsätzliche Workflow in Terraform mit Proxmox VE ist also nach erfolgreicher Einrichtung wie folgt:
Als Basis habe ich einen Debian 12 Container erstellt und danach Terraform mit folgenden Kommandos installiert:[1]
apt install curl unzip && curl -O https://releases.hashicorp.com/terraform/1.5.3/terraform_1.5.3_linux_amd64.zip && unzip terraform_1.5.3_linux_amd64.zip mv terraform /usr/local/bin
Zuerst muss in Proxmox VE ein API-Token erstellt werden, dies passiert auf Datacenter Ebene unter dem Punkt Permissions -> API-Tokens -> Add. Wichtig ist, dass die Privilege Separation für diesen Funktionstest auf No gestellt ist, bzw. Sie bei der Erstellung des API Tokens den Haken nicht setzen. Bitte kopieren Sie sich den API-Key nach der Erstellung, da dieser danach nicht mehr nachträglich eingesehen werden kann. In unserem Fall ergeben sich dann folgende Credentials:
root@pam!terraform2 b057aea1-a092-49c3-b530-a53fd9e6fccc
Damit Terraform weiß, dass es Proxmox als Provider verwenden soll, muss eine provider.tf-Datei erstellt werden:
touch provider.tf nano provider.tf
terraform {
required_providers {
proxmox = {
source = "telmate/proxmox"
version = "2.9.14"
}
}
}
variable "proxmox_api_url" {
type = string
}
variable "proxmox_api_token_id" {
type = string
sensitive = true
}
variable "proxmox_api_token_secret" {
type = string
sensitive = true
}
provider "proxmox" {
pm_api_url= var.proxmox_api_url
pm_api_token_id = var.proxmox_api_token_id
pm_api_token_secret = var.proxmox_api_token_secret
pm_tls_insecure = true
}
Zusätzlich muss sich Terraform nun mit dem API-User und API-Key gegenüber Proxmox VE authentifizieren, hier kann man sich an der folgenden Konfig-Datei credentials.auto.tfvars orientieren und an die eigene Umgebung anpassen:
touch credentials.auto.tfvars nano credentials.auto.tfvars
proxmox_api_url = "https://10.2.1.130:8006/api2/json" proxmox_api_token_id = "root@pam!terraform2" proxmox_api_token_secret = "b057aea1-a092-49c3-b530-a53fd9e6fccc"
da in Terraform die Verwendung von Cloud-Images sinnvoll ist, ein kurzer Einblick, wie man ein solches Cloud-Image erstellt und modifiziert. Dazu wird auf dem Proxmox-Hypervisor ein Ubuntu Image runtergeladen und es wird das Paket libguestfs-tools installiert, welches benötigt wird, um Anpassungen im Cloud-Image vornehmen zu können.[2] Details zur Erstellung von Cloud-Init-Templates findet man im Artikel Cloud Init Templates in Proxmox VE - Quickstart
Das Virt-Customize Tool ist sehr umfangreich und kann unter Anderem folgende Optionen:
--run SCRIPT --touch FILE --firstboot SCRIPT --mkdir DIR --move SOURCE:DEST --install PKG,PKG --firstboot-install PKG,PKG --append-line FILE:LINE
Die Templates sind vorbereitet und man kann anhand dieser Templates nun beliebig viele VMs deployen, in dem folgenden Beispiel 4 sofort lauffähige VMs inklusiver IP-Konfiguration, Hostname usw. Dazu wurden 3 weitere Ressource-Dateien mit den Namen srv_demo_2.tf, srv_demo_3.tf und srv_demo_4.tf angelegt und an unsere Bedürfnisse angepasst.

Danach kann man zum ersten Mal testen, ob Terraform auf den Proxmox Host zugreifen könnte via API. Dazu verwendet man terraform init:
root@js-terraform-01:~# terraform init Initializing the backend... Initializing provider plugins... - Reusing previous version of telmate/proxmox from the dependency lock file - Using previously-installed telmate/proxmox v2.9.14 Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. root@js-terraform-01:~#
Ziel von Terraform ist es, vereinfacht einzelne Ressourcen hochziehen zu können auf diversen Hypervisoren (in diesem Fall Proxmox VE). Dazu definiert man Terraform-Konfigdateien, welche beschreiben, wie die zu provisionierende Ressource auszusehen hat. Ein Beispiel der Datei srvdemo1.tf Es wird ein Clone verwendet, dazu benötigen wir das VM-Template ubuntu2204-ci, welches später anhand eines Cloud-Images erstellt wird.
touch srvdemo1.tf nano srvdemo1.tf
resource "proxmox_vm_qemu" "srv_demo_1" {
name = "srv-demo-1"
desc = "Ubuntu-Server"
target_node = "PMX4"
sshkeys = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj8ipwPHVSI/yvERzILBD52zL1jj6Ja3ptWlVhR0WK6ElBekwKL314Sps79xAitJb>
agent = 1
clone = "ubuntu2204-ci"
qemu_os = "l26"
# this l26 is a small l like linux
cores = 2
sockets = 1
cpu = "host"
memory = 8096
scsihw = "virtio-scsi-pci"
vga {
type = "std"
}
disk {
storage = "vm_nvme"
type = "scsi"
size = "83212M"
discard = "on"
ssd = "1"
}
network {
bridge = "vmbr0"
model = "virtio"
}
## muss dem Template matchen
os_type = "cloud-init"
ipconfig0 = "ip=dhcp"
nameserver = "192.168.110.61"
ciuser = "tk"
}
Es wird eine VM erstellt inklusive IP-Konfiguration, zusätzlich wird ein Cloud-Image verwendet, welches man an seine eigenen Bedürfnisse auch anpassen kann.
Mit terraform plan kann man dann die VM mittels terraform planen lassen, das heißt es wird noch keine Ressource erzeugt, die Konfig-Datei und Verbindung zum Provider wird getestet und validiert.
root@js-terraform-01:~# terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# proxmox_vm_qemu.srv_demo_1 will be created
+ resource "proxmox_vm_qemu" "srv_demo_1" {
+ additional_wait = 5
+ agent = 1
+ automatic_reboot = true
+ balloon = 0
+ bios = "seabios"
+ boot = (known after apply)
+ bootdisk = (known after apply)
+ ciuser = "tk"
+ clone = "ubuntu2204-ci"
+ clone_wait = 10
+ cores = 2
+ cpu = "host"
+ default_ipv4_address = (known after apply)
+ define_connection_info = true
+ desc = "Ubuntu-Server"
+ force_create = false
+ full_clone = true
+ guest_agent_ready_timeout = 100
+ hotplug = "network,disk,usb"
+ id = (known after apply)
+ ipconfig0 = "ip=dhcp"
+ kvm = true
+ memory = 8096
+ name = "srv-demo-1"
+ nameserver = "192.168.110.61"
+ onboot = false
+ oncreate = true
+ os_type = "cloud-init"
+ preprovision = true
+ reboot_required = (known after apply)
+ scsihw = "virtio-scsi-pci"
+ searchdomain = (known after apply)
+ sockets = 1
+ ssh_host = (known after apply)
+ ssh_port = (known after apply)
+ sshkeys = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj8ipwPHVSI/yvERzILBD52zL1jj6JaSKoN1t1ftXEKbp+cuwZPUWykvSaR13ptWlVhR0WK6ElBekwKL314Sps79xAitJbbD35yDuMVtLUK/Bo+j2ehuWWmFZMwi1UKsPgCzF/YarsX12aCIS2Gyyf2NnscgOGlQKIdcgtfO23Xz18yxQxmFuRFVbFscd7gghRoQWsoKKwldbCKS8JEbXE8Mrb5mA7XD1C4dQLMnFvoJUvx3UqZinQHc20lWjqlZIOZ0uxRz6ssVFoCn+bKKNdf43JEnwPhcxQC2vGmKWunojNsXCifdx16fvd/wegXrdL8uw2oWUAvNsjCIUYCFn+VOn5JXEAxlXCAUNN9Z9H6/64QhwTjAXibwzB8Yj2+mGqd2ODy9ZIs+nzqxsmITA8+ayaEigZngol54f6vafmQzRHrM6Zn768UEYqEGb2LgYtI/0eTClO+E0HAPVfwpRwy6T1MhmIY8otSizE3PN3pg+fcyxv9oyMnxVsYCpspzE= root@js-terraform-01>"
+ tablet = true
+ target_node = "PMX4"
+ unused_disk = (known after apply)
+ vcpus = 0
+ vlan = -1
+ vmid = (known after apply)
+ disk {
+ backup = true
+ cache = "none"
+ discard = "on"
+ file = (known after apply)
+ format = (known after apply)
+ iops = 0
+ iops_max = 0
+ iops_max_length = 0
+ iops_rd = 0
+ iops_rd_max = 0
+ iops_rd_max_length = 0
+ iops_wr = 0
+ iops_wr_max = 0
+ iops_wr_max_length = 0
+ iothread = 0
+ mbps = 0
+ mbps_rd = 0
+ mbps_rd_max = 0
+ mbps_wr = 0
+ mbps_wr_max = 0
+ media = (known after apply)
+ replicate = 0
+ size = "83212M"
+ slot = (known after apply)
+ ssd = 1
+ storage = "vm_nvme"
+ storage_type = (known after apply)
+ type = "scsi"
+ volume = (known after apply)
}
+ network {
+ bridge = "vmbr0"
+ firewall = false
+ link_down = false
+ macaddr = (known after apply)
+ model = "virtio"
+ queues = (known after apply)
+ rate = (known after apply)
+ tag = -1
}
+ vga {
+ type = "std"
}
}
Mit terraform apply können die Ressourcen dann erstellt werden, einmal mit yes bestätigen und dann werden (in diesem Fall 4 VMs) deployed. Die Ausgabe wurden zur besseren Übersichtlichkeit gekürzt, sodass nur die vollständige Ausgabe von srv_demo_1 ausgegeben wird:
root@js-terraform-01:~# terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# proxmox_vm_qemu.srv_demo_1 will be created
+ resource "proxmox_vm_qemu" "srv_demo_1" {
+ additional_wait = 5
+ agent = 1
+ automatic_reboot = true
+ balloon = 0
+ bios = "seabios"
+ boot = (known after apply)
+ bootdisk = (known after apply)
+ ciuser = "tk"
+ clone = "ubuntu2204-ci"
+ clone_wait = 10
+ cores = 2
+ cpu = "host"
+ default_ipv4_address = (known after apply)
+ define_connection_info = true
+ desc = "Ubuntu-Server"
+ force_create = false
+ full_clone = true
+ guest_agent_ready_timeout = 100
+ hotplug = "network,disk,usb"
+ id = (known after apply)
+ ipconfig0 = "ip=dhcp"
+ kvm = true
+ memory = 8096
+ name = "srv-demo-1"
+ nameserver = "192.168.110.61"
+ onboot = false
+ oncreate = true
+ os_type = "cloud-init"
+ preprovision = true
+ reboot_required = (known after apply)
+ scsihw = "virtio-scsi-pci"
+ searchdomain = (known after apply)
+ sockets = 1
+ ssh_host = (known after apply)
+ ssh_port = (known after apply)
+ sshkeys = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj8ipwPHVSI/yvERzILBD52zL1jj6JaSKoN1t1ftXEKbp+cuwZPUWykvSaR13ptWlVhR0WK6ElBekwKL314Sps79xAitJbbD35yDuMVtLUK/Bo+j2ehuWWmFZMwi1UKsPgCzF/YarsX12aCIS2Gyyf2NnscgOGlQKIdcgtfO23Xz18yxQxmFuRFVbFscd7gghRoQWsoKKwldbCKS8JEbXE8Mrb5mA7XD1C4dQLMnFvoJUv= root@js-terraform-01>"
+ tablet = true
+ target_node = "PMX4"
+ unused_disk = (known after apply)
+ vcpus = 0
+ vlan = -1
+ vmid = (known after apply)
+ disk {
+ backup = true
+ cache = "none"
+ discard = "on"
+ file = (known after apply)
+ format = (known after apply)
+ iops = 0
+ iops_max = 0
+ iops_max_length = 0
+ iops_rd = 0
+ iops_rd_max = 0
+ iops_rd_max_length = 0
+ iops_wr = 0
+ iops_wr_max = 0
+ iops_wr_max_length = 0
+ iothread = 0
+ mbps = 0
+ mbps_rd = 0
+ mbps_rd_max = 0
+ mbps_wr = 0
+ mbps_wr_max = 0
+ media = (known after apply)
+ replicate = 0
+ size = "83212M"
+ slot = (known after apply)
+ ssd = 1
+ storage = "vm_nvme"
+ storage_type = (known after apply)
+ type = "scsi"
+ volume = (known after apply)
}
+ network {
+ bridge = "vmbr0"
+ firewall = false
+ link_down = false
+ macaddr = (known after apply)
+ model = "virtio"
+ queues = (known after apply)
+ rate = (known after apply)
+ tag = -1
}
+ vga {
+ type = "std"
}
}
# proxmox_vm_qemu.srv_demo_2 will be created
# proxmox_vm_qemu.srv_demo_3 will be created
# proxmox_vm_qemu.srv_demo_4 will be created
Plan: 4 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
proxmox_vm_qemu.srv_demo_4: Creating...
proxmox_vm_qemu.srv_demo_2: Creating...
proxmox_vm_qemu.srv_demo_3: Creating...
proxmox_vm_qemu.srv_demo_1: Creating...
...
proxmox_vm_qemu.srv_demo_4: Creation complete after 39s [id=PMX4/qemu/103]
proxmox_vm_qemu.srv_demo_3: Creation complete after 47s [id=PMX4/qemu/101]
proxmox_vm_qemu.srv_demo_1: Creation complete after 49s [id=PMX4/qemu/102]
proxmox_vm_qemu.srv_demo_2: Creation complete after 53s [id=PMX4/qemu/104]
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

|
Autor: Jonas Sterr Ich beschäftige mich mit den Themen Software Defined Storage, Proxmox Virtualisierung auf Basis von KVM, QEMU & Ceph im Produktmanagement der Thomas-Krenn.AG in Freyung. Proxmox ist meine absolute Leidenschaft und ich freue mich gerne über Kontaktanfragen und einen Austausch auf LinkedIn.
|