Schrumpfen eines Image (.img) mit LVM Partitionen
Da ich vor kurzem ein physisches System virtualisiert habe, befasste ich mich damit, wie ich ein Image, auf welchem sich unter anderem eine LVM Partition befindet, verkleinere.
Wieso? Das mittels „dd“ erstellte Image hatte die exakte Größe der Festplatte, welche sich vorher im besagten System befand. Da von den 320 Gigabyte lediglich ca. 40 GB benötigt wurden, musste ich das Image „schrumpfen“. Damit war es aber noch nicht getan!
Neben der Boot-Partition befand sich auf dem System außerdem noch eine primär genutzte Partition, welche mittels LVM verwaltet wurde. Als ich mir die Partition genauer anschaute, stellte ich fest, dass die Größe der Logical Volumes und des Physical Volumes ebenfalls über dem standen, was ich eigentlich benötige.
Wie ich das Image mit der genannten Partition ohne Datenverlust verkleinerte, werde ich in diesem Artikel erklären.
Der Artikel wird sich in die folgenden Schritte einteilen:
- Mounten der LVM Partition
- Verkleinern der Logical Volumes
- Verkleinern des Physical Volume
- Mounten des Image
- Verkleinern der LVM Partition
- Verkleinern des Image
Ich gehe davon aus, dass sich das Image in eurem Fall als einzelne Datei auf einem Rechner befindet.
Mounten der LVM Partition
Begonnen wurde mit dem einzelnen mounten der LVM Partition. Um die Partition zu mounten, musste ich herausfinden, wann die Partition auf dem Image beginnt. Dazu ließ ich mir die Partitionstabelle anzeigen.
fdisk -l /media/mount-lv_data/gateway01.img
Hierbei konnte nun der Anfangssektor der Partition abgelesen werden.
Hier war zu erkennen, dass die Partition bei mir ab Sektor 2099200 beginnt. Da in meinem Fall jeder Sektor 512 Byte hat, konnte ich nun ausrechnen, ab welchem Byte die zweite Partition beginnt. (2099200*512 = 1074790400) Die ebenfalls angezeigte „erste“ Partition ist die Boot Partition, welche nicht weiter zu beachten war.
Damit ich nun auf die Partition zugreifen konnte, nutzte ich „losetup“ um die Partition des Image mit einem Loop Device zu assoziieren. Hierbei ist es wichtig, losetup das genaue Anfangsbyte der Partition mitzuteilen. Das gelingt mit der Option -o für offset. Alle vorherigen Bytes des Image werden somit ignoriert und das Image wird ab dem spezifizierten Byte geöffnet. Da in meinem Fall das Loop Device „/dev/loop1“ frei war, nutzte ich dieses.
losetup -o 1074790400 /dev/loop1 /media/mount-lv_data/gateway01.img
Die Syntax ist hierbei wie folgt:
losetup -o {offset} {zu verwendendes Device} {Image}
Verkleinern der Logical Volumes
Nachdem die LVM Partition gemountet wurde, erkennt LVM automatisch das Physical Volume, die Volume Groups und die Logical Volumes.
Bei mir haben die Logical Volumes die Bezeichnungen fedora-root und fedora-home. Die Bezeichnungen werde ich im weiteren Verlauf des Posts auch öfter vewenden. Setzt stattdessen in den Kommandos einfach eure Logical Volumes ein.
Bevor die eigentlichen Volumes verkleinert werden konnten, sind noch zwei weitere Schritte notwendig gewesen. (Diese können je nach verwendetem Dateisystem unterschiedlich sein. Die hier aufgeführten Kommandos funktionieren unter ext2, ext3 und ext4 Dateisystemen.)
- Dateisysteme überprüfen
e2fsck -f /dev/mapper/fedora-root
e2fsck -f /dev/mapper/fedora-home
- Dateisysteme auf gewünschte Größe verkleinern
resize2fs -p /dev/mapper/fedora-root 20G
resize2fs -p /dev/mapper/fedora-home 10G
Nachdem ich das Dateisystem nun auf die neue Größe angepasst hatte, verkleinerte ich die Logical Volumes auf die gleiche Größe.
lvreduce -L 20G /dev/mapper/fedora-root
lvreduce -L 10G /dev/mapper/fedora-home
Mit einem erneuten Dateisystem-check schloss ich die Änderungen an den Logical Volumes ab.
e2fsck -f /dev/mapper/fedora-root
e2fsck -f /dev/mapper/fedora-home
Verkleinern des Physical Volume
Zu dem Zeitpunkt ging LVM noch davon aus, dass das Physical Volume eine Größe von 320GB hat. Dieses habe ich mit den folgenden Schritten noch manuell verkleinert.
Um sicherzustellen, dass ich keine Teile des reservierten Speichers für die Logical Volumes abschneide (hätte LVM wahrscheinlich eh nicht zugelassen), habe ich das Physical Volume etwas größer als gemacht, als die Logical Volumes insgesamt. (35GB) Dafür habe ich folgendes Kommando genutzt:
pvresize --setphysicalvolumesize 35G /dev/loop1
In meinem Fall habe ich dabei den folgenden Fehler erhalten:
(cannot resize to 8959 extents as later ones are allocated)
LVM konnte das Physical Volume nicht auf die gegebene Anzahl an Einheiten (extents) verkleinern, da Einheiten belegt sind, die über dem Wert der Einheiten liegen, auf welche ich das Physical Volume verkleinern wollte. Würde LVM dies nicht prüfen, hätte ich hiermit beispielsweise ein Logical Volume löschen können. Nach etwas Recherche fand ich heraus, wie ich diesen Fehler beheben konnte.
Dazu ließ ich mir zuerst eine Übersicht der Segmente auf dem Physical Volume anzeigen.
pvs -v --segments /dev/loop1
In der Spalte „PE Ranges“ war hier abzulesen, dass sich das Volume „root“ auf den physical extents (PE’s) 63254 bis 68373 befindet.
Um dieses nun auf dem Physical Volume nach vorne zu verschieben, führte ich folgendes Kommando aus:
pvmove --alloc anywhere /dev/loop1:63254-68373
Je nach Größe des zu verschiebenden Bereichs kann dies einen kurzen Moment dauern.
Anschließend ließ ich mir erneut eine Übersicht anzeigen.
Hier konnte ich nun ablesen, dass das Logical Volume „root“ auf dem Physical Volume nach vorne verschoben wurde und es die physical extents 3555 bis 8674 nutzt.
Da das ursprüngliche Problem nun behoben wurde, habe ich dann erneut versucht, das Physical Volume zu verkleinern.
pvresize --setphysicalvolumesize 35G /dev/loop1
Dieses mal erfolgreich!
Das verkleinern des Physical Volumes war somit abgeschlossen.
Für die nächsten Schritte wurde die zweite Partition des Image nicht länger benötigt. Diese konnte nun wieder ausgehängt werden.
Volume Group auf nicht aktiv setzen:
vgchange -a n fedora
Assoziierung des Image mit dem Loop Device aufheben:
losetup -vd /dev/loop1
Mounten des Image
Nachdem alles verkleinert wurde, was sich auf der zweiten Partition des Image befand, musste die Partition an sich noch verkleinert werden. Um dies umzusetzen, mountete ich das komplette Image mit „losetup“ unter dem bereits bekannten Loop Device „/dev/loop1“.
losetup /dev/loop1 /media/mount-lv_data/gateway01.img
Verkleinern der LVM Partition
Zum verkleinern der Partition nutzte ich das Tool „parted“. Mit diesem öffnete ich mir zuerst das Device bzw. das Image unter dem Device.
parted /dev/loop1
Anschließend führte ich „resizepart“ aus.
(parted) resizepart
Da ich die zweite Partition verkleinern wollte, beantwortete ich die Frage nach der Partitionsnummer mit „2“.
Partitionsnummer? 2
Die zweite Partition sollte nach der Verkleinerung 40 GB groß sein. Da ich hier dem Physical Volume (35 GB) nicht in die Quere kommen wollte, habe ich die Partition bewusst etwas größer gemacht. Vergrößern könnte ich das Physical Volume im nachhinein ja immer.
Um die Partition auf eine Größe von 40 GB zu verkleinern, beantwortete ich die Frage nach dem Ende der Partition mit „40000“. (Die Angabe erfolgt hier in MB)
Ende? [320GB]? 40000
Der Vorgang war somit abgeschlossen. Hier nochmal eine Screenshot der ausgeführten Kommandos in Parted:
Um die Größe der Partition zu überprüfen, ließ ich mir noch die Partitionstabelle des Image ausgeben.
Hier war zu erkennen, dass die Partition „2“ erfolgreich verkleinert wurde.
Nun konnte Parted beendet werden.
quit
Da das Image für den nächsten Schritt nicht mehr eingehängt sein sollte, habe ich das Image von dem Loop Device getrennt.
losetup -vd /dev/loop1
Verkleinern des Image
Nachdem nun alle nötigen Schritte innerhalb des Image durchgeführt wurden, konnte ich das Image an sich verkleinern.
Dazu ließ ich mir erneut die Partitionstabelle des Image anzeigen.
fdisk -l /media/mount-lv_data/gateway01.img
Hier musste ich nun ablesen, ab welchem Block die letzte Partition endet. In meinem Fall 78125000. Des Weiteren merkte ich mir, dass die Block Size 512 Byte beträgt. Diese beiden Werte benötigte ich für den nächsten Schritt.
Um das Image zu verkleinern nutzte ich nun das Tool „truncate“. Hiermit verkleinerte ich das Image um eine genaue Anzahl an Bytes. Diese rechnete sich truncate anhand meiner Angabe zur Anzahl und zur Größe der Blöcke zusammen. Da die Anzahl der Blöcke bei null beginnt, muss auf die eben abgelesene Anzahl noch ein Block drauf gerechnet werden. Wird dies nicht beachtet, wird ein Block der Partition abgeschnitten. In dem folgenden Kommando habe ich dies allerdings beachtet.
truncate --size=$[(78125000+1)*512] /media/mount-lv_data/gateway01.img
Hiermit habe ich das Image auf die tatsächlich benötigte Größe der Partitionen geschrumpft.
Ende
Sollten bei der Verwendung meiner Anleitung Fragen entstehen, bin ich gerne bereit diese zu beantworten.