
🌐 Auch auf: English · Français · Español
Im letzten Beitrag habe ich den Plan vorgestellt, mein Homelab zu einem kleinen Rechenzentrum im Enterprise-Stil umzubauen: fünf Säulen, acht Meilensteine, ein Blogbeitrag pro Meilenstein. Meilenstein 1 ist das Fundament, auf dem alles andere steht — drei physische Kisten, die zu einem einzigen Proxmox-VE-Cluster werden, plus das Terraform-Modul, das ab jetzt jede VM darauf provisioniert. Dieser Beitrag behandelt beides. Vorwarnung: Dieses ganze Projekt ist eine einzige Baustelle. Nichts hier ist „fertig“ oder endgültig — bestenfalls Beta, und es ändert sich ständig, während ich weitermache. Sieh diesen Beitrag als Momentaufnahme des Stands zum Zeitpunkt des Schreibens, nicht als abgeschlossenen Aufbau.🎯 Ziel dieses Meilensteins
Zwei Dinge mussten erfüllt sein, bevor ich Active Directory, GitLab oder Kubernetes anfassen konnte:- Drei separate HP-Maschinen mussten zu einem Proxmox-VE-Cluster werden, damit sich VMs zentral über eine Oberfläche verwalten, migrieren und sichern lassen.
- Keine VM sollte je wieder zusammengeklickt werden. Jede VM — vom Domain Controller bis zur Kubernetes-Control-Plane — entsteht per
terraform apply, nicht per Assistent in der Proxmox-Oberfläche.
🖥️ Hardware
Drei HP-Maschinen, bewusst nicht identisch — das ist recycelte Hardware, kein abgestimmtes Set:| Host | RAM | Speicher | Management-IP |
|---|---|---|---|
| HP1 | 64 GB | 512 GB OS-SSD + 2 TB SSD | 192.168.10.x |
| HP2 | 32 GB | 512 GB OS-SSD + 2 TB SSD | 192.168.10.x |
| HP3 | 32 GB | 512 GB OS-SSD + 3×2 TB (ZFS RAIDZ1) | 192.168.10.x |
💽 Proxmox VE installieren
Bei der Installation selbst nichts Besonderes: Proxmox-VE-9.2-ISO, mit Rufus auf einen USB-Stick geschrieben, ein Stick pro Maschine, booten, installieren, dreimal wiederholen. Kein Remote Virtual Media, kein PXE — für drei Kisten auf demselben Schreibtisch ist ein USB-Stick immer noch der schnellste Weg von null zum laufenden Hypervisor. Jeder Node bekam bei der Installation eine statische IP im Management-Netz192.168.10.x/24 (.30, .40, .50 für HP1–HP3), das gleichzeitig das Netz ist, in dem der Cluster und jede VM lebt — mehr zu diesem Kompromiss weiter unten. Ein Schritt nach der Installation auf allen dreien: die Paketquellen umstellen. Proxmox zeigt ab Werk auf das Enterprise-Repository, das ein kostenpflichtiges Abo braucht, um tatsächlich Updates zu ziehen. Nach Proxmox‘ eigener Anleitung habe ich das Enterprise-Repo deaktiviert und jeden Node stattdessen auf das No-Subscription-Repository umgestellt — völlig in Ordnung für Tests und Nicht-Produktivbetrieb, also genau das, was ein Homelab ist, nur ohne die gleiche Validierung wie beim Enterprise-Repo:# /etc/apt/sources.list.d/proxmox.sources
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpgDanach die übliche Runde auf allen drei Nodes, bevor irgendetwas anderes passiert:apt-get update
apt-get upgrade
apt-get dist-upgrade🌐 Netzwerk
Jeder Node hat eine einzige NIC, gebridged alsvmbr0 (Linux-Bridge, STP aus), an die später das network_device jeder VM andockt. Ein zweiter Onboard-NIC-Port ist auf den Boards vorhanden, liegt aber vorerst brach — ein Kandidat für ein eigenes Storage- oder Corosync-Netz, aber nichts, was ein 3-Node-Homelab-Cluster am ersten Tag braucht. Das ist auch die eine bewusste Vereinfachung, die ich erwähnen sollte: Corosync (das Heartbeat-/Quorum-Protokoll des Clusters) läuft über dasselbe Netz wie Management- und VM-Traffic, mit einem einzigen Ring:ring0_addr: HP1 = 192.168.10.x
ring0_addr: HP2 = 192.168.10.x
ring0_addr: HP3 = 192.168.10.xIn einem Produktiv-Cluster würde man Corosync in ein eigenes VLAN oder auf eigene NICs legen, damit ein ausgelastetes Management-Netz keinen grundlosen Quorum-Verlust auslösen kann. Für drei Nodes in einem Heimnetz, in dem kein anderer Traffic um Bandbreite konkurriert, ist das Risiko vertretbar — es steht auf der Liste der Dinge, die ich mir nochmal ansehe, falls das hier je über ein Homelab hinauswächst. Falls du doch mal grundlosen Quorum-Verlust erlebst: RackNotes hat eine gründliche Anleitung zur Stimmen-Mathematik, zu Corosync-Fehlerbildern, QDevice und Wiederherstellungswegen: Proxmox cluster quorum loss.🔗 Den Cluster bilden
Standardablauf mitpvecm: Cluster auf HP1 anlegen, dann HP2 und HP3 beitreten lassen. Mit drei stimmberechtigten Mitgliedern verkraftet der Cluster genau einen ausgefallenen Node (2 von 3 Stimmen), bevor er das Quorum verliert — das minimal sinnvolle HA-Setup und überhaupt erst der Grund für drei statt zwei Nodes. Eine Abfrage des Clusters heute bestätigt, dass der Happy Path gehalten hat:$ pvecm status
Cluster name: homelab
Quorate: Yes
Nodes: 3
Nodeid Ip Name
1 192.168.10.x HP1 (local)
2 192.168.10.x HP2
3 192.168.10.x HP3🗄️ Storage-Aufteilung
Hier hören die drei Nodes auf, identisch zu sein. Die zweite Platte jedes Nodes (bzw. die Platten bei HP3) ist absichtlich unterschiedlich eingerichtet:- HP1 & HP2: Die zusätzliche 2-TB-SSD ist als einfacher Directory-Storage eingebunden (
data/data-hp2) — kein ZFS, kein RAID, nur ein Dateisystem für VM-Disks, ISOs und Backups. Eine einzelne SSD, nichts zum Spiegeln, also gewinnt die einfachste Variante. - HP3: Drei 2-TB-Platten bilden einen ZFS-Pool als RAIDZ1 (
data-hp3), was knapp 4 TB nutzbaren Platz bei Ausfalltoleranz für eine Platte ergibt. Das ist der Node für alles, was ich nicht an eine einzelne tote Platte verlieren will — etwa Longhorn-Replikas oder MinIO-Daten, sobald Kubernetes da ist.
local (Root-Dateisystem) und local-lvm (LVM-thin auf der OS-SSD) aus dem Installer, genutzt für das OS selbst und als Überlauf.🧱 Von ClickOps zu Infrastructure as Code
Mit laufendem Cluster ist der verlockende nächste Schritt, siebenmal auf „Create VM“ in der Proxmox-Oberfläche zu klicken. Genau das habe ich in der vorigen Version dieses Homelabs gemacht, und jede VM war am Ende ein bisschen anders — hier eine vergessene Cloud-init-Einstellung, da eine von Hand getippte statische IP, und sechs Monate später keinerlei Aufzeichnung darüber, was ich eigentlich getan hatte. Diesmal nicht: Jede VM in diesem Umbau ist einmal in Terraform definiert und von einem frischen Cluster aus reproduzierbar.⚙️ Das Terraform-Modul
Das Modul liegt in 01_terraform/ im Projekt-Repo und nutzt den Provider bpg/proxmox. Statt ein Ubuntu-Server-ISO einzuhängen und sich durch den Installer zu klicken, wird jede VM aus einem Ubuntu-26.04-Cloud-Image geklont und komplett über Cloud-init konfiguriert — statische IP, DNS, SSH-Key, alles — es gibt also nirgends in der Pipeline einen interaktiven Installationsschritt:resource "proxmox_download_file" "ubuntu_cloud_image" {
content_type = "iso"
datastore_id = var.image_datastore_id
node_name = var.proxmox_node
url = var.ubuntu_cloud_image_url
file_name = "noble-server-cloudimg-amd64.img"
overwrite = false
}
resource "proxmox_virtual_environment_vm" "vm" {
for_each = local.vms
name = each.key
tags = ["terraform", "rebuild-2026"]
node_name = var.proxmox_node
vm_id = each.value.vmid
disk {
datastore_id = var.vm_datastore_id
file_id = proxmox_download_file.ubuntu_cloud_image.id
interface = "scsi0"
size = each.value.disk_gb
}
initialization {
ip_config {
ipv4 {
address = "${each.value.ip}/${var.network_prefix}"
gateway = var.network_gateway
}
}
user_account {
username = var.vm_username
keys = var.ssh_public_keys
}
}
}Alle sieben VMs — eine pro Rolle für diesen Meilenstein — sind in einer einzigen locals.vms-Map deklariert, sodass eine achte VM später ein Fünf-Zeilen-Diff ist und kein kopierter Resource-Block:| Name | Rolle | IP | RAM | Disk |
|---|---|---|---|---|
| HP1-dc01 | AD / DNS / Root-CA | 192.168.10.x | 4 GB | 60 GB |
| HP1-gitlab01 | GitLab / Container Registry | 192.168.10.x | 8 GB | 120 GB |
| HP1-seed01 | Dev-VM (Ansible, kubectl, Tooling) | 192.168.10.x | 4 GB | 60 GB |
| HP1-vault01 | Secrets-Management (Phase 2) | 192.168.10.x | 2 GB | 40 GB |
| HP1-icinga01 | Monitoring | 192.168.10.x | 4 GB | 60 GB |
| HP1-k8s-cp01 | RKE2-Control-Plane | 192.168.10.x | 8 GB | 80 GB |
| HP1-k8s-cp02 | RKE2-Control-Plane | 192.168.10.x | 8 GB | 80 GB |
100 + <last IP octet> (131–137) — Proxmox verlangt IDs ≥ 100, und so lassen sich ID und Adresse auf einen Blick zuordnen, ohne separate Nachschlagetabelle.▶️ Ausrollen
Der gesamte Rollout sind drei Befehle, sobald ein Proxmox-API-Token und ein SSH-Key bereitliegen:cp terraform.tfvars.example terraform.tfvars
# edit terraform.tfvars: API URL, API token, node name, SSH key
terraform init
terraform plan
terraform applyEin paar Minuten später existieren alle sieben VMs, booten und antworten auf ihren zugewiesenen IPs — und Terraform sagt dir genau, welche welche ist:Outputs:
vm_ids = {
"HP1-dc01" = 131
"HP1-gitlab01" = 132
"HP1-icinga01" = 135
"HP1-k8s-cp01" = 136
"HP1-k8s-cp02" = 137
"HP1-seed01" = 133
"HP1-vault01" = 134
}
vm_ips = {
"HP1-dc01" = "192.168.10.x"
"HP1-gitlab01" = "192.168.10.x"
...
}🧩 Ein paar Dinge, die erwähnenswert sind
- Cloud-Image statt ISO. Das Ubuntu-ISO auf dem lokalen Storage von HP1 nutzt dieses Modul absichtlich nicht — ein Cloud-Image zu klonen und per Cloud-init zu konfigurieren ist schneller und läuft komplett unbeaufsichtigt. Das ISO bleibt nur für die seltene manuelle Installation liegen.
ignore_changesauf derfile_idder Disk. Ohne das will Terraform bei jedem Plan das Basis-Image neu importieren, da die ID der heruntergeladenen Datei nach dem ersten Klonen nicht abgeglichen werden soll.- Secrets verlassen nie das interne Repo.
terraform.tfvarsenthält den echten API-Token und SSH-Key und steht in der gitignore; zusätzlich zur gitignore verhindert ein Pre-Push-Hook aktiv, dass die Datei jemals im öffentlichen GitHub-Mirror dieses Projekts landet. - Der State liegt lokal, und das ist okay. Ein Operator, ein Laptop, der
applyausführt — ein Remote-Backend würde ein Problem lösen, das ich noch gar nicht habe.
⚠️ Dieses gesamte Projekt — inklusive des unten gezeigten Terraform-Codes — ist eine Dauerbaustelle. Es läuft, es tut, was es soll, aber es ist immer noch Beta und wird ständig umgebaut. Betrachte nichts davon als fertig oder stabil.
📊 Der blinde Fleck beim Windows-Ballooning
HP1-dc01 wird von diesem Modul wie jede andere VM provisioniert, bleibt aber nicht lange Ubuntu — direkt danach wird sie auf Windows Server umgestellt, weil Active Directory das nun mal braucht. In dem Moment blieb ihr RAM-Graph in der Proxmox-Übersicht flach bei 100 % der zugewiesenen 4 GB kleben, egal wie untätig die VM tatsächlich war. Die Ursache: Proxmox misst die Speichernutzung des Gasts nicht direkt. Es liest sie über QEMUs virtuelles Balloon-Device aus, das nur dann echte Zahlen meldet, wenn im Gast ein Treiber läuft, der es füttert. Auf den Linux-VMs in diesem Cluster kommt der mit qemu-guest-agent — schon oben beim Guest-Agent-Fix behandelt. Windows Server hat nichts Vergleichbares an Bord, also hat das Balloon-Device ohne Zusatzsoftware nichts zu melden, und Proxmox zeigt die VM einfach dauerhaft bei voller Zuteilung. Die Lösung war ein zweites virtuelles CD-ROM-Laufwerk: das Treiber-ISO virtio-win einhängen und darüber den VirtIO-Balloon-Treiber im Geräte-Manager installieren. Im selben Treiberpaket steckt auch das Windows-Gegenstück zum Guest Agent — sobald das Paket installiert war, zeigte der Graph in der Übersicht den tatsächlichen Speicherdruck statt einer flachen Linie an der Decke. Mehr dazu, wie diese VM zu einem echten Domain Controller wird, im nächsten Beitrag.🔜 Wie es weitergeht
Mit einem 3-Node-Cluster mit Quorum und einem wiederholbaren Weg, VMs hochzuziehen, macht Meilenstein 2 ausHP1-dc01 einen echten Domain Controller: Active Directory, DNS und die Offline-Root-CA, der irgendwann alles andere in diesem Homelab vertrauen wird. Das ist der nächste Beitrag. 




