Wie ich ein QCOW2-Image auf ein Drittel geschrumpft habe

Ich verwende auf meinem Root-Server KVM zur Virtualisierung. In einer der virtuellen Maschinen läuft meine Website https://kofler.info. Die virtuelle Festplatte dieser VM befindet sich in einer QCOW2-Image-Datei. Diese ist im Laufe der Jahre auf rund 30 GiB angewachsen (bzw. rund 32 GB bei dezimaler Rechnung). Tatsächlich beträgt die Virtual Size aber nur 24 GB (dezimal), und davon sind innerhalb der Maschine wiederum nur zwei Drittel genutzt. Da müsste es doch möglich sein, die QCOW2-Datei auzuräumen, oder?

Update 14.12.2019: Script, um nicht-allozierten Speicher aus QCOW2-Images zu entfernen.

Image-Datei aufräumen (von »außen«)

Die folgenden Kommandos wurden am Host ausgeführt, vorerst mit einer Backup-Datei des Images, um den laufenden Betrieb nicht zu stören:

qemu-img info ausgangspunkt.qcow2 
  image: ausgangspunkt.qcow2
  file format: qcow2
  virtual size: 24G (25769803776 bytes)
  disk size: 32G
  cluster_size: 65536
  Format specific information:
      compat: 0.10
      refcount bits: 16

Die Image-Datei ist also ca. 32 GiB groß, obwohl die Nutzdaten maximal ca. 24 GiB betragen. Wie kann das sein? Der Overhead resultiert einerseits aus (vielfach nicht mehr benötigten Meta-)Daten der QCOW2-Datei, andererseits aus nicht mehr vorhandenen Snapshots, die im Laufe der Zeit erzeugt und wieder entfernt wurden. Mit qemu-img convert können diese nicht mehr benötigten Ramsch-Daten entfernt werden. (Das Image darf dabei nicht in Betrieb sein!!)

qemu-img convert ausgangspunkt.qcow2  -O qcow2 aufgeraeumt.qcow2

Optional können Sie bei qemu-img convert die Option -c verwenden. Dann werden die Datenblöcke der Image-Datei zlib-komprimiert. Das dauert ziemlich lange (mehrere Minuten).

qemu-img convert ausgangspunkt.qcow2  -O qcow2 -c komprimiert.qcow2

Das Ergebnis (in binären MiB):

du -m *.qcow2
  30003  ausgangspunkt.qcow2
  23215  aufgeraeumt.qcow2  
  13722  komprimiert.qcow2

Das ist ja schon eine ordentliche Verbesserung!

Dateisystem aufräumen (von »innen«)

Ein Blick in die virtuelle Maschine hinein zeigt, dass von den 24 GiB Image-Größe 23 für das Root-Dateisystem vorgesehen sind, das verbleibende GiB für die Swap-Partition. Das Root-Dateisystem nutzt aber nur ca. zwei Drittel des Speicherplatzes:

df -h
  /dev/vda1        23G     15G  7,4G   66% /

Das Problem ist, dass auch die ungenützten Speicherblöcke des Dateisystems alte, nicht mehr benötigte Daten enthalten. Nur wenn die ungenützten Speicherblöcke mit Nullen vollgeschrieben werden, kann das QCOW2-Image diese nun wirklich leeren Speicherblöcke aus dem Image entfernen. Der einfachste Weg, das zu bewerkstelligen, bietet das dd-Kommando. Damit können Sie eine riesige Datei aus Nullen erzeugen. Danach synchronisieren Sie das Dateisystem und löschen die Datei wieder. Laut df hat sich durch die Aktion nichts geändert.

dd if=/dev/zero of=zero bs=1M count=6500
sync
rm zero
df -h 
  /dev/vda1        23G     15G  7,4G   66% /

Tipp: Vermeiden Sie es, mit dd das gesamte Dateisystem vollzuschreiben! Das führt zu einer starken Fragmentierung, die nicht wünschenswert ist.

Image-Datei nochmals aufräumen (von »außen«)

Nach diesen Vorarbeiten ist es an der Zeit, die VM für ein paar Minuten hinunterzufahren. Mit qemu-img convert kann nun eine neue, minimierte Image-Datei erzeugt werden:

