KVM Thin Provisioning

Wie kann man den Festplattenspeicherplatz effizient verwalten? Dies beantwortet dieser Artikel.
Dabei ist „Host“ der Rechner, auf dem viele virtuelle Maschinen („Gäste“) laufen. Es wird mehrfach von Nullen die Rede sein, womit binäre Nullen, also Bytes mit dem Wert 0x00 gemeint sind.

Problem: Festplattenplatz

Die Festplatte eines Gastes ist i.d.R. eine Datei. Es wäre große Verschwendung, den verfügbaren Platz eines Hosts komplett auf die Gäste aufzuteilen - z.B. eine 1000GB-Partition auf dem Host mit zehn 100GB-Dateien voll zu packen, damit die Clients notfalls so viel benutzen können, obwohl ihnen typischerweise je 20 GB reichen sollten und man somit meist Platz für bis zu 50 Gäste hätte.

Idee: Thin-Provisioning

Das RAW-Format benötigt1) hier kann natürlich die Festplattenverwaltung des Hosts selbst wieder optimieren… für eine 100GB-Datei auch 100GByte auf der Host-Festplatte. Es empfiehlt sich aber das QCOW2-Format zu verwenden, da dort erst einmal nur der belegte Platz des Gastes benötigt wird - z.B. 20 GByte. Der Gast „sieht“ aber die konfigurierten 100 GByte und kann diese auch verwenden. Dabei wächst die Datei auf dem Host mit - bis zu den 100GByte. Da dieser Extremfall i.d.R. nicht auftritt, kann man mit etwas Reserve den Gästen in Summe sehr viel mehr Plattenplatz versprechen, als insgesamt vorhanden ist.

Problem 1: Wenn zu viele Gäste gleichzeitig ihren Platz in Anspruch nehmen, so ist die Hostplatte voll! Ein Admin-Eingriff ist notwendig. Dieses Problem lösen Statistiker und Leute, welche sich mit Serverüberwachung beschäftigen.

Problem 2: Wenn Gäste abwechseln überdurchschnittlich viel Platz belegen und dann die überzähligen Dateien (z.B. Windowsupgrade) wieder löschen, so bleibt die jeweilige Festplattendatei erst einmal zu groß. Man muss also den nicht mehr genutzten Platz wieder frei geben, damit er einem anderen Gast zur Verfügung steht. Wir müssen dazu die Information über die Freigabe des Platzes im Gast (Dateien werden gelöscht) weitergeben:

Methode 1: Festplatte füllen, dann leeren

Eine oft beschriebene Vorgehensweise basiert auf dem Wissen, dass im Gast gelöschte Dateien zwar nicht mehr im Verzeichnis auftauchen und ihre Datenblöcke irgendwann überschrieben werden, aber vorläufig noch auf der Festplatte vorhanden sind. Überschreibt man den gesamten als frei deklarierten Platz mit Nullen, so sind die Dateien endgültig vernichtet. So geht man dazu vor:

Im Gast die virtuelle Festplatte mit einer zusätzlichen riesigen Datei nur mit Nullen füllen (Festplattendatei wächst bis zur Maximalgröße), diese Datei wieder löschen. Nun ist jeder unbenutzte Platz auch wirklich mit Nullen gefüllt. Gast herunterfahren.

Linux: mit Bordmitteln mit

dd if=/dev/zero of=delme.soon bs=1M; sync; rm delme.soon; sync

Windows: mit SDelete

Am Host bei heruntergefahrenem Gast die Festplattendatei konvertieren, wonach Blöcke von Nullen keinen Platz mehr benötigen

siehe unten

Gast wieder starten

Nachteil: In unserem Beispiel werden sinnlos 80GB Nullen geschrieben, dann die 100GB-Datei eingelesen und als neue 20GB-Datei geschrieben.
Nachteil: Der komplette „versprochene“ Platz wird zumindest kurzfristig benötigt!
Nachteil: Für einige Minuten ist der Gast (ggf. ein wichtiger Server) nicht benutzbar. Dienste sollten heruntergefahren sein um Abstürze zu vermeiden.
Vorteil: keine Unterstützung des Gast-Betriebssystems nötig (man könnte die Nullen auch remote auf die virtuelle Platte schreiben oder die virtuelle Maschine vorübergehend mit einem anderen Betriebssystem booten…)

Methode 2: discard/TRIM

