TL;DR – Mit Packer gebaute VM-Templates ("Golden Images") für Ubuntu 26.04 & Debian 13 auf Proxmox und VMware vSphere – ohne Cloud-Init. Vollautomatische Installation (autoinstall/preseed), Gast-Tools (
qemu-guest-agent/open-vm-tools) und root-SSH-Key sind fertig eingebacken. Ergebnis: klonen → starten → per DHCP aufeth0direkt alsrootper SSH erreichbar; Hostname/IP danach nach Bedarf (z. B. Ansible)../install-packer.sh # Packer installieren cp credentials.pkrvars.hcl.example credentials.pkrvars.hcl # Zugang eintragen ./build.sh validate # Konfig prüfen ./build.sh ubuntu-26.04 # Template bauen (Default: Proxmox)
Baut generalisierte VM-Templates ("Golden Images") für Ubuntu 26.04 LTS
und Debian 13 (Trixie) auf Proxmox VE und VMware vSphere – im Stil von
chef/bento, aber nativ mit den proxmox-iso- und
vsphere-iso-Buildern von HashiCorp Packer.
Provisionierung, autoinstall/preseed und Skripte sind plattformübergreifend geteilt.
Ohne Cloud-Init. Ergebnis pro Betriebssystem: ein fertig konfiguriertes
Template mit qemu-guest-agent, festen Einstellungen (Zeitzone, Locale,
Tastatur), Interface-Name eth0 (DHCP) und hinterlegtem root-SSH-Key. Zum
Ausrollen wird es geklont, gestartet und direkt per SSH-Key als root erreicht;
Hostname/IP werden anschließend nach Bedarf (z. B. per Ansible) gesetzt.
┌────────────────────┐ API ┌──────────────────────┐
│ Build-Host │ ───────────────────▶ │ Proxmox VE │
│ (This host) │ proxmox-iso │ │
│ + Packer │ │ 1. lädt ISO selbst │
│ + HTTP-Server ◀───┼── autoinstall/preseed│ 2. VM aus ISO │
└────────────────────┘ (http/ wird vom │ 3. Provisionierung │
Gast geladen) │ 4. → Template │
└──────────────────────┘
- Proxmox lädt das Installations-ISO selbst herunter (
iso_download_pve). - Die Installation läuft vollautomatisch via autoinstall (Ubuntu) bzw. preseed (Debian); die Antwortdateien werden vom kurzlebigen HTTP-Server des Build-Hosts ausgeliefert.
- Firmware: UEFI (Proxmox: OVMF +
virtio-scsi-single; vSphere:efi+pvscsi/vmxnet3). - Gast-Tools je Plattform: qemu-guest-agent (Proxmox) bzw. open-vm-tools (vSphere).
| Was | Wozu |
|---|---|
| Debian/Ubuntu Linux oder MacOS | Betriebssystem für den Build-Host |
| Packer ≥ 1.11 | wird per install-packer.sh installiert |
git, curl |
Repo & Hilfsskripte |
| Netzwerk | muss Proxmox auf Port 8006 erreichen und vom VM-Netz aus erreichbar sein (für den HTTP-Server) |
Wichtig: Build-Host und die zu bauende VM müssen sich gegenseitig im Netz erreichen. Am einfachsten ist es, wenn der Build-Host im selben L2-Segment wie die gewählte Proxmox-Bridge liegt.
| Was | Details |
|---|---|
| Proxmox VE | 8.x oder 9.x |
| API-Token | für einen User mit den nötigen Rechten (siehe unten) |
Storage für images |
z. B. local-lvm, ein ZFS-Pool, Ceph … (VM-Disk + EFI) |
Storage für iso |
Datastore mit „ISO image"-Content (z. B. local) |
| Bridge mit DHCP | das VM-Netz braucht während der Installation DHCP |
Pre-flight Proxmox: Der Build-Host muss vom VM-Netz aus erreichbar sein (HTTP-Server für autoinstall/preseed). Bei einer einzelnen NIC wählt Packer die IP automatisch; bei mehreren NICs die richtige IP per
http_ipincredentials.pkrvars.hclsetzen (bindet den HTTP-Server an diese IP).
| Was | Details |
|---|---|
| vCenter | Zugang (User/Passwort) mit Rechten zum Erstellen/Templatisieren von VMs |
| Datastore | für VM-Disk und ISO-Upload (genug Platz) |
| Portgroup | Netzwerk mit DHCP, das den Build-Host erreichen kann |
| Ordner | optionaler VM-/Template-Folder |
Pre-flight vSphere: Datastore ~5 GB frei (ISO-Upload). Die Portgroup muss DHCP haben und den Build-Host (HTTP) erreichen — bei mehreren NICs
http_ipsetzen. Der vCenter-User braucht u. a. Datastore (AllocateSpace/Browse/ FileManagement), Network.Assign, Resource.AssignVMToPool, VirtualMachine.Config.* (inkl. AdvancedConfig fürdisk.EnableUUID), VirtualMachine.Interact, VirtualMachine.Inventory, VirtualMachine.Provisioning (MarkAsTemplate) und VirtualMachine.GuestOperations. Open-VM-Tools werden bereits bei der Installation mitinstalliert, damit Packer die Gast-IP findet.
vm-factory/
├── plugins.pkr.hcl # benötigte Packer-Plugins (Proxmox, vSphere)
├── variables.pkr.hcl # alle Variablen-Definitionen
├── source.pkr.hcl # proxmox-iso Source
├── source-vsphere.pkr.hcl # vsphere-iso Source
├── build.pkr.hcl # Build-Block (beide Sources) + Provisionierung
├── credentials.pkrvars.hcl.example # Proxmox-Zugang/Storage/Netz
├── credentials-vsphere.pkrvars.hcl.example # vCenter-Zugang/Platzierung
├── files/authorized_keys # root-SSH-Keys (Team-Set)
├── os_pkrvars/
│ ├── ubuntu/ubuntu-26.04-x86_64.pkrvars.hcl
│ └── debian/debian-13-x86_64.pkrvars.hcl
├── http/
│ ├── ubuntu/{user-data,meta-data} # autoinstall
│ └── debian/preseed.cfg # preseed
├── scripts/
│ ├── 00-update.sh # Update, qemu-guest-agent, Auto-Updates aus
│ ├── 20-customize.sh # Locale/Tastatur/Zeit/eth0/SSH, Cloud-Init weg, Auto-Resize
│ ├── 30-minimize.sh # moderate Minimierung (snapd, alte Kernel, docs)
│ └── 99-cleanup.sh # Generalisieren
├── install-packer.sh # Packer auf dem Build-Host installieren
└── build.sh # Wrapper: validate / build
git clone git@github.com:styliteag/vm-factory.git
cd vm-factory# Linux
sudo ./install-packer.sh # offizielles HashiCorp-APT-Repo
packer version
# MacOS
brew tap hashicorp/tap
brew install hashicorp/tap/packerAuf dem Proxmox-Host (einmalig). Beispiel mit dediziertem User + Rolle:
pveum role add Packer -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.AllocateTemplate Datastore.Audit \
Sys.Audit Sys.Console Sys.Modify SDN.Use"
pveum user add packer@pve
pveum aclmod / -user packer@pve -role Packer
pveum user token add packer@pve packer --privsep 0 # Token erbt User-Rechte
# Oder einfach einen API-Token anlegen und alle Rechte vergeben in der Proxmox-UI.Das ausgegebene Token-Secret notieren (wird nur einmal angezeigt).
VM.Monitorist wichtig – ohne diese Berechtigung kann Packer dieboot_command-Tasten nicht an die VM senden.
cp credentials.pkrvars.hcl.example credentials.pkrvars.hcl
$EDITOR credentials.pkrvars.hclWerte: API-URL, Node, Token-ID + Secret, Storage-Pools, Bridge. Diese Datei ist
per .gitignore vom Versionsmanagement ausgenommen.
Aufruf: ./build.sh [proxmox|vsphere] {ubuntu-26.04|debian-13|all|validate}
(Plattform optional, Default proxmox).
# Proxmox (Default)
./build.sh validate # Konfiguration prüfen (kein Build)
./build.sh ubuntu-26.04 # nur Ubuntu
./build.sh all # beide nacheinander
# VMware vSphere (Zugang in credentials-vsphere.pkrvars.hcl)
./build.sh vsphere validate
./build.sh vsphere debian-13
./build.sh vsphere all
# zusätzliche Packer-Argumente werden durchgereicht:
./build.sh ubuntu-26.04 -on-error=askIntern wird per -only die passende Source gewählt und -force ersetzt ein
bestehendes Template gleichen Namens. Beim ersten Build lohnt der Blick auf
die VM-Konsole (Proxmox noVNC bzw. vSphere Web-Konsole), um die
boot_command-Eingabe zu beobachten.
Auf dem Proxmox-Host, z. B. mit dem Template ubuntu-26-04-x86-64:
qm clone <TEMPLATE_VMID> 9001 --name web01 --full
qm set 9001 --memory 4096 --cores 4
qm start 9001
# Der Klon holt sich per DHCP eine IP auf eth0; danach direkt als root:
ssh root@<IP-des-Klons>Hostname und ggf. statische IP werden anschließend gesetzt (manuell oder per
Ansible). Im Klon liegt /root/SETUP.md mit fertigen Rezepten (Hostname, feste
IP für netplan/ifupdown, zweite Platte); die MOTD verweist beim Login darauf.
Auskommentierte Kurzvorlagen stehen zusätzlich direkt in 00-eth0.yaml /
/etc/network/interfaces und /etc/fstab.
Platte vergrößern: qm disk resize 9001 scsi0 40G und neu starten. Die
Root-Partition wächst beim Boot automatisch auf die volle Plattengröße
(growroot.service, einmaliger systemd-Oneshot aus scripts/20-customize.sh).
Funktioniert für Ubuntu (Plain-Partition) und Debian (LVM) — kein manuelles
growpart/resize2fs mehr nötig.
| Was | Wo |
|---|---|
| URL, Node, Token, Storage, Bridge, VLAN | credentials.pkrvars.hcl |
| CPU/RAM/Disk-Größe | credentials.pkrvars.hcl bzw. variables.pkr.hcl |
| ISO-Version/Checksumme | os_pkrvars/<os>/…pkrvars.hcl |
| Installations-Antworten | http/ubuntu/user-data, http/debian/preseed.cfg |
| Software im Template | scripts/00-update.sh |
| Zeitzone/Locale/Tastatur/Interface/SSH | scripts/20-customize.sh + Variablen unten |
| root-SSH-Keys (Team-Set) | files/authorized_keys (Override: ssh_authorized_keys) |
| Weiteres OS | siehe CONTRIBUTING.md |
| Variable | Default | Bedeutung |
|---|---|---|
vm_timezone |
Europe/Berlin |
Zeitzone |
vm_locale |
C.UTF-8 |
System-Locale (für reines ASCII: C) |
vm_keymap |
de |
Konsolen-Tastatur |
ssh_authorized_keys |
(leer) | Override für root-Keys; Standard: files/authorized_keys |
root_password |
(leer) | root-Passwort (nur Konsole/Notfall; SSH key-only) |
Ist
ssh_authorized_keysleer, bleibt der Passwort-Login aktiv (sonst wäre der Klon ohne hinterlegten Schlüssel nicht erreichbar).
| Komponente | Version |
|---|---|
| Packer | 1.15.4 |
| Proxmox-Plugin | 1.2.3 (boot_iso-Block) |
| Ubuntu | 26.04 LTS (Resolute Raccoon) |
| Debian | 13.5.0 (Trixie) |
boot_commandgreift nicht / Installer startet nicht automatisch: GRUB war noch nicht bereit oder das Menü-Layout weicht ab.boot_waiterhöhen (z. B.10s) und die noVNC-Konsole beobachten; bei Ubuntu ggf. die Anzahl<down>anpassen.- 403 / Permission denied beim Senden der Tasten: dem Token fehlt
VM.Monitor(siehe Schritt 3). - Packer findet die VM-IP nicht (SSH-Timeout):
qemu-guest-agentmuss im Gast laufen – er wird inuser-data/preseed.cfginstalliert und aktiviert. iso_download_pve-Fehler: Prüfsumme muss konkret sein (sha256:<hex>), deriso_storage_poolmuss „ISO image"-Content erlauben.format-Fehler auf Verzeichnis-Storage: imdisks-Blockformat = "qcow2"ergänzen (Block-/ZFS-Storage braucht das nicht).- Klon hat kein Netz: das Image nutzt DHCP auf
eth0. Gibt es im Zielnetz kein DHCP, inscripts/20-customize.sheine statische Konfiguration hinterlegen. - VM bleibt nach Fehlversuch liegen:
qm destroy <VMID>auf dem Node, dann erneut bauen. Mit-on-error=asklässt sich der Fehlerzustand untersuchen.
MIT · © 2026 Stylite AG