Terraform et Proxmox
Cet article est un peu le préquel de celui sur Ansible. Cette fois, on va s’attarder sur l’étape précédente avec le déploiement d’une dizaine de VM sous Promox avec Terraform.
Terraform est un outil libre d’orchestration développé par HashiCorp à qui on doit déjà les excellents Vault, Packer et Consul. Il est utilisé pour provisionner des infrastructures complètes (serveurs, équipements réseaux, DNS, Firewall…) en utilisant un langage déclaratif (HCL Hashicop Configuration Language). Terraform est aujourd’hui un standard de fait de l’IaC (Infrastructure as Code).
Configurer Proxmox
Création d’un jeton d’API
Je commence par déclarer un rôle dédié avec les permissions nécéssaires pour créer des VMs.
En SSH sur le serveur Proxmox :
- créer un rôle dédié
Terraform
1pveum role add Terraform -privs "VM.Allocate VM.Clone VM.Config.CDROM VM.Config.CPU VM.Config.Cloudinit VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Monitor VM.Audit VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit"
- ajouter un utilisateur dédié
terraform
dans le royaumepve
(voir gestion des utilisateurs)
1pveum user add terraform@pve -password <password> -comment "Terraform account"
- affecter le rôle
Terraform
à l’utilisateurterraform@pve
1pveum aclmod / -user terraform@pve -role Terraform
- créer le jeton pour accéder à l’API (à conserver précieusement)
1pveum user token add terraform@pve terraform -expire 0 -privsep 0 -comment "Terraform token"
2┌──────────────┬──────────────────────────────────────────────────────────┐
3│ key │ value │
4╞══════════════╪══════════════════════════════════════════════════════════╡
5│ full-tokenid │ terraform@pve!terraform │
6├──────────────┼──────────────────────────────────────────────────────────┤
7│ info │ {"comment":"Terraform token","expire":"0","privsep":"0"} │
8├──────────────┼──────────────────────────────────────────────────────────┤
9│ value │ c9995d9f-72d9-4adc-8ddb-80a0ccf470cc │
10└──────────────┴──────────────────────────────────────────────────────────┘
L’option -privsep 0
permet l’héritage des permissions de l’utilisateur.
Je peux maintenant interroger directement l’API Proxmox en utilisant ce jeton (la liste des noeuds dans cet exemple):
Depuis un poste client:
1curl -X GET 'https://pve-01.exemple.tld:8006/api2/json/nodes' -H 'Authorization: PVEAPIToken=terraform@pve!terraform=c9995d9f-72d9-4adc-8ddb-80a0ccf470cc'
2
3{"data":[{"status":"online","id":"node/pve-01","node":"pve-01","ssl_fingerprint":"C9:3B:55:FD:15:4F:35:46:75:85:B8:D7:CD:8E:F9:0C:75:39:3D:99:29:EF:56:F3:6C:F2:7C:21:70:08:95:1A","level":"","type":"node"}]}%
Création d’un modèle de VM
Terraform ne réalise pas de miracle, il se contente de cloner un modèle de VM et plus précisément une image “cloud” pour bénéficier de la personnalisation apportée par cloud-init.
La plupart des distributions fournissent des images au format qcow2
pour KVM:
Exemple avec Debian 11 (toujours en SSH sur le serveur Proxmox):
- télécharger l’image debian
1cd /tmp
2wget https://cdimage.debian.org/cdimage/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
- créer une VM avec un VMID libre (1000 dans l’exemple), adapter le nom du bridge à votre configuration réseau (vmbr1 dans mon cas pour le traffic réseau des VMs)
1qm create 1000 --memory 1024 --core 1 --name debian11-temp --net0 virtio,bridge=vmbr1 --description "Debian 11 cloud template"
- importer l’image Debian dans l’espace de stockage des VMs (“local-lvm” dans l’exemple)
1qm importdisk 1000 /tmp/debian-11-genericcloud-amd64.qcow2 local-lvm
2importing disk '/tmp/debian-11-genericcloud-amd64.qcow2' to VM 1000 ...
3 Logical volume "vm-1000-disk-0" created.
4Successfully imported disk as 'unused0:local-lvm:vm-1000-disk-0'
- attacher le disque au contrôleur de la VM
1qm set 1000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-1000-disk-0
2update VM 1000: -scsi0 local-lvm:vm-1000-disk-0 -scsihw virtio-scsi-pci
- définir le disque comme périphérique de boot par défaut
1qm set 1000 --boot c --bootdisk scsi0
- ajouter le CDrom pour cloud-init
1qm set 1000 --ide2 local-lvm:cloudinit
- ajouter un port serie et l’utiliser pour afficher la console
1qm set 1000 --serial0 socket --vga serial0
- convertir la VM en modèle (template)
1qm template 1000
- supprimer l’image Debian téléchargée
1rm -f /tmp/debian-11-genericcloud-amd64.qcow2
Si tout c’est bien passé, vous devriez obtenir ce résultat:
Installer Terraform
Terraform est un binaire écrit en Go. Hashicop fournit un dépôt pour la majorité des distributions (https://www.terraform.io/downloads) mais le plus simple reste encore de télécharger directement le binaire compilé pour votre plateforme.
exemple pour Mac OSX Intel (sur un poste client):
1wget https://releases.hashicorp.com/terraform/1.1.7/terraform_1.1.7_darwin_amd64.zip
2unzip terraform_1.1.7_darwin_amd64.zip
3sudo mv terraform /usr/local/bin/
4sudo chmod +x /usr/local/bin/terraform
5
6terraform -version
7Terraform v1.1.7
8on darwin_amd64
Utiliser Terraform
Le cycle de vie d’un projet Terraform est décomposé en 4 phases:
- Init : initialise le répertoire de travail et installe les fournisseurs (providers) nécessaires
- Plan : calcule les opérations à effectuer pour obtenir l’état souhaité
- Apply : applique les opérations pour atteindre l’état souhaité
- Destroy : supprime les ressources
Terraform fournit un registre qui référence les provider
pour lui permettent de communiquer avec une multitude de plateformes et d’équipements. Pour Proxmox, le plus populaire est celui proposé par Telmate.
Sur un poste client, je vais créer un dossier pour mon projet et 3 fichiers de configuration:
1mkdir Proxmox-Terraform && cd Proxmox-Terraform
2touch provider.tf main.tf variables.tfvars
3tree
4.
5├── main.tf
6├── provider.tf
7└── variables.tfvars
- provider.tf : pour installer et configurer le provider Proxmox (mettre la dernière version disponible)
1terraform {
2 required_providers {
3 proxmox = {
4 source = "Telmate/proxmox"
5 version = "2.9.6"
6 }
7 }
8}
9
10provider "proxmox" {
11 pm_api_url = var.pm_api_url
12 pm_api_token_id= var.pm_api_token_id
13 pm_api_token_secret= var.pm_api_token_secret
14 #pm_tls_insecure = true //for Proxmox self-signed certificate WUI
15}
- variables.tfvars : pour contenir les variables nécéssaires
Je reprends ici le jeton API et le nom du modèle de VM créés précédemment ainsi que le nom du noeud Proxmox qui va exécuter les VMs.
1variable "pm_api_url" {
2 default = "https://pve-01.exemple.tld:8006/api2/json"
3}
4variable "pm_api_token_id" {
5 default = "terraform@pve!terraform"
6}
7variable "pm_api_token_secret" {
8 default = "c9995d9f-72d9-4adc-8ddb-80a0ccf470cc"
9}
10variable "target_node" {
11 default = "pve-01"
12}
13variable "clone" {
14 default = "debian11-temp"
15}
16variable "ssh_key" {
17 default = "ssh-rsa AAAAB3NzaC1y............c2EAAAABIwAAA== user@destop.exemple.tld"
18}
- main.tf : pour décrire l’état souhaité (ajout de 10 VMs)
Dans cette configuration, j’utilise une itération sur la valeur “count” pour construire le nom de la VM et son adresse IP (test-vm-1 à test-vm-10).
1resource "proxmox_vm_qemu" "tp_servers" {
2 desc = "Deploiement 10 VM Debian sur Proxmox"
3 count = 10
4 name = "test-vm${count.index + 1}"
5 target_node = var.target_node
6 clone = var.clone
7
8 os_type = "cloud-init"
9 cores = 2
10 sockets = 1
11 cpu = "host"
12 memory = 2048
13 scsihw = "virtio-scsi-pci"
14 bootdisk = "scsi0"
15
16 disk {
17 slot = 0
18 size = "2G"
19 type = "scsi"
20 storage = "local-lvm"
21 iothread = 1
22 }
23
24 network {
25 model = "virtio"
26 bridge = "vmbr1"
27 }
28
29 ipconfig0 = "ip=192.168.1.${count.index + 1}/24,gw=192.168.1.1"
30 nameserver = 192.168.1.254
31 searchdomain = exemple.tld
32}
terraform init
La première commande à lancer est un terraform init
pour initialiser le répertoire et travail mais aussi installer le provider Proxmox.
1terraform init
2Initializing the backend...
3Initializing provider plugins...
4- Finding telmate/proxmox versions matching "2.9.6"...
5- Installing telmate/proxmox v2.9.6...
6- Installed telmate/proxmox v2.9.6 (self-signed, key ID A9EBBE091B35AFCE)
7
8Terraform has been successfully initialized!
terraform plan
Avec la commande terraform plan
, Terraform va determiner les actions à accomplir pour atteindre l’objectif que j’ai défini dans le main.tf
. Le résultat de la commande est relativement verbeuse (tronqué dans l’exemple) et permet de connaitre précisément les opérations qui vont être réalisées.
1terraform plan
2 + create
3
4Terraform will perform the following actions:
5
6 # proxmox_vm_qemu.test_server[0] will be created
7 + resource "proxmox_vm_qemu" "test_server" {
8 + clone = "debian11-temp"
9 + cores = 2
10 + cpu = "host"
11 + full_clone = true
12 + ipconfig0 = "ip=192.168.1.1/24,gw=192.168.1.1"
13 + memory = 2048
14 + name = "test-vm-1"
15 + nameserver = "192.168.1.254"
16 + os_type = "cloud-init"
17 + scsihw = "virtio-scsi-pci"
18 + searchdomain = "exemple.tld"
19 + sockets = 1
20 + tablet = true
21 + target_node = "pve-01"
22
23 + disk {
24 + size = "2G"
25 + storage = "local-lvm"
26 + type = "scsi"
27 }
28
29 + network {
30 + bridge = "vmbr1"
31 + macaddr = (known after apply)
32 + model = "virtio"
33 + queues = (known after apply)
34 + rate = (known after apply)
35 + tag = -1
36 }
37 }
terraform apply
C’est maintenant que la magie s’opère avec la commande terraform apply --auto-approve
(l’option --auto-approve
permet d’éviter le prompt de confirmation) qui va provisionner les VMs sur le serveur Proxmox.
1terraform apply --auto-approve
2proxmox_vm_qemu.test_server[8]: Creation complete after 1m59s [id=pve-01/qemu/107]
3proxmox_vm_qemu.test_server[3]: Still creating... [2m0s elapsed]
4proxmox_vm_qemu.test_server[9]: Still creating... [2m10s elapsed]
5proxmox_vm_qemu.test_server[9]: Creation complete after 2m11s [id=pve-01/qemu/108]
6proxmox_vm_qemu.test_server[7]: Creation complete after 2m12s [id=pve-01/qemu/109]
7proxmox_vm_qemu.test_server[3]: Still creating... [2m20s elapsed]
8proxmox_vm_qemu.test_server[3]: Still creating... [2m30s elapsed]
9proxmox_vm_qemu.test_server[3]: Creation complete after 2m34s [id=pve-01/qemu/110]
10proxmox_vm_qemu.test_server[6]: Still creating... [2m40s elapsed]
11proxmox_vm_qemu.test_server[6]: Creation complete after 2m47s [id=pve-01/qemu/111]
12
13Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
Et voilà: 2m47s pour créer 10 VMs prêtes à l’emploi !
1qm list
2 VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
3 102 test-vm-2 running 2048 2.00 536444
4 103 test-vm-1 running 2048 2.00 536524
5 104 test-vm-3 running 2048 2.00 536638
6 105 test-vm-6 running 2048 2.00 536795
7 106 test-vm-5 running 2048 2.00 537133
8 107 test-vm-9 running 2048 2.00 537308
9 108 test-vm-10 running 2048 2.00 537533
10 109 test-vm-8 running 2048 2.00 537529
11 110 test-vm-4 running 2048 2.00 537743
12 111 test-vm-7 running 2048 2.00 537898
13 1000 debian11-temp stopped 1024 2.00 0
Contrairement à Ansible, Terraform fonctionne en mode conservation d’état (stateful) et garde localement le résultat de la commande apply
( fichier terraform.tfstate
). En cas de modification du fichier main.tf
, Terraform n’exécutera que le delta entre la configuration en place et la nouvelle. Si je souhaite 5 VMs de plus, il suffit de passer la valeur count
à 15. La commande terraform plan
va m’indiquer Plan: 5 to add, 10 to change, 0 to destroy.
avec 5 nouvelles VMs dont les noms qui commenceront bien à partir de test-vm-11
à test-vm-15
.
terraform destroy
La commande terraform destroy
va comme son nom l’indique supprimer toutes les ressources créées
1terraform destroy
2proxmox_vm_qemu.test_server[1]: Destruction complete after 5s
3proxmox_vm_qemu.test_server[3]: Destruction complete after 5s
4proxmox_vm_qemu.test_server[2]: Destruction complete after 5s
5proxmox_vm_qemu.test_server[5]: Destruction complete after 7s
6proxmox_vm_qemu.test_server[6]: Destruction complete after 9s
7proxmox_vm_qemu.test_server[7]: Destruction complete after 9s
8proxmox_vm_qemu.test_server[0]: Destruction complete after 9s
9proxmox_vm_qemu.test_server[9]: Destruction complete after 11s
10proxmox_vm_qemu.test_server[4]: Destruction complete after 14s
11proxmox_vm_qemu.test_server[8]: Destruction complete after 14s
12
13Destroy complete! Resources: 10 destroyed.
Conclusion
Terraform est un outil puissant qui remplace avantageusement les solutions à base de PXE et de Preseed. Il est le compagnon idéal d’Ansible. L’article ne couvre que la création de VMs mais sachez que le provider de Telmate permet aussi de créer des conteneurs LXC avec la même facilité déconcertante.
Ressources
- how to deploy vms in proxmox with terraform
- terraformer son server
- how to create proxmox cloud templates
- Cloud images in Proxmox
- cloud init cloud image
- utiliser une image cloud init dans proxmox
- homelab with proxmox and terraform
- automating proxmox with terraform ansible
- provision proxmox vms with terraform
- Doc Proxmox - Cloud-Init_Support
- Terraform for beginners