Eintrag

Proxmox VMs per CLI erstellen: Templates, Cloud-Init und Automatisierung

Proxmox VMs per CLI erstellen: Templates, Cloud-Init und Automatisierung

Die Proxmox Web-UI ist komfortabel, aber für wiederholbare Deployments ist die Kommandozeile unschlagbar. Mit qm (QEMU Manager) lassen sich VMs in Sekunden aus Templates erstellen, per Cloud-Init konfigurieren und auf beliebigen Storage deployen.

Proxmox CLI Workflow VM-Erstellung per CLI: Schnell, reproduzierbar und automatisierbar

Warum CLI statt Web-UI?

%%{init: {'theme': 'dark'}}%%
flowchart LR
    subgraph GUI["Web-UI"]
        A1[Klicken] --> A2[Warten]
        A2 --> A3[Klicken]
        A3 --> A4[Eingeben]
        A4 --> A5[Klicken...]
    end

    subgraph CLI["Kommandozeile"]
        B1[Ein Befehl] --> B2[Fertig]
    end

    style GUI fill:#f7768e,stroke:#f7768e
    style CLI fill:#9ece6a,stroke:#9ece6a
Aspekt Web-UI CLI
Geschwindigkeit Viele Klicks Ein Befehl
Reproduzierbarkeit Manuell Skriptbar
Automatisierung Nicht möglich Ideal
Dokumentation Screenshots Code
Fehleranfälligkeit Höher Geringer

Voraussetzungen

Bevor es losgeht, benötigst du:

  • Proxmox VE (getestet mit 8.x)
  • SSH-Zugang zum Proxmox-Node (als root)
  • Ein VM-Template (z.B. Debian 12 mit Cloud-Init)
  • Storage für die neue VM (lokal, NFS, Ceph, etc.)

Tipp: Templates werden in Proxmox durch Rechtsklick → “Convert to Template” erstellt. Die Template-ID sollte leicht erkennbar sein (z.B. 9xxxxx für Templates).


Das qm-Kommando

qm ist das zentrale Tool für VM-Management in Proxmox:

1
2
3
4
5
6
7
8
9
10
11
# Hilfe anzeigen
qm help

# Alle VMs auflisten
qm list

# Status einer VM
qm status <vmid>

# VM-Konfiguration anzeigen
qm config <vmid>

Wichtige qm-Befehle im Überblick

Befehl Beschreibung
qm list Alle VMs auflisten
qm clone VM aus Template klonen
qm set VM-Konfiguration ändern
qm start VM starten
qm stop VM stoppen
qm destroy VM löschen
qm resize Disk vergrößern

VM aus Template erstellen

Grundlegender Clone-Befehl

1
qm clone <template-id> <neue-vmid> --name <vm-name>

Beispiel:

1
qm clone 940002 100 --name webserver-prod

Dies erstellt eine Linked Clone - schnell, aber abhängig vom Template.

Full Clone (unabhängige Kopie)

Für eine vollständig unabhängige VM mit --full:

1
qm clone 940002 100 --name webserver-prod --full
%%{init: {'theme': 'dark'}}%%
flowchart TB
    subgraph linked["Linked Clone"]
        T1[Template Disk] --> L1[Clone 1]
        T1 --> L2[Clone 2]
        T1 --> L3[Clone 3]
    end

    subgraph full["Full Clone"]
        T2[Template] -.->|Kopie| F1[Clone 1]
        T2 -.->|Kopie| F2[Clone 2]
        T2 -.->|Kopie| F3[Clone 3]
    end

    style linked fill:#7aa2f7,stroke:#7aa2f7
    style full fill:#9ece6a,stroke:#9ece6a
Typ Vorteile Nachteile
Linked Clone Schnell, platzsparend Abhängig vom Template
Full Clone Unabhängig, portabel Langsamer, mehr Speicher

Storage auswählen

Standard-Storage verwenden

Ohne Angabe wird der Storage des Templates verwendet:

1
qm clone 940002 100 --name myvm --full

Anderen Storage angeben

Mit --storage auf spezifischen Storage deployen:

1
qm clone 940002 100 --name myvm --full --storage local-lvm

Verfügbare Storages anzeigen:

1
pvesm status

Ausgabe:

1
2
3
4
5
Name             Type     Status  Total       Used  Available      %
local            dir      active  98041       7489      85510   7.64%
local-lvm        lvmthin  active  392908      39290     353617  10.00%
local-ssd        lvmthin  active  476928      95385     381542  20.00%
nas              nfs      active  3806528    286336    3520191   7.53%

Storage-Typen

Typ Beschreibung Empfehlung
local Lokales Verzeichnis Backups, ISOs
local-lvm LVM Thin Pool Standard-VMs
local-ssd LVM auf SSD/NVMe Performance-kritische VMs
nfs / cifs Netzwerk-Share Shared Storage
ceph Distributed Storage HA-Cluster
zfs ZFS Pool Snapshots

