Virtuele machines deployen op ProxMox met Terraform en Ansible

Nadat ik afgelopen weekend de cursus “Deploying Resources to GCP with Terraform” te hebben voltooid, was het wel eens tijd om te kijken of dat ook werkt op mijn eigen proxmox testomgeving. Hoe kun je servers deployen via Terraform op ProxMox ? Hierbij de stappen die ik gezet heb.

CloudInit

Als eerste hebben we nodig een ProxMox server. Maar dat heb je al als het goed is.
Vervolgens hebben we een CloudInit image nodig. deze zorgt ervoor dat na de installatie er al een aantal dingen worden ingesteld zoals DNS, username en bijv. de ssh keys.
Als eerste maken we even een public key aan welke we kunnen gebruiken.

ssh-keygen -f cloudinit

We gaan er vanuit dat we een Ubuntu 20.04 LTS server willen gaan installeren. We voeren daarvoor de volgende commando’s uit op de proxmox server:

wget http://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
export VM_ID="5000" # Gebruik een hoog ID zodat we niet in conflict komen met VM ID's die we gaan uitrollen
qm create $VM_ID --memory 2048 --net0 virtio,bridge=vmbr0 --sockets 1 --cores 2 --vcpu 2 -hotplug network,disk,cpu,memory --agent 1 --name cloud-init-ubuntu20 --ostype l26
qm importdisk $VM_ID focal-server-cloudimg-amd64.img local-lvm # Waarbij local-lvm een storage locatie is
qm set $VM_ID --scsihw virtio-scsi-pci --virtio0 local-lvm:vm-$VM_ID-disk-0 # Waarbij local-lvm wederom de storage locatie is
qm set $VM_ID --ide2 local-lvm:cloudinit # Wederom local-lvm is de storage locatie
qm set $VM_ID --boot c --bootdisk virtio0
qm set $VM_ID --serial0 socket
qm template $VM_ID
rm focal-server-cloudimg-amd64.img

Als je nu naar de web interface van proxmox gaat zie je dat er een template aangemaakt is met nummer $VM_ID (5000) in ons geval.
Klik op deze template en klik daarna op Cloud-Init
Hierin kun je een aantal dingen instellen welke meegenomen worden bij het installeren van de server.
Je kunt bijv. de username opgeven. Als je daarbij ook de ssh public key opgeeft kun je connecten met de server nadat deze klaar is.
Deze installingen kunnen eventueel ook nog in Terraform geregeld worden.
Nu hebben we de cloudinit geregeld en kunnen we verder met het Terraform gedeelte.

Terraform

We installeren terraform op een device. Voor Ubuntu zetten we de volgende stappen

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install terraform

Voor CentOS/RHEL/AlmaLinux gebruiken we deze stappen

sudo yum install yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install terraform

We maken een directory aan waarbij we alle terraform dingetjes gaan doen

mkdir terraform
cd terraform

Om proxmox te kunnen gebruiken met Terraform hebben we de provider plugin nodig. Hiervoor maken we een bestand aan genaamd version.tf

vim version.tf

hierin kopieren we de volgende tekst

terraform {
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "2.6.8"
}
}
required_version = ">= 0.14"
}

Hiermee zorgen we dat terraform de Telmate proxmox plugin installeert.

vervolgens maken we een bestand aan var.tf

vim var.tf

en daarin plaatsen we de volgende tekst

variable "proxmox_host" {
type = map
default = {
pm_api_url = "https://pve_host:8006/api2/json"
pm_user = "root@pam"
target_node = "pve1"
}
}

variable "vmid" {
default = 400
description = "Starting ID for the CTs"
}

variable "hostnames" {
description = "VMs to be created"
type = list(string)
default = ["terra-test1", "terra-test2"]
}

variable "rootfs_size" {
default = "2G"
}

variable "ips" {
description = "IPs of the VMs, respective to the hostname order"
type = list(string)
default = ["10.10.10.100", "10.10.10.101"]
}

variable "ssh_keys" {
type = map
default = {
pub = "./terraform/cloudinit.pub"
priv = "./terraform/cloudinit"
}
}

#variable "ssh_password" {}

variable "user" {
default = "terrauser"
}

Hierin staan een aantal variabelen welke terraform en cloudinit kunnen gebruiken. Een aantal werkte er niet in mijn test, dus heb ik die in de main.tf geplaatst.
Dat bestand gaan we nu aanmaken.

vim main.tf

En daarin zetten we de volgende configuratie

provider "proxmox" {
pm_api_url = "https://pve_host:8006/api2/json"
pm_user = "root@pam"
pm_password = "secretpassword"
pm_tls_insecure = true
}

resource "proxmox_vm_qemu" "prox-vm" {
count = length(var.hostnames)
name = var.hostnames[count.index]
target_node = var.proxmox_host["target_node"]
vmid = var.vmid + count.index
full_clone = true
clone = "cloud-init-focal"

cores = 2
sockets = 1
vcpus = 2
memory = 2048
balloon = 2048
boot = "c"
bootdisk = "virtio0"

scsihw = "virtio-scsi-pci"

onboot = false
agent = 1
cpu = "kvm64"
numa = true
hotplug = "network,disk,cpu,memory"

network {
bridge = "vmbr0"
model = "virtio"
}

ipconfig0 = "ip=${var.ips[count.index]}/24,gw=${cidrhost(format("%s/24", var.ips[count.index]), 1)}"

disk {
#id = 0
type = "virtio"
storage = "local-zfs"
size = "5G"
}

os_type = "cloud-init-ubuntu20"

#creates ssh connection to check when the CT is ready for ansible provisioning
connection {
host = var.ips[count.index]
user = var.user
private_key = file(var.ssh_keys["priv"])
agent = false
timeout = "3m"
}

Dit zijn vooral de instellingen voor het creeeren van de VM’s. Welke proxmox server je moet gebruiken, hoeveel geheugen, disc size, cpu, netwerk config.
Dit staat allemaal in deze file.

Wanneer alles ingesteld is gaan we terraform zijn werk laten doen.

terraform init
terraform plan
terraform apply

(of terraform apply -auto-approve om niet yes in te hoeven typen)

Vervolgens gaat terraform 2 nieuwe VM’s aanmaken, terra-test1 en terra-test2.
Wanneer het allemaal gelukt is kun je connecten via

ssh -i cloudinit terrauser@10.10.10.100 # -i is de variabele voor de key file

Als alles goed is gegaan kunnen we ook de net gecreeerde servers weer verwijderen.
Dit doe je dmv het commando

terraform destroy

Alles is nu weer verwijdert.

Ansible

Om ook Anisble te gebruiken maken we de volgende aanpassingen in main.tf

provisioner "remote-exec" {
# Leave this here so we know when to start with Ansible local-exec
inline = [ "echo 'Cool, we are ready for provisioning'"]
}

provisioner "local-exec" {
working_dir = "../../ansible/"
command = "ansible-playbook -u ${var.user} --key-file ${var.ssh_keys["priv"]} -i ${var.ips[count.index]}, provision.yaml"
}

provisioner "local-exec" {
working_dir = "../../ansible/"
command = "ansible-playbook -u ${var.user} --key-file ${var.ssh_keys["priv"]} -i ${var.ips[count.index]}, install-qemu-guest-agent.yaml"
}
}

Dit ga ik nog nader specificeren

Met dank aan https://vanmieghem.io/