mv kofler.info.qcow2 backup.qcow2
qemu-img convert backup.qcow2  -O qcow2 kofler.info.qcow2
du -m kofler.info.qcow2
  9796   kofler.info.qcow2

Damit ist die Image-Datei auf ein Drittel ihrer ursprünglichen Größe geschrumpft. Die VM kann nun wieder gestartet werden.

Nebenwirkungen

Die hier beschriebene Vorgehensweise hat zwei Nachteile:

  • Erstens ist die Ersparnis in diesem Umfang nicht von Dauer. Innerhalb der virtuellen Maschine werden neue ungenützte Speicherblöcke entstehen, selbst dann, wenn der Speicherbedarf des Dateisystems als Ganzes nicht steigt. Und auch im QCOW2-Image wird sich im Laufe der Zeit neuer ungenützter Speicher anhäufen. Und schließlich werden neue/geänderte Datenblöcke im QCOW2-Image nicht komprimiert (das wäre wohl zu langsam). Die zlib-Kompression gilt also nur für Daten, die sich nicht ändern. Damit die Ersparnis von Dauer ist, muss die hier skizzierte Aktion irgendwann (vielleicht in ein, zwei Jahren) wiederholt werden.

  • Zweitens hat die Komprimierung des Image (Option -c bei qemu-img convert) natürlich eine relativ hohe Auswirkung auf die Geschwindigkeit. Datenblöcke müssen beim Lesen dekomprimiert werden. Der Effekt ist bei schnellen Datenträgern (SSDs) deutlich stärker bemerkbar als bei langsamen Datenträgern (also herkömmlichen Festplatten). Ob Sie bereit sind, diesen Nachteil in Kauf zu nehmen, hängt von den Anforderungen ab. In meinem Fall läuft die VM kofler.info ohnedies die meiste Zeit im Leerlauf, der Geschwindigkeitsunterschied ist daher für mich nicht relevant. Gegebenenfalls lassen Sie die Option -c einfach weg, auch ohne die Komprimierung ist ja bereits eine deutliche Platzersparnis erreichbar.

Script für /var/lib/libvirt (Update Dez. 2019)

Das Thema lässt mich nicht los. Ich verwende den virt-manager mittlerweile auch intensiv am Desktop als VirtualBox-Alternative. Allerdings scheinen aktuelle virt-manager-Versionen beim Anlegen von QCOW2-Images generell den maximal vorgesehenen Speicherplatz zu allozieren. Die QCOW2-Dateien sind also von Anfang an viel zu groß.

Das folgende Script kann im Verzeichnis /var/lib/libvirt/images in der Form shrink-images *.qcow2 aufgerufen werden. Von den oben erwähnten Maßnahmen wird nur die erste (und schnellste) ausgeführt. Auf meinem Rechner reichte das aus, um den Speicherplatz von 30 Testinstallationen von 670 GiB auf 240 GiB zu reduzieren. Denken Sie daran, dass Sie die virtuellen Maschinen stoppen, bevor Sie das Script ausführen!!

#!/bin/bash
# Aufruf: ./shrink-images name.qcow2
for filename in "$@"; do
  bak=$filename.bak
  du -h $filename
  mv $filename $bak
  qemu-img convert $bak  -O qcow2 $filename 
  rm $bak
  du -h $filename
  echo ""
done

Quellen

4 Gedanken zu „Wie ich ein QCOW2-Image auf ein Drittel geschrumpft habe“

  1. Was hier auch super hilft ich gleich ein DISCARD/TRIM-fähiges Dateisystem zu haben, denn dann ist der gesamte Aufwand überflüssig (konfigurierbar via qemu)! qcow2 kann das, aber es ergibt mehr Sinn hier gleich ZFS Volumes (oder der noch immer sehr instabile Clone BTRFS) zu verwenden, da die das auch können, aber nicht geschrumpft werden müssen wie qcow2.

  2. Hallo,

    kann es sein, dass in dem Befehl mit Komprimierung

    „qemu-img convert ausgangspunkt.qcow2 -O qcow2 komprimiert.qcow2“

    die Option „-c“ fehlt?

Kommentare sind geschlossen.