Cloud-Init Konfiguration

Cloud-Init ermöglicht die automatische Erstkonfiguration der VM beim Start.

IP-Adresse setzen

1
qm set <vmid> --ipconfig0 ip=<ip>/<cidr>,gw=<gateway>

Beispiel mit statischer IP:

1
qm set 100 --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1

DHCP verwenden:

1
qm set 100 --ipconfig0 ip=dhcp

DNS-Server setzen

1
2
qm set 100 --nameserver "8.8.8.8 8.8.4.4"
qm set 100 --searchdomain "example.com"

SSH-Keys hinzufügen

1
qm set 100 --sshkeys ~/.ssh/id_ed25519.pub

Hinweis: Der SSH-Key muss URL-encoded sein bei Sonderzeichen. Alternativ aus Datei lesen.

User und Passwort

1
2
qm set 100 --ciuser admin
qm set 100 --cipassword "geheimes-passwort"

Sicherheit: Passwörter im Klartext vermeiden! Besser: SSH-Keys verwenden.


Cloud-Init Snippets

Für komplexere Konfigurationen verwendet man Cloud-Init Snippets - YAML-Dateien mit erweiterten Einstellungen.

Snippet-Verzeichnis

Snippets werden auf einem Storage mit Content-Type snippets abgelegt:

1
2
3
4
5
6
7
# Snippet-fähige Storages anzeigen
pvesm status | grep snippets

# Typischer Pfad
ls /var/lib/vz/snippets/
# oder bei NFS
ls /mnt/pve/<storage-name>/snippets/

User-Data Snippet erstellen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#cloud-config
# Datei: /mnt/pve/nas/snippets/debian-config.yml

# Pakete installieren
packages:
  - qemu-guest-agent
  - git
  - curl
  - vim

# Dienste aktivieren
runcmd:
  - systemctl enable qemu-guest-agent
  - systemctl start qemu-guest-agent

# Timezone setzen
timezone: Europe/Berlin

# Locale setzen
locale: de_DE.UTF-8

Snippet der VM zuweisen

1
qm set 100 --cicustom "user=<storage>:snippets/<datei>.yml"

Beispiel:

1
qm set 100 --cicustom "user=nas:snippets/debian-config.yml"

Snippet-Typen

Typ Beschreibung Parameter
user User-Data (Pakete, Befehle) user=storage:snippets/file.yml
network Netzwerk-Konfiguration network=storage:snippets/net.yml
meta Meta-Daten meta=storage:snippets/meta.yml

Mehrere Snippets kombinieren:

1
qm set 100 --cicustom "user=nas:snippets/user.yml,network=nas:snippets/network.yml"

Disk-Größe anpassen

Disk vergrößern

1
qm resize <vmid> <disk> <größe>

Beispiele:

1
2
3
4
5
# Auf 50 GB setzen
qm resize 100 scsi0 50G

# Um 20 GB erweitern
qm resize 100 scsi0 +20G

Wichtig: Die Partition im Gast-System muss ebenfalls angepasst werden (z.B. mit growpart und resize2fs).

Disk-Informationen anzeigen

1
qm config 100 | grep -E "^(scsi|virtio|ide|sata)"

Ausgabe:

1
scsi0: nas:100/vm-100-disk-0.qcow2,size=32G

VM starten und verwalten

VM starten

1
qm start 100

Status prüfen

1
qm status 100

Ausgabe:

1
status: running

Auf Boot warten

Nach dem Start braucht die VM Zeit zum Booten. Ein einfacher Check:

1
2
3
4
5
6
# Warten bis SSH erreichbar
while ! ssh -o ConnectTimeout=2 [email protected] "echo OK" 2>/dev/null; do
    echo "Warte auf VM..."
    sleep 5
done
echo "VM ist bereit!"

VM stoppen

1
2
3
4
5
# Graceful shutdown
qm shutdown 100

# Sofort stoppen (wie Stecker ziehen)
qm stop 100

VM löschen

1
2
3
# VM muss gestoppt sein
qm stop 100
qm destroy 100

Mit Disks löschen:

1
qm destroy 100 --purge

Komplettes Beispiel

Ein vollständiger Workflow für eine neue Webserver-VM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash
# deploy-webserver.sh

# Variablen
TEMPLATE=940002
VMID=100
NAME="webserver-prod"
IP="192.168.1.100"
GW="192.168.1.1"
STORAGE="local-lvm"
DISK_SIZE="50G"
SNIPPET="nas:snippets/debian-config.yml"

# 1. VM aus Template klonen
echo "Erstelle VM $NAME ($VMID)..."
qm clone $TEMPLATE $VMID --name $NAME --full --storage $STORAGE

# 2. Cloud-Init konfigurieren
echo "Konfiguriere Cloud-Init..."
qm set $VMID --ipconfig0 ip=$IP/24,gw=$GW
qm set $VMID --cicustom "user=$SNIPPET"

