Cloud-init ist der Standarddienst zur Erstkonfiguration von virtuellen Maschinen und Cloud-Instanzen unter Linux. Er läuft beim ersten Start, liest eine Konfiguration aus der Umgebung (Metadatendienst der Cloud, ISO, Datei oder Netzwerk) und richtet das System entsprechend ein – Benutzer, SSH-Schlüssel, Netzwerk, Pakete. Ohne Cloud-init müsste jede Instanz nach dem Start manuell nachkonfiguriert werden.

Datenquellen

Cloud-init sucht nach Datenquellen. In der Cloud stellt der Anbieter einen Metadatendienst unter 169.254.169.254 bereit; die gängigen Anbieter haben eigene Quellen (AWS, Azure, GCP, OpenStack). Für Umgebungen ohne Metadatendienst – etwa Proxmox VE, Testumgebungen, lokale Virtualisierung – gibt es NoCloud: Die Konfiguration wird über ein Datenträger-Image mit dem Label cidata oder über einen HTTP-Server geliefert, wahlweise auch auf der Kernel-Kommandozeile.

Die drei Dateien

Im NoCloud-Fall sind es drei Dateien:

  • user-data: die eigentliche Konfiguration – Benutzer, Pakete, Befehle, Dateien. Format ist meist #cloud-config, eine YAML-Struktur; auch ein Shell-Skript per #!/bin/bash wird akzeptiert.
  • meta-data: Identität der Instanz – instance-id und local-hostname. Die instance-id ist entscheidend: Ändert sie sich, läuft die Konfiguration erneut.
  • network-config: Netzwerkkonfiguration im Format von Netplan (Version 2). Ohne diese Datei versucht die Instanz DHCP.
#cloud-config
hostname: app01
users:
  - name: admin
    groups: [sudo]
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3Nza… admin@bastion

package_update: true
packages:
  - nginx
  - unattended-upgrades

write_files:
  - path: /etc/nginx/conf.d/app.conf
    content: |
      server {
        listen 80;
        root /var/www/html;
      }

runcmd:
  - systemctl enable --now nginx
  - ufw allow 22/tcp

Phasen und Zustand

Der Ablauf ist in Phasen aufgeteilt: init-local (noch vor dem Netzwerk), init (Netzwerk und Datenquelle), config (Module ausführen), final (Abschluss und Neustart, falls nötig). Je nach Anweisung erfolgt ein Neustart – das ist normal und erklärt, warum eine frisch gestartete Instanz manchmal kurzzeitig nicht erreichbar ist.

Wichtige Zustandsdateien:

  • /var/lib/cloud/ enthält den Zustand; Löschen des Verzeichnisses führt dazu, dass die Konfiguration erneut ausgeführt wird.
  • cloud-init status zeigt, ob alles durchgelaufen ist; cloud-init status --long nennt Details.
  • /var/log/cloud-init.log und /var/log/cloud-init-output.log sind die ersten Anlaufpunkte bei Fehlern.

Bewährte Praxis

  1. Fehler sichtbar machen: runcmd bricht bei einem Fehler nicht sofort ab, und die Ausgabe landet im Log. Wer wissen will, ob alles geklappt hat, prüft den Status – nicht die Erreichbarkeit des Ports.
  2. Nicht zu viel hineinpacken. Cloud-init eignet sich für Benutzer, Schlüssel, Netzwerk und Grundpakete. Umfangreiche Konfiguration gehört in ein Ansible-Playbook oder in ein gebautes Image (Packer).
  3. Geheimnisse nicht im user-data: Die Daten sind für jeden mit Zugriff auf die Metadaten oder den Datenträger lesbar. Passwörter und Tokens gehören in eine Secret-Verwaltung.
  4. Idempotenz beachten: Ein Modul, das mehrfach läuft, darf keinen Schaden anrichten. runcmd ist nicht idempotent – deshalb sollte es nur ergänzende Schritte enthalten.

Verwandte Grundlagen: Virtualisierung, Unveränderliche Infrastruktur, Proxmox VE, Terraform.