Proxmox: Block Size von virtuellem Datenträger nachträglich ändern

Warum die Block Size nachträglich ändern?

Wenn man einen neuen ZFS Pool erstellt sollte man sich genau überlegen, welche Block Size man in Proxmox für den Pool einträgt, bevor man irgendwelche VMs erstellt. Denn jeder danach neu erstellte Datenträger (zvol), der auf diesem Pool liegen soll, wird automatisch mit der dort festgelegten Block Size (volblocksize) erstellt und kann später nicht mehr geändert werden.
Dies kann sehr problematisch werden, denn standardmäßig nutzt Proxmox eine volblocksize von 8K. Das mag für einen normalen ZFS Mirror passen, für ein Raidz Array von Laufwerken mit 4K logischer Sektorgröße oder höher (bzw. ashift von 12 oder mehr) taugt das nichts.
Wenn man den Pool z.B. mit einem ashift-Wert von 12 erstellt, dann ist die kleinstmögliche Größeneinheit, welche auf das einzelne physikalische Laufwerk geschrieben werden kann, 4 KB. Für jedes virtuelle Laufwerk wird auf dem Pool ein eigenes zvol angelegt, welches quasi als virtuelle Festplatte dient. Ähnlich wie beim Pool selbst kann man auch für jedes zvol die kleinstmögliche Größeneinheit einstellen. Diesen Wert nennt man volblocksize.

Wenn man ein Raidz-Array einem Mirror vorzieht, dann eigentlich nur, weil bei einem Raidz weniger Platz für die Ausfallsicherheit verloren geht. Denn schneller ist ein Mirror eigentlich immer. Man kann aber eben auch nur den halben Platz nutzen, da alle Daten doppelt gespeichert werden müssen.
Im Gegensatz dazu verliert man bei einem Raidz1 mit 3 Laufwerken in Theorie nur 1/3 der Kapazität und bei einem Raidz1 mit 5 Laufwerken nur 1/5 der Kapazität. Dies ist aber auch nur der Fall, wenn die volblocksize auch erhöht wurde.
Denn mit dem Standardwert für volblocksize von 8K wird alles auf der virtuellen Festplatte in 8KB Blöcken gespeichert. Diese 8 KB Blöcke müssen dann aber noch vom Pool gespeichert werden und da kommt des dann zum Problem. Denn wenn die Laufwerke des Pools z.B. eine logische Sektorgröße von 4K haben, dann ist die Auflösung einfach viel zu grob, da eben nur ein vielfaches von 4 KB gespeichert werden kann. Im Endeffekt werden kann viele „angebrochene“ 4 KB Blöcke geschrieben und ein 8 KB Block auf dem zvol braucht dann doch 16 KB Platz auf dem Pool. Man verliert also trotzdem die Hälfte der Kapazität und nicht nur die theoretischen 1/3 oder gar 1/5.

Wer wissen will, was eine brauchbare volblocksize für einen Raidz1 Pool ist, der sollte sich diese Tabelle anschauen. Dort ist für Raidz1 (und Raidz2/Raidz3 über die Reiter ganz unten) tabellarisch aufgelistet, wieviel Kapazität man tatsächlich verliert, wenn man eine bestimmte volblocksize mit einer bestimmten Anzahl von Laufwerken nutzt.
Nehmen wir meinen Raidz1 Pool aus 5 SDDs mit einer logischen Sektorgröße von 4K (ashift=12) als Beispiel:

In der ersten Spalte der Tabelle sieht man die Blockgröße in Sektoren.
In der ersten Zeile steht die Anzahl der Laufwerke, aus denen der Raidz1 Pool besteht.
Die Prozentzahlen zeigen den zusätzlich nötigen Platz für die Parität an, welcher zusätzlich zu den reinen Daten verbraucht wird. Wenn ich 1 GB an reinen Daten speichern will und dort 25% stehen, dann werden 1,25 GB tatsächlich verbraucht.

Möchte man die optimale volblocksize für einen Raidz1 Pool herausfinden, so geht man erst in die Spalte, welche der Anzahl der Laufwerke des eigenen Pools entspricht. Ich habe 5 SSDs also nehme ich die Spalte in der ich die 5 eingekreist habe.
Normalerweise möchte man die Blockgröße kleinstmöglich haben und im Idealfall sollte diese auch einem Vielfachen von Zwei entsprechen (diese sind in der Tabelle fett geschrieben). Ich nehme also die oberste Zeile in der Tabelle die fett geschrieben ist und wo der Prozentwert möglichst klein ist. In meinem Fall wäre es die rot eingekreiste Zeile mit der Blockgröße in Sektoren von 8.
Bei einer Blockgröße von 8 Sektoren und 5 SSDs würde ich also 25% zusätzlichen Platz benötigen. Ich würde also 1/5 der Gesamtkapazität für die Parität verlieren, was ja auch genau das Optimum bei 5 SSDs wäre.