# 3. Disk vergrößern
echo "Vergrößere Disk auf $DISK_SIZE..."
qm resize $VMID scsi0 $DISK_SIZE

# 4. VM starten
echo "Starte VM..."
qm start $VMID

echo "VM $NAME erfolgreich erstellt!"
echo "IP-Adresse: $IP"
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
    participant Admin
    participant Proxmox
    participant Storage
    participant VM

    Admin->>Proxmox: qm clone (Template → VM)
    Proxmox->>Storage: Disk kopieren
    Storage-->>Proxmox: Disk erstellt

    Admin->>Proxmox: qm set (Cloud-Init)
    Proxmox->>Proxmox: Config speichern

    Admin->>Proxmox: qm resize
    Proxmox->>Storage: Disk vergrößern

    Admin->>Proxmox: qm start
    Proxmox->>VM: Boot
    VM->>VM: Cloud-Init ausführen
    VM-->>Admin: SSH bereit

Hardware anpassen

CPU und RAM

1
2
3
4
5
6
7
8
9
10
11
# CPU-Kerne setzen
qm set 100 --cores 4

# Sockets setzen
qm set 100 --sockets 1

# RAM setzen (in MB)
qm set 100 --memory 4096

# Ballooning aktivieren
qm set 100 --balloon 2048

Netzwerk

1
2
3
4
5
6
7
8
# Netzwerk-Interface hinzufügen
qm set 100 --net0 virtio,bridge=vmbr0

# VLAN setzen
qm set 100 --net0 virtio,bridge=vmbr0,tag=100

# MAC-Adresse festlegen
qm set 100 --net0 virtio,bridge=vmbr0,macaddr=BC:24:11:00:00:01

QEMU Guest Agent

Für bessere Integration mit Proxmox:

1
qm set 100 --agent enabled=1

Tipp: Der Guest Agent muss im Gast-System installiert sein (qemu-guest-agent).


Cluster-Überlegungen

VM auf bestimmtem Node erstellen

Der Clone-Befehl wird auf dem Node ausgeführt, auf dem die VM erstellt wird:

1
2
# Auf Node "gandalf" ausführen
ssh root@gandalf "qm clone 940002 100 --name myvm --full"

VM zwischen Nodes migrieren

1
qm migrate 100 <ziel-node>

Online-Migration (ohne Downtime):

1
qm migrate 100 gandalf --online

Best Practices

Namenskonventionen für VMIDs

Bereich VMIDs Verwendung
100-199 Produktiv-VMs  
200-299 Entwicklung  
900000+ Templates z.B. 940002 = Debian 12

Template-Notes nutzen

Hilfreiche Informationen in den Template-Notes speichern:

1
2
3
4
5
6
7
8
9
10
11
12
qm set 940002 --description "# Debian 12 Template

## Quick Deploy
\`\`\`bash
qm clone 940002 <VMID> --name <NAME> --full
\`\`\`

## Cloud-Init Snippet
\`\`\`bash
qm set <VMID> --cicustom user=nas:snippets/debian-config.yml
\`\`\`
"

Automatisierung mit Ansible

Für komplexere Setups empfiehlt sich Ansible mit dem community.general.proxmox_kvm Modul:

1
2
3
4
5
6
7
8
9
10
11
- name: VM aus Template erstellen
  community.general.proxmox_kvm:
    api_host: proxmox.example.com
    api_user: root@pam
    api_token_id: ansible
    api_token_secret: ""
    clone: debian-12-template
    name: webserver
    newid: 100
    full: true
    storage: local-lvm

Fehlerbehebung

Häufige Fehler

Fehler Ursache Lösung
VM is locked VM wird bearbeitet qm unlock <vmid>
storage not found Falscher Storage-Name pvesm status prüfen
VMID already exists ID vergeben Andere VMID wählen
Cloud-Init not available Kein Cloud-Init-Drive Template prüfen

Logs prüfen

1
2
3
4
5
# Proxmox Task-Log
journalctl -u pvedaemon

# VM-spezifisches Log
cat /var/log/pve/tasks/active

Zusammenfassung

Die wichtigsten Befehle auf einen Blick:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# VM erstellen
qm clone <template> <vmid> --name <name> --full --storage <storage>

# Cloud-Init
qm set <vmid> --ipconfig0 ip=<ip>/<cidr>,gw=<gw>
qm set <vmid> --cicustom "user=<storage>:snippets/<file>.yml"

# Disk vergrößern
qm resize <vmid> scsi0 <size>

# VM starten
qm start <vmid>

# VM löschen
qm stop <vmid> && qm destroy <vmid>

Mit diesen Befehlen lassen sich VMs in Sekunden deployen - reproduzierbar, dokumentiert und automatisierbar. Die Kombination aus Templates und Cloud-Init macht das Setup neuer Systeme zum Kinderspiel.


Dieser Eintrag ist vom Autor unter CC BY 4.0 lizensiert.