Hintergrund: Betriebssysteme haben für SSDs lernen müssen, dass man den nicht benutzten Platz an den Datenträger meldet, so dass die Speicherstellen freigegeben werden und für das gleichmäßigere Verteilen von Schreibzugriffen genutzt werden können. Der Vorgang wird meist TRIM, Trimmen oder discard genannt.

Diese Fähigkeit des Gast-Betriebssystem nutzt man nun wie folgt:

⇒ Gast löscht eine Datei
(in seiner Festplattenverwaltung wird der Platz, z.B. Block 666777, als frei gekennzeichnet)
⇒ per Trim wird der frei werdende Speicher (z.B. einmal täglich) an die virtuelle Festplatte gemeldet
(die Info, dass 666777 nicht mehr benötigt wird, wird an die virtuelle Festplatte weitergereicht)
⇒ KVM gibt den entsprechenden Speicher in der Festplattendatei auf dem Host frei
(KVM belegt keinen Platz mehr für Block 666777, der in der Datei als Block 4545 gespeichert war)
⇒ Die Festplattendatei hat eine Lücke mehr, und belegt somit auf der Host-Festplatte weniger Platz.
(Das Filesystem des Hosts hat die Information erhalten, dass in der Festplattendatei der Block 4545 mit Nullen belegt ist und braucht dafür so gut wie keinen Platz mehr auf der echten Festplatte.)

Damit dies funktioniert muss der Gast trimmen können und KVM die Freigabe auch verarbeiten:

Gast anpassen

Die virtuelle Festplatte für den Gast muss eine SCSI-Festplatte sein (ggf. nachträglich geändert - Backup gemacht?).
Dafür benötigt man unter Windows die stable Windows-Virtio-Treiber-CD von Fedora (z.B. im Nov. 2019 die Datei virtio-win-0.1.171.iso).

Für eine Linux-Gast kann man meist auch nachträglich von IDE oder virtio auf SCSI wechseln.

Installation eines Win10-Gastes2) erfolgreich getestet mit Win10 1909 auf Debian Buster KVM mit virtio-TreiberCD 1.171 :

Vor der Windowsinstallation die Einstellungen der virtuellen Maschine anpassen: Festplatte als SCSI, dazu den SCSI-Controller virtio-scsi hinzufügen

Zweites CD-Laufwerk anlegen und mit der Treiber-CD-Datei virtio-win-0.1.171.iso verbinden.

Bei der Installation wird keine Festplatte gefunden. Jetzt auf Treiber laden klicken und von der zweiten CD laden lassen.

Installation normal durchlaufen lassen.

Nachträgliches Ändern der Boot-Platte eines Win10-Gastes3) z.B. auf Ubuntu-Xenial KVM mit mehreren Win10 1909 gelungen :

CD-Laufwerk mit der Treiber-CD-Datei verbinden (wie oben).

neue winzige virtuelle Mini-Platte als SCSI hinzufügen, den SCSI-Controller auf virtio-SCSI (nicht hypervisor) stellen, booten

Treiber im Gerätemanager installieren („aktualisieren“, CD auswählen), durchbooten, dann komplett herunterfahren (mit Shift)

Boot-Platte auf SCSI umstellen, Bootreihenfolge prüfen, booten - wenn es funktioniert: miniDisk entfernen

Einige Windowsinstallation wollten erst nach folgender Folklore booten:

Boot-Platte wieder auf IDE, booten (i.d.R. erfolgreich), herunterfahren

Boot-Platte auf SCSI setzen, dann Mini-Platte entfernen, dann Mini-Platte wieder hinzufügen (ändert Reihenfolge)

erfolgreich booten, herunterfahren, Mini-Platte entfernen, fertig (hoffentlich)

KVM ergänzen

In der KVM-Konfigurationsdatei muss ein weiterer Eintrag gemacht werden (während der Gast heruntergefahren ist):

mit virsh edit Gastname die Konfigurationsdatei öffnen, ggf. mit Taste i in den Einfügemodus wechseln

folgende Zeile suchen

<driver name='qemu' type='qcow2'/>

und mit discard='unmap' ergänzen

<driver name='qemu' type='qcow2' discard='unmap'/>

Info: ca. zwei Zeilen darunter steht, dass es ein SCSI-Device ist.

mit ESC : w q speichern und verlassen.

Gast vollenden

Nun den Gast wieder starten.

Gast: Testen ob Trim aufrufbar ist

Linux: fstrim -av

Win10: Laufwerk optimieren (im Explorer durchklicken: Laufwerk→Eingenschaften→Tools→Optimieren)

Host: Prüfen, ob Trim bei der Datei auf dem Host etwas verändert (ls -hls, siehe unten)