Möchte man die entsprechende volblocksize für Proxmox haben, dann muss man den Wert von „Blockgröße in Sektoren“ mit der Blockgröße seines Pools multiplizieren. Meine SSDs nutzen eine logische Sektorgröße von 4K also habe ich den Pool mit einem ashift-Wert von 12 erstellt, wodurch der Pool ebenfalls eine Blockgröße von 4 KB hat. Bei einer „Blockgröße in Sektoren“ von 8 und einer Pool-Blockgröße von 4 KB wäre die volblocksize also 32K (8 * 4KB).

Meine volblocksize ist falsch. Wie ändere ich die nun?

Wie gesagt, man kann die volblocksize von zvols nicht mehr nachträglich ändern. Beim Pool ist über die GUI zwar jederzeit die Blockgröße änderbar, diese wird aber nur auf neu erstellte virtuelle Festplatten angewandt.
Es führt also nichts drum herum in jeder VM alle virtuelle Festplatten durch neu erstellte virtuelle Festplatten zu ersetzen.

1.) Block Size für den Pool ändern

Als erstes muss über das Proxmox Webinterface unter „Datacenter -> Storage -> DeinPool“ der Wert für „Block Size“ auf den neuen Wert angepasst werden. Jede danach neu erstelle virtuelle Festplatte des Pools nutzt dann diesen Wert als volblocksize. Wie man den passenden Wert herausfinden kann man der Tabelle oben entnehmen.

2.) Backup von der VM erstellen

Wir werden alle virtuellen Festplatten der VM löschen, also sollte vorher ein Backup angelegt werden, damit im Ernstfall problemlos die alte VM wieder durch das Backup eingespielt werden kann. Da wir die Festplatten löschen helfen auch keine Snapshots. Falls Snapshots vorhanden sind müssen diese sogar vorher noch gelöscht werden, da sich sonst keine virtuelle Festplatte löschen lässt, für die noch Snapshots existieren.

Als „Mode“ sollte „Stop“ gewählt werden. Wir müssen die VM sowieso mehrfach herunterfahren und „Stop“ ist die sicherste Art ein Backup zu erstellen.

3.) Linux Live CD als primäres Bootquelle setzen

Um die Daten von der alten virtuellen Festplatte auf die neue virtuelle Festplatte zu kopieren werden wir eine Debian Live CD nutzen und mit dieser per dd-Befehl die Festplatten auf Blockebene klonen. Dies klont auch gleich die komplette Partitionstabelle, Bootloader, Partitionen usw. und wir haben wirklich eine 1:1-Kopie der Festplatte und müssen nachträglich nichts mehr ändern.
Eine Debian Live CD ISO bekommt ihr hier.
Auf den Server kopieren könnt ihr die ISO auch direkt über das Proxmox Webinterface unter „Storage View -> DeinServerName -> Dein StorageFürISOs -> Content -> Upload“:

Danach die VM herunterfahren. Sobald diese aus ist dort die Debian Live CD einbinden:

Und die Boot-Reihenfolge so ändern, dass da CD/DVD ganz oben steht:

Beim nächsten Start der VM solltet Ihr dann in ein Live Debian booten anstatt in das normale Betriebssystem. Das hat den Vorteil, dass das Live Debian auf keinerlei virtuelle Festplatten zugreifen muss, da es rein aus dem RAM heraus läuft und alle Festplatten ausgebunden werden können um sie korrekt zu klonen.

4.) Neue virtuelle Festplatten erstellen

Als nächstes muss für jede bestehende virtuelle Festplatte eine genau gleich große neue virtuelle Festplatte erstellt werden. Hier einfach alle Einstellungen von der alten Festplatte für die neue Festplatte übernehmen:

5.) Live CD booten und Festplatten herausfinden

VM starten und bei der VM unter „Console“ (oder Doppelklick auf die VM für Vollbild im eigenen Fenster) die VM per VNC bedienen. Im Boot-Bildschirm „Debian GNU/Linux Live“ auswählen und mit Enter bestätigen:

Danach folgendes eintippen:

sudo lsblk

Der Befehl sollte euch alle verbundenen virtuellen Festplatten auflisten. Nun muss herausgefunden werden, was der Name der alten Festplatte und was der Name der neuen Festplatte ist. Bei mir sieht die Ausgabe so aus:

Mich interessieren nur die Festplatten, welche in der Spalte „TYPE“ den Wert „disk“ haben. Von denen gibt es 3 Stück und deren Namen kann man in der Spalte „NAME“ entnehmen. In meinem Fall heißen die Festplatten „sda“, „sdb“ und „sdc“.
In der Spalte „SIZE“ steht dessen Größe und sowohl meine alte als auch meine neue Festplatte habe ich mit einer Kapazität von 16 GB erstellt. Uns interessieren hier also nur die Festplatten „sda“ und „sdc“, da nur diese die beiden Festplatten die wir klonen wollen sein können.
Dann muss man noch wissen, welche von beiden Festplatten denn die Neue und welche die Alte ist. Ist in dem Fall ziemlich einfach. Meine alte Festplatte war partitioniert und die neue Festplatte ist frisch erstellt und somit unpartitioniert. „sda“ hat 3 Partitionen (sda1, sda2 und sda3) und „sdc“ hat keine einzige Partition. Somit muss „sda“ die alte und „sdc“ die neue Festplatte sein.
Hier jetzt bitte die Namen der jeweiligen Festplatten mitschreiben und wirklich sicherstellen, dass das nur genau die Festplatten sein können die man denkt, damit nicht die falsche Festplatte unwiderruflich überschrieben wird.
Die Namen „sda“ und „sdc“ sind dort übrigens verkürzt dargestellt. Der volle Pfad zu den Festplatten hat immer ein „/dev/“ vorangestellt. Statt „sda“ und „sdc“ müssen wir also später „/dev/sda“ und „/dev/sdc“ verwenden.

