From 89689528b68f676a0f018cf4264b470f93619e7b Mon Sep 17 00:00:00 2001 From: spleenftw <57947900+Spleenftw@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:28:00 +0200 Subject: [PATCH] Add: Fixing an error I made a few years ago and migrating to LVM --- migrate-to-lvm/content/index.md | 453 ++++++++++++++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 migrate-to-lvm/content/index.md diff --git a/migrate-to-lvm/content/index.md b/migrate-to-lvm/content/index.md new file mode 100644 index 0000000..5076153 --- /dev/null +++ b/migrate-to-lvm/content/index.md @@ -0,0 +1,453 @@ +--- +title: "Fixing an error I made a few years ago and migrating to LVM" +date: 2025-09-21 +slug: migrate-to-lvm +status: +tags: + - linux + - disks + - partitions + - lvm + - debian + - blog + - homelab +category: system +--- + +
A few years ago when I decided to go down the rabbit-hole of homelabbing, one of the first thing I did was a debian12-template. +Smart choice would you say :
+Great, so now I can simply clone the template over and over for every need I have, right ? Right... ? Except for the simple fact that when I created the debian12-template, I made a mistake that i've to correct now : I did not use LVM.
+When you create a linux virtual machine, there's a step called partitioning (there are a few steps before : language choice, keyboard language, network configuration, root password, first user setup and then the partitioning step)
+
We have 4 choices :
+So the thing is, what choices do I have if I ever decided not to use LVM for every.single.vm in my homelab because of the mistake I made with the debian12-template a few years ago ?
+To my knowledge, there's only 2 way : either restart everything from scratch or try to migrate every vm partitions' to a LVM one. Considering the lack of time, motivation and documentation I currently have, restart everything from scratch is off the table.
+Let's assess what we currently have on our fresh debian12 installation :
+root@debian:~# cat /etc/os-release
+PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
+I've installed docker and a few packages, to run a container called uptime-kuma just to see if it still works after migrating with curl.
+root@debian:~# docker ps
+CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+a5fec5ba4df5 louislam/uptime-kuma:1 "/usr/bin/dumb-init …" 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:3001->3001/tcp, :::3001->3001/tcp uptime-kuma
+root@debian:~# curl localhost:3001
+Found. Redirecting to /dashboardroot@debian:~#
+For the disks and current partitioning :
+root@debian:~# fdisk -l
+Disk /dev/sda: 5 GiB, 5368709120 bytes, 10485760 sectors
+Disk model: QEMU HARDDISK
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+Disklabel type: dos
+Disk identifier: 0x3563c74a
+
+Device Boot Start End Sectors Size Id Type
+/dev/sda1 * 2048 8484863 8482816 4G 83 Linux
+/dev/sda2 8486910 10483711 1996802 975M 5 Extended
+/dev/sda5 8486912 10483711 1996800 975M 82 Linux swap / Solaris
+root@debian:~# df -h | grep /dev
+udev 965M 0 965M 0% /dev
+/dev/sda1 4.0G 2.6G 1.2G 69% /
+tmpfs 984M 0 984M 0% /dev/shm
+So let's try to migrate our freshly installed debian 12 virtual machine
+/!\ Before anything, create a snapshot or a backup ! /!\
+First thing first, we do need another disk so we have somewhere to migrate to :)
+Adding a disk on Proxmox is quite easy. Just go to the VM configuration and select the option to add another disk.
+
+
We should now see the new virtual disk we've just added :
+root@debian:~# fdisk -l
+Disk /dev/sdb: 5 GiB, 5368709120 bytes, 10485760 sectors
+Disk model: QEMU HARDDISK
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+
+
+Disk /dev/sda: 5 GiB, 5368709120 bytes, 10485760 sectors
+Disk model: QEMU HARDDISK
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+Disklabel type: dos
+Disk identifier: 0x3563c74a
+
+Device Boot Start End Sectors Size Id Type
+/dev/sda1 * 2048 8484863 8482816 4G 83 Linux
+/dev/sda2 8486910 10483711 1996802 975M 5 Extended
+/dev/sda5 8486912 10483711 1996800 975M 82 Linux swap / Solaris
+Now we want to partition the new disk, with fdisk :
+root@debian:~# fdisk /dev/sdb
+
+Welcome to fdisk (util-linux 2.38.1).
+Changes will remain in memory only, until you decide to write them.
+Be careful before using the write command.
+
+Device does not contain a recognized partition table.
+Created a new DOS (MBR) disklabel with disk identifier 0x931446ee.
+
+Command (m for help): n
+Partition type
+ p primary (0 primary, 0 extended, 4 free)
+ e extended (container for logical partitions)
+Select (default p): p
+Partition number (1-4, default 1):
+First sector (2048-10485759, default 2048):
+Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-10485759, default 10485759):
+
+Created a new partition 1 of type 'Linux' and of size 5 GiB.
+
+Command (m for help): t
+Selected partition 1
+Hex code or alias (type L to list all): 8e
+Changed type of partition 'Linux' to 'Linux LVM'.
+
+Command (m for help): a
+Selected partition 1
+The bootable flag on partition 1 is enabled now.
+
+Command (m for help): w
+The partition table has been altered.
+Calling ioctl() to re-read partition table.
+Syncing disks.
+Little tip for Linux: most of the time, when you’re prompted to make a choice and one option is in capital letters, it indicates the default choice that will be used if you just press Enter.
+So now, our disk /dev/sdb has a partition (which we can check with fdisk -l /dev/sdb :
root@debian:~# fdisk -l /dev/sdb
+Disk /dev/sdb: 5 GiB, 5368709120 bytes, 10485760 sectors
+Disk model: QEMU HARDDISK
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+Disklabel type: dos
+Disk identifier: 0x931446ee
+
+Device Boot Start End Sectors Size Id Type
+/dev/sdb1 * 2048 10485759 10483712 5G 8e Linux LVM
+We can now install a few packages that will help us to transfer files, use LVM and extend our partition size.
+apt update && apt install lvm2 rsync parted -y
Now that lvm2 is installed, we have to :
root@debian:~# pvcreate /dev/sdb1
+ Physical volume "/dev/sdb1" successfully created.
+root@debian:~# vgcreate vg-system /dev/sdb1
+ Volume group "vg-system" successfully created
+root@debian:~# lvcreate -L 1G -n lv-swap vg-system
+ Logical volume "lv-swap" created.
+root@debian:~# lvcreate -l 100%FREE -n lv-root vg-system
+ Logical volume "lv-root" created.
+We can then use the mkfs.ext4 command to format the logical volume lv-root to ext4. And with mkswap we can set up the lv-swap as... swap (who would've guessed, right ?)
root@debian:~# mkfs.ext4 /dev/vg-system/lv-root
+mke2fs 1.47.0 (5-Feb-2023)
+Discarding device blocks: done
+Creating filesystem with 1047552 4k blocks and 262144 inodes
+Filesystem UUID: 73265d61-1c37-4362-8298-c54e2488baa9
+Superblock backups stored on blocks:
+ 32768, 98304, 163840, 229376, 294912, 819200, 884736
+
+Allocating group tables: done
+Writing inode tables: done
+Creating journal (16384 blocks): done
+Writing superblocks and filesystem accounting information: done
+root@debian:~# mkswap /dev/vg-system/lv-swap
+Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
+no label, UUID=4d315a61-ccb8-45aa-9647-f99399ac24ec
+We have now to recreate the filesystem structure on the new logical volume lv-root and copy all the data on it :
+mkdir /mnt/newroot
+mount /dev/vg-system/lv-root /mnt/newroot
+rsync -avxHAX --progress --exclude=/mnt --exclude=/proc --exclude=/sys --exclude=/dev --exclude=/run --exclude=/tmp / /mnt/newroot/
+You should see something like this at the end and no errors :
+sent 2,529,433,716 bytes received 1,376,360 bytes 53,280,212.13 bytes/sec
+total size is 2,535,865,018 speedup is 1.00
+It is time now to mount the new root filesystem (devices, processes, sysfs, and runtime environment) :
+mkdir -p /mnt/newroot/{dev,proc,sys,run,tmp}
+mount --bind /dev /mnt/newroot/dev
+mount --bind /proc /mnt/newroot/proc
+mount --bind /sys /mnt/newroot/sys
+mount --bind /run /mnt/newroot/run
+Now that the new root filesystem is ready and all the special filesystems are mounted, we can chroot into it and finalize the setup:
+root@debian:~# chroot /mnt/newroot
+root@debian:/#
+Inside the chroot, we will now create the fstab file so that the system knows how to mount the new volumes at boot.
+Tip I’m using the EOF block so that everything between the first << 'EOF' and the final EOF gets written into the /etc/fstab file.
+
It’s simply a way to insert a block of text into a file directly from the shell without using a text-editor like nano,n.vi.m or even echo.
cat > /etc/fstab << 'EOF'
+# LVM Configuration
+/dev/vg-system/lv-root / ext4 defaults 0 1
+/dev/vg-system/lv-swap none swap sw 0 0
+
+# Temporary filesystems
+tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0
+EOF
+We now need to regenerate the initramfs, an early-boot filesystem that includes all the drivers and tools the kernel needs to find and mount the root filesystem :
+root@debian:/# update-initramfs -u -k all
+update-initramfs: Generating /boot/initrd.img-6.1.0-39-amd64
+update-initramfs: Generating /boot/initrd.img-6.1.0-25-amd64
+Next, we need to install the bootloader GRUB, so our system knows how to boot.
+root@debian:/# grub-install /dev/sdb
+Installing for i386-pc platform.
+Installation finished. No error reported.
+After that, we regenerate GRUB’s configuration :
+root@debian:/# update-grub
+Generating grub configuration file ...
+Found linux image: /boot/vmlinuz-6.1.0-39-amd64
+Found initrd image: /boot/initrd.img-6.1.0-39-amd64
+Found linux image: /boot/vmlinuz-6.1.0-25-amd64
+Found initrd image: /boot/initrd.img-6.1.0-25-amd64
+Warning: os-prober will not be executed to detect other bootable partitions.
+Systems on them will not be added to the GRUB boot configuration.
+Check GRUB_DISABLE_OS_PROBER documentation entry.
+done
+We can exit the chroot, dismount the /dev, /proc, /sys and /run that we previously mounter, shut the vm down and disable the old disk, select the new disk in the boot order and simply boot the virtual machine up.
+umount /mnt/newroot/dev
+umount /mnt/newroot/proc
+umount /mnt/newroot/sys
+umount /mnt/newroot/run
+umount /mnt/newroot
+In the boot order of you virtual machine, you should only see the network card and the new disk you've juste migrated to.
+
We are now booting on the new disk with LVM !
+
First thing first, let's check our disks with fdisk -l and a df -h:
root@debian:~# fdisk -l
+Disk /dev/sda: 5 GiB, 5368709120 bytes, 10485760 sectors
+Disk model: QEMU HARDDISK
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+Disklabel type: dos
+Disk identifier: 0x931446ee
+
+Device Boot Start End Sectors Size Id Type
+/dev/sda1 * 2048 10485759 10483712 5G 8e Linux LVM
+
+
+Disk /dev/mapper/vg--system-lv--swap: 1 GiB, 1073741824 bytes, 2097152 sectors
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+
+
+Disk /dev/mapper/vg--system-lv--root: 4 GiB, 4290772992 bytes, 8380416 sectors
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+root@debian:~# df -h
+Filesystem Size Used Avail Use% Mounted on
+udev 963M 0 963M 0% /dev
+tmpfs 197M 584K 197M 1% /run
+/dev/mapper/vg--system-lv--root 3.9G 2.6G 1.1G 71% /
+tmpfs 984M 0 984M 0% /dev/shm
+tmpfs 5.0M 0 5.0M 0% /run/lock
+tmpfs 984M 0 984M 0% /tmp
+overlay 3.9G 2.6G 1.1G 71% /var/lib/docker/overlay2/ab90d480e6ec488256582f1bd9cff1a19bf69d1d2bf5f7c4bf7b66c4f5de9764/merged
+tmpfs 197M 0 197M 0% /run/user/1000
+Then let's check our LVM configuration with LVM with pvs, vgs and lvs :
root@debian:~# pvs
+ PV VG Fmt Attr PSize PFree
+ /dev/sda1 vg-system lvm2 a-- <5.00g 0
+root@debian:~# vgs
+ VG #PV #LV #SN Attr VSize VFree
+ vg-system 1 2 0 wz--n- <5.00g 0
+root@debian:~# lvs
+ LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
+ lv-root vg-system -wi-ao---- <4.00g
+ lv-swap vg-system -wi-ao---- 1.00g
+Our final test will be to see if our docker is still runnig and working with docker ps and curl :
root@debian:~# docker ps
+CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+a5fec5ba4df5 louislam/uptime-kuma:1 "/usr/bin/dumb-init …" 4 hours ago Up 5 minutes (healthy) 0.0.0.0:3001->3001/tcp, :::3001->3001/tcp uptime-kuma
+root@debian:~# curl localhost:3001
+Found. Redirecting to /dashboardroot@debian:~#
+So all of this was to one day, if needed, I could expand my VM disk storage. +In Proxmox, Hardware > click on the Hard Drive you want to expand > Disk Actions > Resize. +Let's say I added 5 more Gigs, because the current 5G I gave the VM are not enough, we now have 10G disk storage, but only 5G are used by the filesystem.
+root@debian:~# fdisk -l
+Disk /dev/sda: 10 GiB, 10737418240 bytes, 20971520 sectors
+Disk model: QEMU HARDDISK
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+Disklabel type: dos
+Disk identifier: 0x931446ee
+
+Device Boot Start End Sectors Size Id Type
+/dev/sda1 * 2048 10485759 10483712 5G 8e Linux LVM
+
+
+Disk /dev/mapper/vg--system-lv--swap: 1 GiB, 1073741824 bytes, 2097152 sectors
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+
+
+Disk /dev/mapper/vg--system-lv--root: 4 GiB, 4290772992 bytes, 8380416 sectors
+Units: sectors of 1 * 512 = 512 bytes
+Sector size (logical/physical): 512 bytes / 512 bytes
+I/O size (minimum/optimal): 512 bytes / 512 bytes
+We can see that we have a single partition, /dev/sda1. We'll use parted to manage disk partitions :
root@debian:~# parted /dev/sda
+GNU Parted 3.5
+Using /dev/sda
+Welcome to GNU Parted! Type 'help' to view a list of commands.
+(parted) print
+Model: QEMU QEMU HARDDISK (scsi)
+Disk /dev/sda: 10.7GB
+Sector size (logical/physical): 512B/512B
+Partition Table: msdos
+Disk Flags:
+
+Number Start End Size Type File system Flags
+ 1 1049kB 5369MB 5368MB primary boot, lvm
+
+(parted) resizepart 1 100%
+We can verify that the entire 10GB is now allocated to /dev/sda1:
+(parted) print
+Model: QEMU QEMU HARDDISK (scsi)
+Disk /dev/sda: 10.7GB
+Sector size (logical/physical): 512B/512B
+Partition Table: msdos
+Disk Flags:
+
+Number Start End Size Type File system Flags
+ 1 1049kB 10.7GB 10.7GB primary boot, lvm
+Next, we resize our LVM Physical Volume with pveresize and check that the newly available space (5GB) is recognized:
root@debian:~# pvresize /dev/sda1
+ Physical volume "/dev/sda1" changed
+ 1 physical volume(s) resized or updated / 0 physical volume(s) not resized
+Then we verify that the Volume Group sees the free space with vgs:
root@debian:~# vgs
+ VG #PV #LV #SN Attr VSize VFree
+ vg-system 1 2 0 wz--n- <10.00g 5.00g
+We extend the Logical Volume using lvextend:
root@debian:~# lvextend -l +100%FREE /dev/vg-system/lv-root
+ Size of logical volume vg-system/lv-root changed from <4.00 GiB (1023 extents) to <9.00 GiB (2303 extents).
+ Logical volume vg-system/lv-root successfully resized.
+Finally, we resize the filesystem to use the new space with resize2fs :
root@debian:~# resize2fs /dev/vg-system/lv-root
+resize2fs 1.47.0 (5-Feb-2023)
+Filesystem at /dev/vg-system/lv-root is mounted on /; on-line resizing required
+old_desc_blocks = 1, new_desc_blocks = 2
+The filesystem on /dev/vg-system/lv-root is now 2358272 (4k) blocks long.
+We can check with df -h that the root filesystem now has more available space:
root@debian:~# df -h | grep root
+/dev/mapper/vg--system-lv--root 8.8G 2.6G 5.8G 31% /
+Let's take a look at my brand new debian12-template that has LVM :
+root@deb12-template:~# df -h | grep root
+/dev/mapper/deb12--template--vg-root 15G 1.7G 12G 13% /
+If you ever clone it and rename the host (with hostnamectl sethostname and editing /etc/hosts ), you'll be stuck with the same VG name. And you may want to rename it. Here's are a few steps to achieve that :
vgrename to rename the VG (make sense)Step one : using vgrename to rename the VG (make sense)
+Here I decided to rename it system-vg but you can rename it whatever suits you.
+root@deb12-template:~# vgs
+ VG #PV #LV #SN Attr VSize VFree
+ deb12-template-vg 1 2 0 wz--n- <15.52g 0
+root@deb12-template:~# vgrename deb12-template-vg system-vg
+ Volume group "deb12-template-vg" successfully renamed to "system-vg"
+root@deb12-template:~# vgs
+ VG #PV #LV #SN Attr VSize VFree
+ system-vg 1 2 0 wz--n- <15.52g 0
+Step two : updating /etc/fstab/ with the new VG name
+My current /etc/fstab is currently looking like this :
+root@deb12-template:~# cat /etc/fstab
+# /etc/fstab: static file system information.
+#
+# Use 'blkid' to print the universally unique identifier for a
+# device; this may be used with UUID= as a more robust way to name devices
+# that works even if disks are added and removed. See fstab(5).
+#
+# systemd generates mount units based on this file, see systemd.mount(5).
+# Please run 'systemctl daemon-reload' after making changes here.
+#
+# <file system> <mount point> <type> <options> <dump> <pass>
+/dev/mapper/deb12--template--vg-root / ext4 errors=remount-ro 0 1
+# /boot was on /dev/sda1 during installation
+UUID=f4ca6e38-0263-4fe1-95f1-dc0cf9449ce2 /boot ext2 defaults 0 2
+/dev/mapper/deb12--template--vg-swap_1 none swap sw 0 0
+/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
+You want to replace the deb12-template with system. Using vi(m), it is simple with :%s/oldtexttoreplace/replacement/g, which would be :%s/deb12--template/system/g. So now, my /etc/fstab is now looking like this :
root@deb12-template:~# cat /etc/fstab
+# /etc/fstab: static file system information.
+#
+# Use 'blkid' to print the universally unique identifier for a
+# device; this may be used with UUID= as a more robust way to name devices
+# that works even if disks are added and removed. See fstab(5).
+#
+# systemd generates mount units based on this file, see systemd.mount(5).
+# Please run 'systemctl daemon-reload' after making changes here.
+#
+# <file system> <mount point> <type> <options> <dump> <pass>
+/dev/mapper/system--vg-root / ext4 errors=remount-ro 0 1
+# /boot was on /dev/sda1 during installation
+UUID=f4ca6e38-0263-4fe1-95f1-dc0cf9449ce2 /boot ext2 defaults 0 2
+/dev/mapper/system--vg-swap_1 none swap sw 0 0
+/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
+Step three (optionnal, only if you have swap) : updating /etc/initramfs-tools/conf.d/resume
+root@deb12-template:~# cat /etc/initramfs-tools/conf.d/resume
+RESUME=/dev/mapper/deb12--template--vg-swap_1
+Once again, we replace the deb12--template with system.
+root@deb12-template:~# cat /etc/initramfs-tools/conf.d/resume
+RESUME=/dev/mapper/system--vg-swap_1
+Step four : regenerating the initramfs
+This part should be the easiest one if everything else before runned smoothly. We will regenerating the initramfs with update-initramfs -u -k all :
+root@deb12-template:~# update-initramfs -u -k all
+update-initramfs: Generating /boot/initrd.img-6.1.0-39-amd64
+update-initramfs: Generating /boot/initrd.img-6.1.0-25-amd64
+Last step : updating grub
+We now have to update the /boot/grub/grub.cfg which still has the deb12--template VG name.
+root@deb12-template:~# cat /boot/grub/grub.cfg | grep deb12--template
+ linux /vmlinuz-6.1.0-39-amd64 root=/dev/mapper/deb12--template--vg-root ro quiet
+ linux /vmlinuz-6.1.0-39-amd64 root=/dev/mapper/deb12--template--vg-root ro quiet
+ linux /vmlinuz-6.1.0-39-amd64 root=/dev/mapper/deb12--template--vg-root ro single
+ linux /vmlinuz-6.1.0-25-amd64 root=/dev/mapper/deb12--template--vg-root ro quiet
+ linux /vmlinuz-6.1.0-25-amd64 root=/dev/mapper/deb12--template--vg-root ro single
+Again, we'll use n.vi.m and :%s/x/y/g to replace every occurence of deb12--template
root@deb12-template:~# cat /boot/grub/grub.cfg | grep system
+ linux /vmlinuz-6.1.0-39-amd64 root=/dev/mapper/system--vg-root ro quiet
+ linux /vmlinuz-6.1.0-39-amd64 root=/dev/mapper/system--vg-root ro quiet
+ linux /vmlinuz-6.1.0-39-amd64 root=/dev/mapper/system--vg-root ro single
+ linux /vmlinuz-6.1.0-25-amd64 root=/dev/mapper/system--vg-root ro quiet
+ linux /vmlinuz-6.1.0-25-amd64 root=/dev/mapper/system--vg-root ro single
+Then simply reboot, and it should be good !
+root@deb12-template:~# df -h | grep root
+/dev/mapper/system--vg-root 15G 1.7G 12G 13% /
+Thanks for reading me,
+
spleenftw