Bei Erfolg:

Im Linux-Gast dafür sorgen, dass Trim automatisch regelmäßig durchgeführt wird (via crontab4) Datei in cron.weekly mit fstrim -a oder systemd5) aktivieren von fstrim.timer mit sudo systemctl unmask fstrim.timer && sudo systemctl start fstrim.timer ).

Ein Win10-Gast optimiert automatisch wöchentlich (anscheinend auch nach einer größeren Lösch-Aktion)

Fehlersuche: Wenn die Platte partout nicht zu trimmen ist, so kann die KVM-Konfigurationsdatei recht alt sein:

Plan A: Ändere einzelne Einstellungen (Maschinentyp) und hoffe.

Plan B: Kopiere die Festplatte, lege eine neue Gastmaschine an und verbinde sie mit der kopierten Datei und lass die neue Maschine laufen.

Nachbetrachtung

Man muss natürlich damit rechnen, dass obiges Vorgehen immer auch einen Leistungsverlust bei den Festplattenzugriffen bedeutet. Sparse-Files haben nun einmal den Ruf, dass sie im längeren Gebrauch zu einer Fragmentierung der Host-Festplatte führen. Das stört aber nur Benutzer einer echten Festplatte. Mit SSDs ist das kein praktisches Problem. Außerdem kann man jederzeit die unten beschriebene Konvertierung in eine neue Datei durchführen, wodurch auch eine Fragmentierung behoben werden dürfte.

Handwerkszeug

Test: Dateigrößen

Merke: Das qcow2-Format von KVM erzeugt „sparse“-Dateien. Diese können & werden Lücken haben. Unbenutzter Platz kann logisch als mit Nullen gefüllt angesehen werden. Dies wird dem Host-Betriebssystem (genauer: EXT4-Treiber) mitgeteilt, der das entsprechend vermerkt und dafür keinen Festplattenplatz benötigt. Man kann übrigens auch beliebige Dateien, die Blöcke mit Nullen enthalten, verkleinern, in dem man fallocate -d dateiname aufruft. Wie unterscheidet man nun den angeblichen und den realen Platzbedarf?

ls -hls

Der Befehl liefert sowohl die offizielle Größe, als auch den tatsächlich belegten Platz. Auch du *.qcow2 meldet die tatsächliche Belegung. Die offizielle Größe ist wichtig, falls man ein Backup ohne weitere Vorkehrungen über's Netz schiebt: Diese Größe wird übertragen, auch wenn sehr viele Nullen dabei sind. Gezippt sollte das kaum ein Problem sein, kostet aber Zeit. Rsync kann wie immer auch dieses Problem lösen…

Tipp: Konvertieren der QCOW2-Datei

Enthält eine QCOW2-Datei Leerstellen (echte Nullen oder Lücken via sparse-file), so kann man die Datei verkleinern lassen, in dem man sie in eine neue Datei konvertiert. Dies erledigt bei heruntergefahrenem Gast folgende Befehlsfolge (Backup vorhanden?):

mv gast.qcow2 gast.org
qemu-img convert -O qcow2 gast.org gast.qcow2

Dies kann man natürlich auch zum Zweck eines Backups machen:

qemu-img convert -O qcow2 gast.qcow2 /backup/ziel/pfad/gast.qcow2

Wer wirklich auf den Platzbedarf achtet, kann den zusätzlichen Parameter -c zum Komprimieren mitgeben. Dies dauert auch mit mehreren Prozessorkernen deutlich länger. Belegte Sektoren werden jetzt komprimiert, beim späteren Überschreiben aber wieder unkomprimiert abgelegt. Dies führt z.B. zu folgenden Einsparungen:

bei einem frischen Debian Buster XFCE von 4,2GB auf 1,5GB Platzbedarf.

bei einem frischen Win10 1909 von 15 GByte auf 7 GByte

Bei zukünftigen Schreibzugriffen muss man jedoch mit Tempoeinbußen rechnen. Geht es jedoch mehr um Performance, so kann man beim Konvertieren den parameter „-o preallocation=metadata“ mit angeben. Das kostet wenig echten Plattenplatz, legt aber bereits alle Metadaten der qcow2-Datei an. Zukünftige Schreibzugriffe sollten entsprechend schnell sein. Ein Vergleich findet sich hier.

Deutlich ausführlicher hier nachzulesen mit vielen weiteren englischen Quellen.

Hier eine ausführlichere englische Quelle zum Trimmen in KVM.