6.) Festplatten klonen

Das Klonen der Festplatten machen wir mit folgendem Befehl:

sudo dd conv=sparse if=/dev/ZuKlonendeFestplatte of=/dev/NeueFestplatte bs=8K status=progress

Zu den Parametern:
„conv=spare“ sorgt dafür, dass beim Klonen das Thin Provisioning erhalten bleibt. Nutzt man kein Thin Provisioning kann der Parameter weggelassen werden.

„if=/dev/ZuKlonendeFestplatte“ besagt was kopiert werden soll. Hier sollte eure alte Festplatte stehen.

„of=/dev/NeueFestplatte“ besagt wohin kopiert werden soll. Hier sollte eure neue Festplatte stehen.

„bs=4K“ sagt in welchen Blockgrößen der Kopiervorgang stattfinden soll. Hier bin ich nicht ganz sicher was der beste Wert wäre. Ich denke mit 8K macht ihr nichts falsch, wenn eure alte virtuelle Festplatte mit einer Block Size von 8K erstellt wurde.

„status=progress“ zeigt euch an wie weit das kopieren fortgeschritten ist

Ich nutze Thin Provisioning, meine alte virtuelle Festplatte hatte eine Blocksize von 8K, meine alte Festplatte ist „/dev/sda“ und diese möchte ich auf die neue leere Festplatte „/dev/sdc“ klonen. Ich führe also folgendes aus:

sudo dd conv=sparse if=/dev/sda of=/dev/sdc bs=8K status=progress

Tipp falls die Zeichen „=“ und „/“ nicht über Shift+7 und Shift+0 funktionieren sollten. „=“ ist bei mir in der VM über die Taste „`“ und „/“ über die Taste „/“ auf dem Num-Block eintippbar.

Das Klonen sieht dann so aus:

Danach noch einmal ausführen:

sudo lsblk

Wenn alles geklappt hat sollte eure neue Festplatte nun die gleiche Anzahl und Größe an Partitionen haben wie eure alte Festplatte.
Bei mir sind die Partitionen „sdc1“, „sdc2“ und „sdc3“ neu hinzugekommen:

Nun könnt ihr die VM mit folgendem Befehl herunterfahren:

sudo shutdown now

7.) Alte virtuelle Festplatte aushängen

Eure alte und neue virtuelle Festplatte sollte nun von Sicht der VM aus absolut identisch sein. Das heißt aber auch, dass da nun alle Partitionen mit genau der gleichen UUID doppelt in der VM vorhanden sind. Das hat den Vorteil, dass da keine Systemeinstellungen abgeändert werden müssen, aber es muss die alte virtuelle Festplatte zuvor erst entfernt werden, bevor man die VM wieder starten kann.

Also erst die alte virtuelle Festplatte aushängen (Detach-Knopf):

Dann die ISO wieder entfernen:

Und bei der Bootreihenfolge die neue virtuelle Festplatte nach ganz oben setzen:

8.) Testen ob alles so läuft wie bisher

Wenn Ihr jetzt die VM erneut startet, dann sollte eigentlich alles genau so sein wie bisher.
Wenn ihr sehen wollt ob die VM nun weniger Platz verbraucht, dann könnt ihr als root auf dem Proxmox Server selbst folgenden Befehl eingeben:

zfs list

Dort seht ihr alle virtuellen Festplatten und was diese an Platz auf dem Pool belegen. Der Wert in der Spalte „REFER“ bezieht sich auf die Größe der virtuellen Festplatte ohne Snapshots. Die neue virtuelle Festplatte sollte dort bei „REFER“ nun eigentlich weniger Platz auf dem Pool verbrauchen.
Ist etwas schwer zu erkennen welche denn nun genau die gesuchten virtuellen Festplatten sind. Wenn der Name „DeinPool/DeinVMDataset/vm-123-disc-4“ ist, dann ist es die Festplatte Nr. 4 von der VM mit der ID 123. Welche Festplatte wie heißt steht sonst auch unter „Hardware“ bei den „Festplatten“ in der VM.

Sollte alles passen könnt ihr die alte ausgehängt virtuelle Festplatte dann auch endgültig löschen:

Das geht wie gesagt aber auch erst, wenn ihr alle Snapshots gelöscht habt.

Ich hoffe das konnte wem helfen und falls ja würde ich mich über einen Kommentar freuen.

MfG

Björn