Cannot boot from initramfs (unable to switch root, sysroot directory is empty)

Greetings everyone.

Okay, so I have a problem with Fedora 34. More specifically, I have a problem with a custom built image that is part of the services that we deliver.

The Problem
The problem has to do with initramfs. See, we’ve been using initrd up until now, but the amount of packages and binaries have increased since our last upgrade from Fedora 32 to Fedora 34. Without manually adding new packages, the base, release and dependency packages have now increased to a point where initrd has become over 500MB in size.

The size of this initrd makes this image very unstable: legacy PXE doesn’t work for instance, because this image is too big for TFTP and will freeze on most networks. However, the biggest, most crucial issue we have, is that GRUB2 is not allowing this initrd to boot anymore, mainly on HP laptops. Whenever we go back to Fedora 32, the images seem to be more stable. We think it’s because of initrd being smaller here. The default Fedora Workstation (34) images also work on systems where our custom image is getting kernel panics.

Our image uses a /vmlinuz and /initrd file to boot into a RAMDisk using either USB (GRUB2) or PXE (iPXE). This is by design: Our application is a Chromium-based, integrated kiosk web browser, running on Fedora (34). It is supposed to be volatile and stateless.

Initramfs
I’ve been looking into initramfs as a replacement to initrd, since it’s much newer, much lighter, and the size of this file may not trigger any bugs in GRUB2. Perhaps this will also enable us the use of legacy PXE implementations like PXELINUX and Windows Deployment Services. I figured I could easily replace the use of CPIO + XZ with Dracut. But I’ve been stuck on an issue I can’t really wrap my head around…

The Paradox
Replacing initrd with initramfs in GRUB2 isn’t that hard. If I use the same name for both files (not at the same time), it would look for the file name in the config and find the file. Easy, right? But then, the kernel messages pop up, and it fails to boot reading something like: Failed to switch root: Specified switch root path /sysroot does not seem to be an OS tree. os-release file is missing.

Needless to say, I checked out the contents of /sysroot: empty. There should be an os-release file in /etc. Reading up on “Sysroot”, it’s supposed to mount the OS directory structure, which is probably why it’s telling me that it’s missing some files.

Sysroot
Here’s where I got lost: The directory structure is inside initramfs, right?. But in order to run initramfs through GRUB2, I need to mount the directory structure to Sysroot. That means I can only reach /sysroot from inside initramfs. But I can’t mount initramfs, because I need the OS-release file in /sysroot. I also can’t mount the directories inside initramfs, because it’s an image file. Can you see my paradox? How am I supposed to mount to /sysroot, when this requires something inside initramfs itself? I’ve already tried the root= kernel parameter with a PARTUUID or LABEL, but I can’t use UUIDs since it’s vFAT over UEFI.

Did I miss something here? Am I even supposed to use initramfs, when using bootable USB RAMDisks? If not, should I look into splitting up initrd into multiple files? How do I even do this?
NOTE: We are already using the highest possible compression (XZ level 9). I’ve tried splitting initrd before, but I have not been able to do it properly.

I personally don’t like asking for help, but when all the Google search results are in purple, I may need a point in the right direction. A lot of systems are not working after our upgrade to F:34 and I would really like to get this fixed. Does anybody know how to use Dracut properly? Anyone with experience in generating initramfs images? Why is my /sysroot not already mounted?

Help is much appreciated, thank you.

I would suggest serving your rootfs off a NFS server rather than putting 500+ MB in the initramfs. If you configure the rootfs on the NFS server to be read-only (by editing /etc/sysconfig/readonly-root), I think your client machines could share the same OS image. Some parts of the file system will be overlaid with a tmpfs mount (see /etc/rwtab.d) so that they will work much the same as if the image were in a RAMDISK. I wrote a howto on setting up such a system, but it is quite dated.

I would like to find a solution that doesn’t require our clients to set up extra infrastructure components. Being able to boot entirely into RAM from a USB drive is a critical feature for us.

Also, when generating the initramfs using Dracut, the file size is indeed closer to 30MB (initramfs) than 500MB (initrd). The smaller filesize is one of the reasons I’m looking into initramfs.

When using this command:

lsinitramfs initramfs-5.13.7-200_34.img | grep os-release

It returns these values:

etc/os-release
usr/lib/os-release

The os-release is missing in /sysroot during boot, because it’s not being mounted. This is because the filesystem is just a vFAT (USB) containing this initramfs. The USB drive itself is not a root filesystem!

My problem: I can’t mount these files, because I cannot reach inside initramfs during GRUB2, because it’s an IMG-file. How do I mount the contents of initramfs to /sysroot?