Du hast ein Tutorial befolgt. Debian-Cloud-Image gezogen, mit virt-customize den qemu-guest-agent reingebacken, brav --truncate /etc/machine-id aufgerufen, das Image in ein Proxmox-Template konvertiert. Dann drei VMs daraus geklont — und zwei hängen sich am DHCP. Im DHCP-Log: zwei Leases mit derselben Client-ID. Im Gast: identische /etc/machine-id.
Aber du hast doch gerade ein truncate gemacht?
Das Symptom
Cloud-Init-Templates auf Proxmox sind simpel: VM-Image mit cloud-init drin, via qm template in Klon-Modus, pro Deployment qm clone. Funktioniert — bis du mehr als eine VM klonst und Lease-Konflikte siehst:
- Zwei Klone bekommen vom DHCP-Server dieselbe IP.
systemd-networkdschreibt im Journal:DUID generated from machine-id.cat /etc/machine-idliefert auf jedem Klon denselben Hex-String.
Alle Klone haben dieselbe machine-id geerbt. systemd-networkd leitet daraus die DHCP-Client-DUID ab. Aus DHCP-Sicht: alle Klone sind dieselbe Maschine.
Die naheliegende Lösung, die nicht funktioniert
Jedes zweite Tutorial schreibt:
virt-customize -a $IMG --truncate /etc/machine-id
Sieht plausibel aus. Läuft fehlerfrei durch. Datei ist nach dem Befehl leer. Alles gut? Nein. Beim nächsten Boot ist die Datei wieder gefüllt — und beim nächsten virt-customize-Aufruf auf demselben Image ebenfalls.
Warum: das libguestfs-Verhalten
In den Verbose-Logs steht eine unscheinbare Zeile:
[ 1.6] Setting the machine ID in /etc/machine-id
virt-customize schreibt am Anfang jeder Operation einen Zufallswert in /etc/machine-id. Hartcodiert in libguestfs — aus einem Grund, der mit Proxmox nichts zu tun hat: Fedora-Kernel-Postinstall-Scripts erwarten eine gesetzte machine-id, sonst bleibt der Kernel halb installiert. RHEL-Bug #1554546, seit 2018 WONTFIX.
Wer --truncate /etc/machine-id aufruft, gewinnt nichts — virt-customize schreibt sie unmittelbar danach wieder.
Der Fix: virt-sysprep, nicht virt-customize
virt-sysprep ist genau für diesen Zweck gebaut und respektiert das machine-id-Reset. Als letzter Schritt nach allen virt-customize-Aufrufen:
virt-sysprep -a $IMG --operations
machine-id,bash-history,logfiles,tmp-files,net-hostname,net-hwaddr,
ssh-hostkeys,ssh-userdir,dhcp-client-state,package-manager-cache
machine-id— Datei wird geleert, systemd generiert beim Boot neu.ssh-hostkeys— sonst hat jeder Klon dieselbe Server-Identität.net-hwaddr— leert persistente Mappings, damit systemd nicht die alte MAC zuweist.dhcp-client-state— alte Leases raus.
Wichtig: erst virt-customize (Pakete installieren), dann virt-sysprep. Andersrum sinnlos.
Belt-and-suspenders zusätzlich ein Firstboot-Hook, falls jemand später nochmal virt-customize anwirft:
virt-customize -a $IMG --firstboot-command
'rm -f /etc/machine-id /var/lib/dbus/machine-id &&
systemd-machine-id-setup &&
systemctl restart systemd-networkd 2>/dev/null || true'
Bonus-Falle: PVE 9 und das fehlende dhcpcd-base
Auf Proxmox VE 9 schlägt der erste virt-customize-Aufruf mit --install fehl: die libguestfs-Appliance bekommt keinen Netzwerk-Zugriff, apt update scheitert an DNS. Fehlender Dependency-Eintrag im Debian-guestfs-tools-Paket — in PVE 8.x kam der DHCP-Client noch transitiv, in Debian 13 / PVE 9 ist die Kette gebrochen. Upstream als libguestfs/libguestfs#211, Fix in trixie-proposed-updates.
Workaround:
apt install dhcpcd-base
auf dem Proxmox-Host. Danach funktioniert virt-customize --install wieder.
Lessons Learned
Copy-paste-Tutorials sind eine eigene Korrektheitsklasse. Das --truncate /etc/machine-id-Anti-Pattern hat sich über zehn Jahre durch hunderte Blog-Posts vererbt, weil niemand es nachgeprüft hat. Das Kommando wirft keinen Fehler — das Symptom tritt erst auf, wenn man mehr als eine VM klont.
virt-customize und virt-sysprep sind unterschiedliche Tools mit unterschiedlichen Zwecken. virt-customize baut das Image, virt-sysprep macht es klonbar. Wer beide in der richtigen Reihenfolge einsetzt, hat ein deutlich saubereres Setup.
Primärquellen lesen ist nicht optional. RHEL-Bug #1554546, libguestfs Issue #211, der upstream-Commit zur machine-id — alles in zehn Minuten zu finden, während die Frustration mit dem kaputten Template Stunden frisst.