Einleitung
In diesem Tutorial lernst du, wie du virtuelle Maschinen (VMs) über die Kommandozeile mit virt-install erstellst. Außerdem schauen wir uns an, wie wir Storage Pools mit virsh erstellen können. Anders als GUI-Tools wie virt-manager ermöglicht dir der CLI-Ansatz, VM-Erstellung zu automatisieren und in Infrastructure as Code (IaC) Workflows zu integrieren.
Warum Kommandozeile statt virt-manager?
| virt-manager (GUI) | virt-install (CLI) |
|---|---|
| Klicken, Auswählen | Reproduzierbar via Script |
| Nicht versionierbar | YAML/Shell-Script in Git |
| Nur lokal | Remote via SSH |
| Manuell | Automatisierbar (Ansible, OpenTofu) |
Was erreichen wir?
- ✅ Storage Pools für VM-Disks einrichten
- ✅ ISO-Images herunterladen und verifizieren
- ✅ VM-Erstellung via
virt-install - ✅ VNC-Zugriff für Installation
- ✅ Grundlage für OpenTofu/Terraform Integration
Zielgruppe: Homelab-Betreiber mit KVM-Host-Setup (siehe KVM-Virtualisierung Tutorial)
Voraussetzungen
- KVM-Host mit installiertem libvirt (siehe KVM-Virtualisierung Tutorial)
- Ansible-User mit libvirt-Berechtigungen (siehe KVM-Virtualisierung Tutorial)
- VLAN-Netzwerk konfiguriert (z.B. VLAN 40)
- SSH-Zugriff zum KVM-Host
Prüfen:
# KVM-Host erreichbar?
ssh ansible@192.168.40.100
# libvirtd läuft?
systemctl status libvirtd
# Ansible-User in libvirt-Gruppe?
groups ansible | grep libvirt
# qemu-utils installiert? (WICHTIG für QCOW2-Images)
dpkg -l | grep qemu-utils
# Falls qemu-utils fehlt:
sudo apt update
sudo apt install -y qemu-utilsPhase 1: Storage Pools einrichten
Storage Pools sind libvirt’s Abstraktionsschicht für Storage. Statt Disks direkt in /var/lib/libvirt/images/ zu legen, definierst du Pools für verschiedene Storage-Backends.
Was sind Storage Pools?
┌─────────────────────────────────────┐
│ VM-Disks │
│ ├── vm1.qcow2 │
│ ├── vm2.qcow2 │
│ └── vm3.qcow2 │
└──────────────┬──────────────────────┘
│ libvirt Storage Pool
▼
┌─────────────────────────────────────┐
│ Backend (Directory, LVM, NFS, etc.)│
│ /var/lib/libvirt/images/ │
│ oder: /mnt/storage-pool/ │
└─────────────────────────────────────┘Pool-Typen:
| Typ | Backend | Use Case |
|---|---|---|
dir | Directory | Einfach, lokal (QCOW2, RAW) |
lvm | LVM Volume Group | Performance, thin provisioning |
netfs | NFS/CIFS | Shared Storage (Cluster) |
iscsi | iSCSI | SAN |
zfs | ZFS Dataset | Advanced Features |
Wir nutzen: dir (einfach, flexibel)
Szenario 1: Separate Disk für VMs
Hardware: Zweite Disk /dev/sdb dediziert für VMs.
Schritt 1: Disk vorbereiten
# Auf KVM-Host als root/ansible mit sudo
# WARNUNG: Alle Daten auf /dev/sdb werden gelöscht!
# Disk-Info prüfen
lsblkErwartete Ausgabe:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 120G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 110G 0 part /
└─sda3 8:3 0 10G 0 part [SWAP]
sdb 8:16 0 500G 0 disk <-- Diese DiskSchritt 2: Partition und Dateisystem erstellen
# Partition erstellen (gesamte Disk)
sudo parted /dev/sdb --script mklabel gpt
sudo parted /dev/sdb --script mkpart primary ext4 0% 100%
# Dateisystem erstellen
sudo mkfs.ext4 -L vm-storage /dev/sdb1
# UUID herausfinden
sudo blkid /dev/sdb1Ausgabe:
/dev/sdb1: LABEL="vm-storage" UUID="abc12345-..." TYPE="ext4"Schritt 3: Mountpoint erstellen und einhängen
# Mountpoint erstellen
sudo mkdir -p /mnt/vm-storage
# In /etc/fstab eintragen (persistent)
echo "UUID=abc12345-... /mnt/vm-storage ext4 defaults,noatime 0 2" | \
sudo tee -a /etc/fstab
# fstab über systemd neu einlesen
sudo systemctl daemon-reload
# Mounten
sudo mount -a
# Prüfen
df -h | grep vm-storageAusgabe:
/dev/sdb1 492G 73M 467G 1% /mnt/vm-storageSchritt 4: Berechtigungen setzen
# libvirt-qemu User/Group benötigt Zugriff
sudo chown -R libvirt-qemu:kvm /mnt/vm-storage
sudo chmod 770 /mnt/vm-storageSchritt 5: Storage Pool in libvirt definieren
# Pool-Definition erstellen
sudo virsh pool-define-as \
vm-storage \
dir \
--target /mnt/vm-storage
# Pool starten
sudo virsh pool-start vm-storage
# Autostart aktivieren
sudo virsh pool-autostart vm-storage
# Status prüfen
sudo virsh pool-list --allAusgabe:
Name State Autostart
---------------------------------
default active yes
vm-storage active yesDetails anzeigen:
sudo virsh pool-info vm-storageAusgabe:
Name: vm-storage
UUID: ...
State: running
Persistent: yes
Autostart: yes
Capacity: 492.00 GiB
Allocation: 73.00 MiB
Available: 491.93 GiBSzenario 2: Selbe Disk wie Host-System
Hardware: Nur eine Disk /dev/sda, VMs sollen auf separater Partition/Directory liegen.
Option A: Separate Partition (empfohlen bei Neuinstallation)
Während Host-Installation separate Partition für VMs erstellen:
/dev/sda1 512 MB /boot/efi
/dev/sda2 100 GB /
/dev/sda3 10 GB swap
/dev/sda4 500 GB /var/lib/libvirt/storage <-- VM-StorageNach Installation:
# Mountpoint sollte bereits existieren
df -h | grep libvirt
# Falls nicht, siehe Szenario 1 (Partition erstellen)Option B: Directory im Root-Filesystem (einfachste Lösung)
Vorteil: Keine Repartitionierung nötig Nachteil: VMs teilen sich I/O mit Host-OS
# Storage-Directory erstellen
sudo mkdir -p /var/lib/libvirt/storage
# Berechtigungen
sudo chown -R libvirt-qemu:kvm /var/lib/libvirt/storage
sudo chmod 770 /var/lib/libvirt/storagePool definieren:
sudo virsh pool-define-as \
vm-storage \
dir \
--target /var/lib/libvirt/storage
sudo virsh pool-start vm-storage
sudo virsh pool-autostart vm-storageStorage Pool für ISOs
Separate Pool für ISO-Images (saubere Trennung).
# ISO-Directory erstellen
sudo mkdir -p /var/lib/libvirt/isos
sudo chown -R libvirt-qemu:kvm /var/lib/libvirt/isos
# Pool definieren
sudo virsh pool-define-as \
iso-storage \
dir \
--target /var/lib/libvirt/isos
sudo virsh pool-start iso-storage
sudo virsh pool-autostart iso-storage
# Prüfen
sudo virsh pool-listAusgabe:
Name State Autostart
---------------------------------
default active yes
iso-storage active yes
vm-storage active yesPhase 2: Debian 13 ISO herunterladen
Schritt 1: Download-Verzeichnis vorbereiten
# In ISO-Pool wechseln
cd /var/lib/libvirt/isos
# Als ansible-User (mit sudo falls nötig)
# Falls keine Schreibrechte:
sudo chown ansible:libvirt /var/lib/libvirt/isosSchritt 2: Debian 13 netinst ISO herunterladen
Offizielle Quelle: https://cdimage.debian.org/debian-cd/
# Debian 13.5.0 amd64 netinst
wget https://cdimage.debian.org/debian-cd/13.5.0/amd64/iso-cd/debian-13.5.0-amd64-netinst.iso
# Checksummen herunterladen
wget https://cdimage.debian.org/debian-cd/13.5.0/amd64/iso-cd/SHA512SUMS
wget https://cdimage.debian.org/debian-cd/13.5.0/amd64/iso-cd/SHA512SUMS.signDownload-Größe: ~400 MB
Schritt 3: ISO-Integrität verifizieren
Wichtig: Immer Checksummen prüfen!
# SHA512-Checksumme prüfen
sha512sum -c SHA512SUMS 2>&1 | grep netinstErwartete Ausgabe:
debian-13.5.0-amd64-netinst.iso: OKFalls FAILED: ISO ist korrupt, erneut herunterladen!
Schritt 4: GPG-Signatur verifizieren (optional, empfohlen)
# Debian Signing Keys importieren (einmalig)
gpg --keyserver keyring.debian.org --recv-keys 0x6294BE9B
gpg --keyserver keyring.debian.org --recv-keys 0x42028EA404AAD9AA
# Signatur prüfen
gpg --verify SHA512SUMS.sign SHA512SUMSErwartete Ausgabe:
gpg: Good signature from "Debian CD signing key <debian-cd@lists.debian.org>"Warnung über Trust: Normal, solange “Good signature” erscheint ✅
Schritt 5: Dateiberechtigungen korrigieren
# ISO für libvirt lesbar machen
sudo chown libvirt-qemu:kvm debian-13.5.0-amd64-netinst.iso
sudo chmod 644 debian-13.5.0-amd64-netinst.isoPhase 3: VM mit virt-install erstellen
Schritt 1: Netzwerk vorbereiten
Voraussetzung: VLAN-Netzwerk in libvirt definiert (siehe OPNsense Tutorial).
Prüfen:
sudo virsh net-list --allErwartete Ausgabe:
Name State Autostart Persistent
------------------------------------------------
default active yes yes
vlan40-infra active yes yesFalls vlan40-infra fehlt: Siehe KVM-Virtualisierung Tutorial → Netzwerk-Sektion.
Schritt 2: VM-Parameter definieren
Best Practice: Parameter in Variablen für Reproduzierbarkeit.
# VM-Konfiguration
VM_NAME="test-vm-01"
VM_RAM=4096 # 4 GB RAM
VM_VCPUS=2 # 2 vCPUs
VM_DISK_SIZE=40 # 40 GB Disk
VM_NETWORK="vlan40-infra"
VM_OS_VARIANT="debian12" # Debian 13 nutzt debian12 Template
ISO_PATH="/var/lib/libvirt/isos/debian-13.5.0-amd64-netinst.iso"OS-Varianten anzeigen:
osinfo-query os | grep -i debianAusgabe (Auszug):
debian10 | Debian 10
debian11 | Debian 11
debian12 | Debian 12Hinweis: Debian 13 (Trixie) nutzt debian12 Template bis offizielles Template verfügbar.
Schritt 3: VM erstellen via virt-install
sudo virt-install \
--name="${VM_NAME}" \
--ram="${VM_RAM}" \
--vcpus="${VM_VCPUS}" \
--disk pool=vm-storage,size="${VM_DISK_SIZE}",format=qcow2,bus=virtio \
--cdrom="${ISO_PATH}" \
--os-variant="${VM_OS_VARIANT}" \
--network network="${VM_NETWORK}",model=virtio \
--graphics vnc,listen=0.0.0.0 \
--console pty,target_type=serial \
--boot uefi \
--noautoconsoleParameter-Erklärung:
| Parameter | Wert | Erklärung |
|---|---|---|
--name | test-vm-01 | VM-Name (eindeutig) |
--ram | 4096 | RAM in MB (4 GB) |
--vcpus | 2 | Anzahl virtueller CPUs |
--disk pool= | .qcow2 | Pfad zur virtuellen Festplatte im Pool |
--disk size= | 40 | Disk-Größe in GB |
--disk format= | qcow2 | Format: QCOW2 (Copy-on-Write, sparse) |
--disk bus= | virtio | Paravirtualisierter Controller (beste Performance) |
--cdrom | .iso | ISO-Datei für Installation |
--os-variant | debian12 | OS-Typ für Optimierungen |
--network network= | vlan40-infra | Libvirt-Netzwerk-Name |
--network model= | virtio | Paravirtualisierte NIC (beste Performance) |
--graphics | vnc,listen=0.0.0.0 | VNC-Server auf allen Interfaces |
--console | pty | Serielle Konsole (virsh console) |
--boot | uefi | Moderner UEFI-Boot (statt Legacy BIOS) |
--noautoconsole | - | Konsole nicht automatisch öffnen |
Wichtige Hinweise:
bus=virtio: Paravirtualisierte Disk = deutlich bessere Performance als IDE/SATA format=qcow2: Sparse-File, wächst dynamisch (40 GB Limit, aber initial nur ~1 GB belegt) listen=0.0.0.0: VNC von überall erreichbar (Firewall beachten!)
Ausgabe:
Starting install...
Domain is still running. Installation may be in progress.
You can reconnect to the console to complete the installation process.Schritt 4: VM-Status prüfen
# Alle VMs anzeigen
sudo virsh list --allAusgabe:
Id Name State
----------------------------
1 test-vm-01 runningWeitere Infos:
# VM-Details
sudo virsh dominfo test-vm-01
# VM-Disk-Info
sudo virsh domblklist test-vm-01
# VM-Netzwerk-Info
sudo virsh domiflist test-vm-01Phase 4: VNC-Zugriff zur Installation
VNC-Port herausfinden
sudo virsh vncdisplay test-vm-01Ausgabe:
127.0.0.1:0Bedeutung:
127.0.0.1= Nur lokal (wegen unsererlisten=0.0.0.0sollte aber0.0.0.0stehen):0= Display 0 → Port5900 + 0 = 5900
Korrektur (falls 127.0.0.1):
# VM XML bearbeiten
sudo virsh edit test-vm-01Suche nach <graphics type='vnc' und ändere:
<graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>Speichern: :wq
VM neu starten:
sudo virsh destroy test-vm-01
sudo virsh start test-vm-01Variante 1: VNC direkt (nicht empfohlen für Production)
VNC-Viewer installieren (falls nicht vorhanden):
# Auf Client
sudo apt install tigervnc-viewerVerbinden:
vncviewer 192.168.40.100:5900Sicherheitshinweis: VNC ist unverschlüsselt! Nur in trusted Networks nutzen.
Variante 2: SSH-Tunnel (empfohlen)
Sicherer Zugriff via SSH-Port-Forwarding:
# Auf Client
ssh -L 5900:localhost:5900 ansible@192.168.40.100In neuem Terminal:
vncviewer localhost:5900Vorteil: Traffic durch SSH-Tunnel verschlüsselt ✅
Variante 3: virt-manager Remote
GUI-Alternative:
# Auf Client
virt-manager -c 'qemu+ssh://ansible@192.168.40.100/system'In virt-manager:
- Doppelklick auf
test-vm-01 - Konsolen-Fenster öffnet sich
- Debian Installer startet
Phase 5: Debian Installation (Detaillierte Schritte)
Installer starten
- Install-Methode wählen:
Graphical Install
Installation durchführen
- Language:
- English
- Location:
- other → Europe → Germany
- Locales:
- en_US.UTF-8
- Keyboard:
- German
- DHCP-Fehler:
- Mit
Continuebestätigen
- Mit
- Configure network manually
- IP address:
192.168.40.120 - Netmask:
255.255.255.0 - Gateway:
192.168.40.1 - Name server:
192.168.40.1
- IP address:
- Hostname:
test-vm-01
- Domain name:
home.arpa
- Root password / Re-enter password to verify:
- Starkes Passwort (mind. 16 Zeichen)
- Full name for new user:
- (leer lassen)
- Username for your account:
ansible
- Choose a password for the new user / Re-enter password to verify:
- Starkes Passwort (mind. 16 Zeichen)
- Wichtig:
- User
ansiblewird für spätere Automation benötigt!
- User
- Partition disks:
- Guided - use entire disk → Virtual disk 1 → All files in one partition → Finish partitioning and write changes to disk
- Write changes to disk?
- Yes
- Scan for extra installation media?
- No
- Package Manager:
- Germany → deb.debian.org
- HTTP proxy:
- (leer lassen)
- Participate in the package usage survey?
- No
- Software selection:
- Alles abwählen, dann nur auswählen:
- SSH server
- standard system utilities
- Alles abwählen, dann nur auswählen:
- Continue
- to reboot
Nach dem Reboot
Die VM ist nun unter 192.168.40.120 per SSH erreichbar.
Autostart aktivieren
Damit die VM auch wieder hochfährt, wenn das Host-System mal crasht, aktivieren wir an der VM noch den Autostart.
sudo virsh autostart test-vm-01Phase 6: Post-Installation
Schritt 1: SSH-Zugriff testen
In Phase 5 wurde die statische IP 192.168.40.120 direkt im Debian-Installer gesetzt. Die VM hat also keine DHCP-Adresse, sondern ist direkt unter dieser IP erreichbar.
SSH-Login:
ssh ansible@192.168.40.120Falls die IP aus irgendeinem Grund unbekannt ist (z. B. beim Testen mit DHCP statt statischer IP), kannst du sie über die VNC-Konsole oder ARP ermitteln:
# Via VNC-Konsole in VM
ip addr show
# Oder via ARP vom Host
arp -a | grep -i "00:16:3e" # libvirt MAC-PräfixSchritt 2: Statische IP konfigurieren
In VM:
sudo nano /etc/network/interfacesInhalt:
auto lo
iface lo inet loopback
auto enp1s0
iface enp1s0 inet static
address 192.168.40.120/24
gateway 192.168.40.1
dns-nameservers 192.168.40.1
dns-search home.arpaWichtig: Interface-Name prüfen mit ip addr show.
# Netzwerk neu starten
sudo systemctl restart networking
# Testen
ping -c 3 192.168.40.1Schritt 3: System aktualisieren
sudo apt update
sudo apt upgrade -y
sudo apt dist-upgrade -ySchritt 4: VM herunterfahren
Via SSH:
sudo shutdown -h nowOder via virsh:
sudo virsh shutdown test-vm-01
# Force (falls hängt)
sudo virsh destroy test-vm-01Phase 7: VM-Management-Basics
VM starten/stoppen
# Starten
sudo virsh start test-vm-01
# Herunterfahren (sauber)
sudo virsh shutdown test-vm-01
# Ausschalten (unsauber, force)
sudo virsh destroy test-vm-01
# Neustart
sudo virsh reboot test-vm-01VM-Autostart
# Autostart aktivieren (VM startet bei Host-Boot)
sudo virsh autostart test-vm-01
# Autostart deaktivieren
sudo virsh autostart --disable test-vm-01
# Status prüfen
sudo virsh dominfo test-vm-01 | grep AutostartVM-Info anzeigen
# Alle VMs
sudo virsh list --all
# VM-Details
sudo virsh dominfo test-vm-01
# Ressourcen-Nutzung
sudo virsh domstats test-vm-01
# Disk-Info
sudo virsh domblklist test-vm-01
# Netzwerk-Info
sudo virsh domiflist test-vm-01VM löschen
# VM stoppen
sudo virsh destroy test-vm-01
# VM aus libvirt entfernen
sudo virsh undefine test-vm-01
# Disk manuell löschen
sudo rm /var/lib/libvirt/storage/test-vm-01.qcow2Achtung: undefine löscht nur die VM-Definition, nicht die Disk!
Phase 8: VM-Snapshots
Snapshots speichern den VM-Zustand zu einem bestimmten Zeitpunkt.
Snapshot erstellen
# VM sollte laufen
sudo virsh snapshot-create-as test-vm-01 \
--name "fresh-install" \
--description "Direkt nach Debian-Installation"Snapshots anzeigen
sudo virsh snapshot-list test-vm-01Ausgabe:
Name Creation Time State
----------------------------------------------------
fresh-install 2026-01-31 14:23:45 +0100 shutoffSnapshot wiederherstellen
# VM stoppen
sudo virsh shutdown test-vm-01
# Auf Snapshot zurücksetzen
sudo virsh snapshot-revert test-vm-01 fresh-install
# VM starten
sudo virsh start test-vm-01Snapshot löschen
sudo virsh snapshot-delete test-vm-01 fresh-installHinweis: Snapshots belegen zusätzlichen Speicherplatz!
Phase 9: VM-Templates erstellen
Idee: Basis-VM als Template für schnelle Deployments.
Schritt 1: Basis-VM vorbereiten
- Frische Debian-Installation
- System aktualisieren
- Wichtige Pakete installieren (vim, htop, etc.)
- SSH-Key hinterlegen
- WICHTIG: Hostname & statische IP nicht setzen (wird pro VM individuell)
Schritt 2: VM generalisieren
In VM:
# Machine-ID löschen (wird bei Boot neu generiert)
sudo rm /etc/machine-id
sudo touch /etc/machine-id
# SSH Host Keys löschen (werden bei Boot neu generiert)
sudo rm /etc/ssh/ssh_host_*
# Cloud-init (optional, für Automation)
sudo apt install cloud-initVM herunterfahren:
sudo shutdown -h nowSchritt 3: Template speichern
# Disk als Template kopieren
sudo cp /var/lib/libvirt/storage/test-vm-01.qcow2 \
/var/lib/libvirt/storage/debian13-template.qcow2
# Schreibschutz (verhindert versehentliche Änderung)
sudo chmod 444 /var/lib/libvirt/storage/debian13-template.qcow2Schritt 4: Neue VM aus Template
# Template kopieren
sudo cp /var/lib/libvirt/storage/debian13-template.qcow2 \
/var/lib/libvirt/storage/neue-vm.qcow2
# Schreibrechte wiederherstellen
sudo chmod 644 /var/lib/libvirt/storage/neue-vm.qcow2
# VM-Definition erstellen
sudo virt-install \
--name="neue-vm" \
--ram=4096 \
--vcpus=2 \
--disk path=/var/lib/libvirt/storage/neue-vm.qcow2,format=qcow2,bus=virtio \
--import \
--os-variant=debian12 \
--network network=vlan40-infra,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--noautoconsoleParameter --import: Nutzt existierende Disk statt ISO!
Phase 10: Automation mit Scripten
Beispiel: VM-Creation Script
nano create-vm.shInhalt:
#!/bin/bash
set -e
# Parameter
VM_NAME="$1"
VM_RAM="${2:-4096}"
VM_VCPUS="${3:-2}"
VM_DISK_SIZE="${4:-40}"
# Validierung
if [ -z "$VM_NAME" ]; then
echo "Usage: $0 <vm-name> [ram_mb] [vcpus] [disk_gb]"
exit 1
fi
# Pfade
ISO_PATH="/var/lib/libvirt/isos/debian-13.5.0-amd64-netinst.iso"
DISK_PATH="/var/lib/libvirt/storage/${VM_NAME}.qcow2"
# VM erstellen
echo "Creating VM: $VM_NAME"
echo " RAM: ${VM_RAM} MB"
echo " vCPUs: $VM_VCPUS"
echo " Disk: ${VM_DISK_SIZE} GB"
sudo virt-install \
--name="${VM_NAME}" \
--ram="${VM_RAM}" \
--vcpus="${VM_VCPUS}" \
--disk path="${DISK_PATH}",size="${VM_DISK_SIZE}",format=qcow2,bus=virtio \
--cdrom="${ISO_PATH}" \
--os-variant=debian12 \
--network network=vlan40-infra,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--console pty,target_type=serial \
--boot uefi \
--noautoconsole
echo "VM created successfully!"
echo "Connect via: vncviewer $(hostname -I | awk '{print $1}'):5900"Ausführbar machen:
chmod +x create-vm.shNutzung:
# Standard (4 GB RAM, 2 vCPU, 40 GB Disk)
./create-vm.sh my-new-vm
# Custom
./create-vm.sh my-big-vm 8192 4 100Vorbereitung für OpenTofu/Terraform
Terraform Provider: dmacvicar/libvirt
Später (OpenTofu-Tutorial, im Backlog): VMs deklarativ via HCL definieren.
Beispiel (Vorschau):
resource "libvirt_volume" "vm_disk" {
name = "my-vm.qcow2"
pool = "vm-storage"
format = "qcow2"
size = 42949672960 # 40 GB
}
resource "libvirt_domain" "vm" {
name = "my-vm"
memory = "4096"
vcpu = 2
disk {
volume_id = libvirt_volume.vm_disk.id
}
network_interface {
network_name = "vlan40-infra"
}
}In Forgejo CI/CD: OpenTofu applied automatisch bei Git-Push — Details folgen in einem eigenen Tutorial.
Zusammenfassung
Wir haben gelernt:
✅ Storage Pools einrichten (separate Disk oder Directory)
✅ ISO-Download und Integritätsprüfung
✅ VM-Erstellung via virt-install
✅ VNC-Zugriff für Installation
✅ VM-Management (start, stop, autostart)
✅ Snapshots für Backups
✅ Templates für schnelle Deployments
✅ Automation via Shell-Scripts
Workflow:
1. Storage Pool erstellen
2. ISO herunterladen & verifizieren
3. virt-install ausführen
4. Via VNC installieren
5. Post-Installation (SSH, Updates)
6. (Optional) Template erstellenNächste Schritte
Serienreihenfolge:
- ✅ Was ist ein Homelab? (Serie Teil 0)
- ✅ OPNsense: Eigene Firewall fürs Homelab mit VLANs (Teil 1)
- ✅ KVM-Virtualisierung auf Debian 13 einrichten (Teil 2)
- ✅ VMs & Storage Pools mit libvirt und virt-install ← Du bist hier
- Weiterer KVM-Node + Cluster (in Vorbereitung)
Wichtige Befehle (Cheat Sheet)
Storage Pools
# Pools anzeigen
sudo virsh pool-list --all
# Pool-Info
sudo virsh pool-info <pool-name>
# Pool starten
sudo virsh pool-start <pool-name>
# Pool stoppen
sudo virsh pool-destroy <pool-name>
# Pool löschen
sudo virsh pool-delete <pool-name>
sudo virsh pool-undefine <pool-name>VM-Management
# VMs anzeigen
sudo virsh list --all
# VM starten
sudo virsh start <vm-name>
# VM stoppen (sauber)
sudo virsh shutdown <vm-name>
# VM stoppen (force)
sudo virsh destroy <vm-name>
# VM löschen
sudo virsh undefine <vm-name>
sudo rm /path/to/disk.qcow2
# VM-Info
sudo virsh dominfo <vm-name>
# Autostart
sudo virsh autostart <vm-name>
sudo virsh autostart --disable <vm-name>Snapshots
# Snapshot erstellen
sudo virsh snapshot-create-as <vm> --name <snapshot-name>
# Snapshots anzeigen
sudo virsh snapshot-list <vm>
# Snapshot wiederherstellen
sudo virsh snapshot-revert <vm> <snapshot-name>
# Snapshot löschen
sudo virsh snapshot-delete <vm> <snapshot-name>VNC
# VNC-Port anzeigen
sudo virsh vncdisplay <vm-name>
# VNC-Client verbinden
vncviewer <host-ip>:5900
# Via SSH-Tunnel
ssh -L 5900:localhost:5900 user@host
vncviewer localhost:5900Fehlerbehebung
Problem: virt-install schlägt fehl mit “Permission denied”
Symptom:
ERROR internal error: process exited while connecting to monitorLösung:
# Disk-Pfad Berechtigungen prüfen
ls -la /var/lib/libvirt/storage/
# Besitzer korrigieren
sudo chown libvirt-qemu:kvm /var/lib/libvirt/storage/*.qcow2
# SELinux/AppArmor (falls aktiviert)
sudo aa-complain /usr/sbin/libvirtdProblem: VM bekommt keine IP via DHCP
Lösungen:
# 1. Netzwerk in libvirt aktiv?
sudo virsh net-list --all
sudo virsh net-start vlan40-infra
# 2. OPNsense DHCP für VLAN 40 aktiv?
# In OPNsense GUI prüfen
# 3. MAC-Adresse in DHCP-Range?
sudo virsh domiflist <vm-name>
# MAC notieren, in OPNsense Firewall-Logs prüfenProblem: VNC-Verbindung verweigert
Lösungen:
# 1. VNC läuft?
sudo virsh vncdisplay <vm-name>
# 2. Firewall (auf KVM-Host)?
sudo ufw allow 5900/tcp
# 3. VNC auf 0.0.0.0?
sudo virsh edit <vm-name>
# <listen type='address' address='0.0.0.0'/> prüfenProblem: Disk voll trotz QCOW2
QCOW2 wächst dynamisch, aber:
# Tatsächliche Größe
ls -lh /var/lib/libvirt/storage/vm.qcow2
# Virtuelle Größe
qemu-img info /var/lib/libvirt/storage/vm.qcow2
# Compact (Leerraum zurückgewinnen)
sudo qemu-img convert -O qcow2 vm.qcow2 vm-compact.qcow2
sudo mv vm-compact.qcow2 vm.qcow2Weiterführende Ressourcen
Offizielle Dokumentation
- libvirt: https://libvirt.org/
- virt-install: https://linux.die.net/man/1/virt-install
- virsh: https://libvirt.org/manpages/virsh.html
Storage
- Storage Pools: https://libvirt.org/storage.html
- QCOW2 Format: https://qemu.readthedocs.io/en/latest/system/images.html
Automation
- Terraform libvirt Provider: https://github.com/dmacvicar/terraform-provider-libvirt
- Ansible virt Module: https://docs.ansible.com/ansible/latest/collections/community/libvirt/
Weiterführend
- Was ist ein Homelab? (Serie Teil 0)
- OPNsense: Eigene Firewall fürs Homelab mit VLANs (Serie Teil 1)
- KVM-Virtualisierung auf Debian 13 einrichten (Serie Teil 2)
Changelog
- 2026-06-24 — Phase 6 konsolidiert: “IP via DHCP”-Hinweis entfernt, da Phase 5 eine statische IP setzt; DHCP-Fallback als optionale Anmerkung behalten; “GitLab Tutorial”-Verweis auf “OpenTofu-Tutorial (Backlog)” geändert; Forgejo statt GitLab CI/CD; K3s-Schritte aus “Nächste Schritte” entfernt und durch aktuelle Serienreihenfolge mit internen Links ersetzt; Weiterführend + Changelog ergänzt.
- 2026-01-25 — Erstveröffentlichung (Entwurf).