====== Converting a machine to an LVM root FS ======

This topic explains how to modify the root file system and repartition the disk of a running system. These are dangerous activities and if not performed correctly, can result in the loss of data and/or an unbootable machine. You are recommended to test the following guide on a test machine (perhaps a virtual server you can create on your own network) before risking a system with valuable data on it, or which would be difficult to re-install if it becomes unbootable.

You should DEFINITELY have a backup of the system you plan to do this to, although if you don't keep good backups as standard procedure, you probably shouldn't be dealing with this level of system administration, until you've got some basics put in place.

Suppose you have a machine with a hard disk which has a single partition on it for the entire root file system of the server (maybe it has a second partition for swap, but the entire space on the disk is allocated) and you want to convert the machine to use Logical Volume Management instead. Two reasons why you might want to do this are: * LVM makes it simple to add another disk to the machine and expand or move partitions between the disks, perhaps in order to install a bigger disk and then remove the older smaller one * Some security scanning tool or expert advises that you should use separately mounted partitions for things like /home, /tmp, /var etc, with some special options like noexec or nosuid on the non-root partitions Now let's add a further complication to the situation - the machine in question is in a remote data centre which you either do not have access to, or it's at the very least inconvenient to get there in order to do things like repartitioning the disk from a rescue image. So, you need to find a way to: - Reduce the space used on disk by the existing (running) root file system - Create a new partition for LVM in the disk space you have now freed up - Create Logical Volumes under LVM, create file systems inside them, mount them and copy the contents of the existing system to them - Persuade GRUB and the initramfs to start the machine using the new Logical Volumes You can then do whatever you like with the partition which held the old root file system, such as: * use it as swap space * create a Physical Volume in it and add it to the LVM Volume Group you're now using * use it for /boot * ignore it because it's too small to bother with any more It's not necessarily obvious how to achieve all the above steps even when you can reboot the machine into a rescue system and work at its console, but doing them when you have remote SSH access to the system only does make things more interesting. ===== Reducing the space used by the running system ===== **resize2fs** can reduce the size of a file system, but only when it is not mounted, and **e2fsck** has been run on it immediately beforehand. Therefore we need to find a way to run **e2fsck** and **resize2fs** on the root file system before it has been mounted (there is no way of unmounting the root file system on a running machine). Fortunately, initramfs provides a way to do this. Firstly, create a script in /etc/initramfs-tools/scripts/local-premount called something like resizefs (the name can be anything you like), containing:#!/bin/sh -e # Try to resize the root FS before it has been mounted PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac echo "Attempting to resize the root FS" device="/dev/sda1" size="8G" if [ -x /sbin/e2fsck ] then echo "Running e2fsck" /sbin/e2fsck -f $device if [ -x /sbin/resize2fs ] then echo "Running resize2fs" /sbin/resize2fs -p $device $size else echo "Cannot find /sbin/resize2fs" fi else echo "Cannot find /sbin/e2fsck" fi echo "Resize root FS script ends" Adjust the device name **/dev/sda1** to be correct for your currently-mounted root FS device, and change the desired size **8G** to something at least 10% bigger than the amount **df -h** tells you the current root FS is using. The script as it stands will get run within the initramfs shortly before the root file system device gets mounted - ideal :) However, it won't currently work, because the command resize2fs is not present in the standard initramfs. To get it included, create another file under /etc/initramfs-tools/hooks (again, you can call it anything you like) with the content:#!/bin/sh -e # Include resize2fs in the commands available to the initramfs PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac . /usr/share/initramfs-tools/hook-functions copy_exec /sbin/resize2fs /sbin Once both of the above are in place, update the initramfs and reboot the machine:# update-initramfs -u # rebootWhen it comes back up, the **df -h** command should show that the root file system is now much smaller than it used to be (and will therefore have a higher usage percentage). Once the machine has rebooted, the next step is to reduce the size of the partition in which the (now smaller) root file system resides, so that there is unallocated space on the disk, which we can later use for LVM. **fdisk /dev/sda** (adjusted for whatever your root file system device name is) will probably show a single partition **sda1** which is the same size as your root FS used to be, and might also have another partition for swap. If it's any more complicated than that, you are thoroughly recommended to create a matching setup on a virtual server and try out these instructions on that in order to be sure that you understand what you're doing and how to adapt these instructions to your starting setup. In **fdisk** you need to: - delete the partition holding the root FS - create a new partition with the same number, and starting at the same sector, and at least 10% larger than the size you made the root FS itself in the previous step (which, if you recall, was at least 10% larger than **df -h** told you the root FS was actually using). - Just to be very clear about that, take the size **df -h** told you the root FS was using to start with, add 10% and shring the root FS to that size (above) then add __another__ 10% and make that the size of the new partition you are creating now - you will almost certainly be told that **Partition #1 contains a ext4 signature** and asked **Do you want to remove the signature?** - You **do not** want to remove the signature. - write the changes to disk A small adjustment to the initramfs script we created earlier will now __increase__ the size of the root FS to occupy precisely the amount of space available in this new partition. Edit the script you created in /etc/initramfs-tools/scripts/local-premount and remove the value of the **size** variable (leave it saying simply **size=""**). Then update the initramfs with the modified script and reboot the server again:# update-initramfs -u # reboot When the machine restarts, **df -h** should tell you that the root FS is now about 10% bigger than it was after the previous reboot, and this means that it is now using the entire space available in the (much smaller than previously) partition you created. We have now finished with the script added to the initramfs, so remove the files you created and rebuild the initramfs:# rm /etc/initramfs-tools/scripts/local-premount/resize /etc/initramfs-tools/hooks/copyfile # update-initramfs -u The next step is to use the now-unallocated disk space to create an LVM partition and create some Logical Volumes in it. ===== Create a new partition for LVM ===== If LVM is not installed (which is likely, given that you're weren't previously using it), install the **lvm2** package:# aptitude install lvm2 Then create a new disk partition using **fdisk /dev/sda** (again, adjust the device name as appropriate for your system) and create a new partition of type primary using all the available space which now follows the smaller root partition you worked on earlier. Make the partition type **8e** (for LVM). You can use the new partition immediately:# pvcreate /dev/sda2 # vgcreate System /dev/sda2 # lvcreate -L 20G -n root System Adjust **/dev/sda2** to be the partition you just created for LVM to use, substitute whatever name you want to use for your Logical Volume Group in place of **System** and adjust **20G** to be an appropriate size for the new (LVM-based) root partition, __bearing in mind__ that /home, /var and any other partitions you choose to create will occupy __their own space__ and therefore the space taken up by these does __not__ need to be included in the size you make **root**. Continue to use **lvcreate** to set up all the partitions you want to have on your new system. Common choices might be: * / * /home * /var * /var/log You can also create a swap partition in LVM if you wish. ===== Create file systems in the new partitions ===== Once you have created all the partitions you want in LVM, format each of them. For standard EXT file systems, use# mkfs.ext4 -L root /dev/System/root etc. This will format an EXT4 file system with a label (whatever follows **-L**) which you can then use in **/etc/fstab** to ensure the right system get mounted on the correct mount points. If you made an LVM swap partition, format that too with# mkswap -L swap /dev/System/swap Once all the partitions are formatted, mount them so that the system itself can be copied across:# mount /dev/System/root /mnt # mkdir /mnt/home # mount /dev/System/home /mnt/home # mkdir /mnt/var # mount /dev/System/var /mnt/var # mkdir /mnt/var/log # mount /dev/System/varlog /mnt/var/log # rsync -Pavx / /mnt Note that the **-x** parameter to **rsync** tells it not to cross partition boundaries, so it will not, for example, try to copy the directory tree which is now under /mnt into /mnt/mnt etc. If **/boot** happened to be a separate partition on your old system, make sure that gets copied as well:# rsync -Pav /boot /mnt ===== Switch to the new file system and tell GRUB to boot into it ===== Now you have a copy of the running system's file systems in the new LVM partitions, and everything is mounted under /mnt. To get GRUB to use this next time you reboot, **chroot* into the new file system and update /etc/fstab, then update GRUB:# mount --bind /dev /mnt/dev # chroot /mnt # mount -t proc /proc /proc # mount -t sysfs /sys /sys # vi /etc/fstabYou want **/etc/fstab** to contain the new mount points and the corresponding labels for the Logical Volumes:# LABEL=root / ext4 errors=remount-ro 0 1 LABEL=home /home ext4 errors=remount-ro,nodev,nosuid 0 2 LABEL=var /var ext4 errors=remount-ro,nodev,nosuid 0 2 LABEL=varlog /var/log ext4 errors=remount-ro,nodev,nosuid,noexec 0 2The mount options shown for the non-root partitions match the recommendations from [[https://github.com/ovh/debian-cis|the security hardening script]] I was using on this system. Once that is done, tell GRUB to boot into the LVM system and not the old partition:# update-grub # grub-install /dev/sda # umount /sys # umount /proc # exit # reboot Once the machine reboots, check that the root file system is mounted from LVM:# df -h / Filesystem Size Used Avail Use% Mounted on /dev/mapper/System-root 20G 1.5G 3.2G 8% / ===== Congratulations ===== You have now converted the machine from having a single disk partition with the entire file system inside it, into a machine with as many separate LVM partitions as you like, and you've confirmed that it boots correctly. Everything has been done remotely with no requirement to boot from a rescue system or to log in to the console. ---- [[.:|Go up]]\\ Return to [[:|main index]].