I'm trying to design a framework that would allow me to do full transactional upgrade of Ubuntu and the root file system.
The requirement is that if my upgrade fails I want to be able to roll back to the exact state I was at before.
Ubuntu Core seems to be providing the exact kind of functionality I need, but it comes with a lot of security limitations, and is really a fairly different system compared to classical Ubuntu.
One option is to have 2 partitions. I'd install the new version of the OS on the 2nd partition, re-apply all my configurations and then update grub to boot from that partition.
However, I'd then need to decide on the size of each partition which is not ideal. This would also make it more complicated to share some directories between the 2 versions of the OS (i.e., instead of copying logs in /var
, I'd rather be able to just bind-mount /var
from somewhere else).
What I'm thinking is having a root directory with a bunch of empty directories /etc
, /lib
, /opt
, etc., and one directory such as /versions
which would contain my different versions of the OS.
E.g.
/versions/v1/
, /versions/v2/
.
At boot time, the boot process would select the right version and then bind mount each of the child directories onto the root subdirectories.
In other words, if I want to boot from /versions/v2
, it would bind mount:
/versions/v2/etc
on /etc
/versions/v2/opt
on /opt
etc.
What I'm wondering is if this is the right approach to this problem and if so then how could that be accomplished.
After some research, I've found a way to achieve what I was looking for.
I had to dig into the initramfs image (
/boot/initrd.img-...
) to find out how the mounting of various file systems was performed. The initramfs image for ubuntu core was particularly useful.The design I've settled on is actually fairly similar to ubuntu core. I create an initial ubuntu installation, do the configurations I need and then do a deep copy using
cpio
and finally package the copy into a read-only squashfs file system usingmksquashfs
. I will store the squashfs image on the main partition of the new OS. During the loading of the OS, I've editedinitrd.img
to mount the squashfs image of the version I want onto/root
, and then have set upoverlayroot
on top of it, which is a writable overlay.