Cloud-Init ist der De-facto-Standard für die automatische Konfiguration von virtuellen Maschinen in Cloud-Umgebungen. In diesem Artikel zeige ich dir, wie du ein Cloud-Init Template in Proxmox erstellst und automatisch VMs damit bereitstellen kannst.
Was ist Cloud-Init?
Cloud-Init ist ein Werkzeug, das beim ersten Start einer virtuellen Maschine ausgeführt wird, um das System automatisch zu konfigurieren. Dazu gehören:
- Einrichten von Benutzerkonten und SSH-Keys
- Netzwerk-Konfiguration
- Konfiguration von Paketquellen
- System-Anpassungen
Voraussetzungen
Bevor wir beginnen, stelle sicher, dass folgende Pakete installiert sind:
1
| apt install libguestfs-tools wget
|
Schritt-für-Schritt Anleitung
1. Image herunterladen
Zuerst laden wir das Cloud-Image herunter:
1
2
3
| mkdir -p /opt/cloud_init
cd /opt/cloud_init
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2
|
2. qemu-guest-agent installieren
Der qemu-guest-agent ermöglicht die Kommunikation zwischen Proxmox und der VM:
1
| virt-customize -a debian-13-generic-amd64.qcow2 --install qemu-guest-agent
|
3. Root-Passwort setzen
1
| virt-customize -a debian-13-generic-amd64.qcow2 --root-password password:dein-passwort
|
4. /etc/machine-id leeren
Dies ist wichtig für Cloud-Init:
1
| virt-customize -a debian-13-generic-amd64.qcow2 --run-command "echo -n > /etc/machine-id"
|
5. SSH-Keys hinzufügen
1
2
3
4
5
6
7
8
| virt-customize -a debian-13-generic-amd64.qcow2 \
--run-command "mkdir -p /root/.ssh && chmod 700 /root/.ssh" \
--run-command "cat >> /root/.ssh/authorized_keys << 'SSHEOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx user@host-1
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy user@host-2
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz user@host-3
SSHEOF" \
--run-command "chmod 600 /root/.ssh/authorized_keys"
|
6. SSH Root-Login aktivieren (optional)
1
2
| virt-customize -a debian-13-generic-amd64.qcow2 \
--run-command "sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config"
|
7. VM erstellen
Jetzt erstellen wir die VM in Proxmox:
1
2
3
4
5
| qm create 9999 \
--name debian-13 \
--memory 2048 \
--cores 4 \
--net0 virtio,bridge=vmbr1
|
8. Disk importieren
1
| qm importdisk 9999 debian-13-generic-amd64.qcow2 local-zfs
|
9. VM konfigurieren
1
2
3
4
5
6
7
8
9
10
11
12
13
| qm set 9999 --scsihw virtio-scsi-single --scsi0 "local-zfs:vm-9999-disk-0,cache=writeback,discard=on,ssd=1"
qm set 9999 --boot c --bootdisk scsi0
qm set 9999 --scsi2 local-zfs:cloudinit
qm set 9999 --agent enabled=1
qm set 9999 --serial0 socket
qm set 9999 --vga serial0
qm set 9999 --cpu cputype=host
qm set 9999 --ostype l26
qm set 9999 --balloon 2048
qm set 9999 --ciupgrade 1
qm set 9999 --ipconfig0 ip=dhcp
qm set 9999 --nameserver 192.168.1.1
qm set 9999 --searchdomain localdomain
|
Erklärung der qm set Befehle
| Befehl | Beschreibung |
|---|
--scsihw virtio-scsi-single | SCSI-Controller konfigurieren |
--boot c --bootdisk scsi0 | Boot-Reihenfolge festlegen |
--scsi2 ...:cloudinit | Cloud-Init Disk hinzufügen |
--agent enabled=1 | qemu-guest-agent aktivieren |
--serial0 socket | Serielle Konsole |
--vga serial0 | VGA-Ausgabe auf serial0 |
--cpu cputype=host | CPU-Typ |
--ostype l26 | Linux 2.6+ Kernel |
--balloon | Memory-Ballooning |
--ciupgrade 1 | Cloud-Init Upgrade |
--ipconfig0 ip=dhcp | DHCP für Netzwerk |
--nameserver | DNS-Server |
--searchdomain | Search-Domain |
10. Als Template markieren
Zum Schluss markieren wir die VM als Template:
Cloud-Init Konfiguration anpassen
Um eine VM aus dem Template zu starten, kannst du die Cloud-Init Konfiguration anpassen:
1
2
| qm set 9999 --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1
qm set 9999 --nameserver 8.8.8.8
|
Statische IP-Adresse
Mit Cloud-Init kannst du auch statische IP-Adressen konfigurieren:
1
| qm set 9999 --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1
|
Cloud-Init Konfigurationsdateien
Cloud-Init verwendet zwei Hauptkonfigurationsdateien, die auf einem separaten Datenträger (CIDATA) gespeichert werden:
user-data
Die user-data Datei enthält die Benutzerkonfiguration. Erstelle eine ISO-Datei mit beiden Dateien:
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
33
34
35
36
| mkdir -p /tmp/cloud-init-iso
cd /tmp/cloud-init-iso
# user-data erstellen
cat > user-data << 'EOF'
#cloud-config
users:
- name: admin
sudo: ALL=(ALL) NOPASSWD:ALL
groups: sudo
shell: /bin/bash
ssh-authorized-keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx user@host-1
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy user@host-2
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz user@host-3
package_update: true
packages:
- vim
- curl
- wget
- git
runcmd:
- systemctl enable sshd
- timedatectl set-timezone Europe/Berlin
EOF
# meta-data erstellen
cat > meta-data << 'EOF'
instance-id: debian-13-vm
local-hostname: debian-13-vm
EOF
# ISO erstellen
genisoimage -output cloud-init.iso -volid cidata -rock -joliet meta-data user-data
|
Cloud-Init Module erklärt
Cloud-Init unterstützt viele Module. Die wichtigsten sind:
| Modul | Beschreibung |
|---|
users | Benutzerkonten erstellen |
packages | Pakete installieren |
package_update | Paketliste aktualisieren |
package_upgrade | Pakete aktualisieren |
runcmd | Befehle beim ersten Start ausführen |
write_files | Dateien schreiben |
timezone | Zeitzone setzen |
locale | Locale setzen |
ssh_authorized_keys | SSH-Keys für Benutzer |
ssh_pwauth | SSH-Passwort-Authentifizierung |
Benutzer mit sudo-Rechten erstellen
Standardmäßig kann derDefault-Benutzer (admin) bereits sudo verwenden. Für zusätzliche Benutzer:
1
2
3
4
5
6
7
8
9
10
11
| users:
- name: admin
sudo: ALL=(ALL) NOPASSWD:ALL
groups: sudo,adm
shell: /bin/bash
ssh-authorized-keys:
- ssh-ed25519 AAAAC3N...
- name:onitoring
sudo: ALL=(ALL) NOPASSWD:ALL
groups: sudo
shell: /bin/bash
|
Pakete installieren
Um Pakete beim ersten Start zu installieren:
1
2
3
4
5
6
7
| packages:
- vim
- curl
- wget
- git
- htop
- net-tools
|
Paketquellen (Repositories) konfigurieren
Um eigene Paketquellen hinzuzufügen:
1
2
3
4
5
| write_files:
- path: /etc/apt/sources.list.d/custom.list
content: |
deb https://repo.example.com/debian stable main
permissions: "0644"
|
Oder für einen lokalen Mirror:
1
2
3
4
5
6
| write_files:
- path: /etc/apt/sources.list
content: |
deb http://192.168.1.10/debian bookworm main contrib
deb http://192.168.1.10/debian bookworm-updates main contrib
permissions: "0644"
|
Cloud-Init ISO in Proxmox einhängen
Nachdem du die ISO erstellt hast, kannst du sie als Cloud-Init Datenträger verwenden:
1
2
3
4
5
| # ISO auf den Proxmox-Server kopieren
scp cloud-init.iso root@proxmox:/tmp/
# ISO als Cloud-Init Datenträger konfigurieren
qm set 9999 --ide2 local:iso/cloud-init.iso,media=cdrom
|
Automatische Konfiguration beim Klonen
Wenn du eine VM von einem Template klonst, kannst du die Cloud-Init Konfiguration direkt anpassen:
1
2
3
4
5
6
7
8
9
10
| # VM klonen
qm clone 9999 100 --name debian-13-neu
# Cloud-Init Konfiguration setzen
qm set 100 --ipconfig0 ip=192.168.1.200/24,gw=192.168.1.1
qm set 100 --nameserver 192.168.1.1
qm set 100 --searchdomain localdomain
# SSH-Keys für neuen Benutzer
qm set 100 --sshkeys "ssh-ed25519 AAAAC3N..."
|
Netzwerk-Konfiguration
Für komplexere Netzwerk-Konfigurationen kannst du network-config verwenden:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| cat > network-config << 'EOF'
version: 2
ethernets:
ens18:
addresses:
- 192.168.1.100/24
gateway4: 192.168.1.1
nameservers:
addresses:
- 192.168.1.1
- 8.8.8.8
search:
- localdomain
EOF
|
Fazit
Mit Cloud-Init kannst du VMs in Proxmox schnell und automatisiert bereitstellen. Das Template muss nur einmal erstellt werden, und anschließend kannst du beliebig viele VMs davon klonen und mit individueller Konfiguration starten.
Die wichtigsten Vorteile sind:
- Automatisierung der VM-Bereitstellung
- Zentrale Konfiguration über Cloud-Init
- Wiederverwendbare Templates
- Flexible Netzwerk-Konfiguration
Komplettes Script
Hier ist das vollständige Script zur automatischen Erstellung eines Cloud-Init Templates:
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
| #!/bin/bash
WORK_DIR="/opt/cloud_init"
IMAGE_URL="https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2"
IMAGE_NAME="debian-13-generic-amd64.qcow2"
VM_ID="9999"
VM_NAME="debian-13"
VM_MEMORY="2048"
VM_CORES="4"
VM_BRIDGE="vmbr1"
STORAGE_LOCAL="local-zfs"
ROOT_PASSWORD="xxx"
NAMESERVER="192.168.1.1"
SEARCHDOMAIN="localdomain"
ENABLE_ROOT_SSH="true"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
error() {
echo "[ERROR] $1" >&2
exit 1
}
log "Starte Cloud-Init Template Erstellung..."
mkdir -p "$WORK_DIR" || error "Konnte Verzeichnis nicht erstellen"
cd "$WORK_DIR" || error "Konnte Verzeichnis nicht wechseln"
if [ ! -f "$IMAGE_NAME" ]; then
log "Lade Cloud-Image herunter: $IMAGE_URL"
wget "$IMAGE_URL" || error "Download fehlgeschlagen"
else
log "Image existiert bereits: $IMAGE_NAME"
fi
log "Installiere qemu-guest-agent..."
virt-customize -a "$IMAGE_NAME" --install qemu-guest-agent || error "qemu-guest-agent Installation fehlgeschlagen"
log "Setze root-Passwort..."
virt-customize -a "$IMAGE_NAME" --root-password password:"$ROOT_PASSWORD" || error "Passwort-Setzung fehlgeschlagen"
log "Leere /etc/machine-id..."
virt-customize -a "$IMAGE_NAME" --run-command "echo -n > /etc/machine-id" || error "machine-id Leerung fehlgeschlagen"
log "Füge SSH-Keys zu root hinzu..."
virt-customize -a "$IMAGE_NAME" \
--run-command "mkdir -p /root/.ssh && chmod 700 /root/.ssh" \
--run-command "cat >> /root/.ssh/authorized_keys << 'SSHEOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx user@host-1
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy user@host-2
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAAAzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz user@host-3
SSHEOF" \
--run-command "chmod 600 /root/.ssh/authorized_keys" || error "SSH-Keys hinzufügen fehlgeschlagen"
if [ "$ENABLE_ROOT_SSH" = "true" ]; then
log "Aktiviere SSH Root-Login..."
virt-customize -a "$IMAGE_NAME" \
--run-command "sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config" || error "SSH-Konfiguration fehlgeschlagen"
fi
log "Erstelle VM mit ID $VM_ID..."
qm create "$VM_ID" \
--name "$VM_NAME" \
--memory "$VM_MEMORY" \
--cores "$VM_CORES" \
--net0 virtio,bridge="$VM_BRIDGE" || error "VM-Erstellung fehlgeschlagen"
log "Importiere Disk..."
qm importdisk "$VM_ID" "$IMAGE_NAME" "$STORAGE_LOCAL" || error "Disk-Import fehlgeschlagen"
log "Konfiguriere VM..."
qm set "$VM_ID" --scsihw virtio-scsi-single --scsi0 "$STORAGE_LOCAL:vm-$VM_ID-disk-0,cache=writeback,discard=on,ssd=1"
qm set "$VM_ID" --boot c --bootdisk scsi0
qm set "$VM_ID" --scsi2 "$STORAGE_LOCAL:cloudinit"
qm set "$VM_ID" --agent enabled=1
qm set "$VM_ID" --serial0 socket
qm set "$VM_ID" --vga serial0
qm set "$VM_ID" --cpu cputype=host
qm set "$VM_ID" --ostype l26
qm set "$VM_ID" --balloon "$VM_MEMORY"
qm set "$VM_ID" --ciupgrade 1
qm set "$VM_ID" --ipconfig0 ip=dhcp
qm set "$VM_ID" --nameserver "$NAMESERVER"
qm set "$VM_ID" --searchdomain "$SEARCHDOMAIN"
log "Markiere VM als Template..."
qm template "$VM_ID" || error "Template-Markierung fehlgeschlagen"
log "✓ Cloud-Init Template erfolgreich erstellt!"
log "Template ID: $VM_ID"
log "Template Name: $VM_NAME"
|