/cleanroom

Cleanroom Arch Linux installs

Primary LanguagePerlGNU General Public License v3.0GPL-3.0

Cleanroom

Cleanroom is a script that I use to create clean images of Arch Linux installations for bare-metal machines and containers. While you can use this set of scripts to set up any Arch Linux image you want, the type-baremetal one in this repository enables me to do (semi-) stateless systems, close to the stateless systems proposed by the systemd team:

http://0pointer.net/blog/revisiting-how-we-put-together-linux-systems.html

I put up some notes on the process that took me to this point here:

https://omitframepointer.wordpress.com/

(And yes, it is really hard to find a name that is geeky and available at wordpress.com;-)

(Semi-) Stateless Systems

While Lennarts blog post is about stateless systems that basically "forget" everything on each reboot, my setup does keep /var around. I do want to keep my logs.

So my semi-stateless system has the following changes compared to a "normal" Arch Linux installation:

  • The pacman DB is in /usr/share/pacman/db. That is to keep the pacman DB in sync with the actual contents of /usr.

  • /usr not be written to ever (as far as I know;-).

  • / is a tmpfs that is empty on each reboot.

  • There is a /usr/lib/modules/boot directory with the initrd, kernel, a small tarball used to populate the root filesystem and some additional files with information for the boot loader.

  • It will overwrite some systemd-binaries with versions newer than the ones found in arch linux. This should no longer be necessary once the next systemd release (220) hits arch linux.

  • Mkinitcpio is changed to use the systemd (from arch linux) and sd-stateless hooks (the latter is in the type-baremetal folder). This makes sure the initrd will unpack /usr/lib/modules/boot/rootfs.tar into the tmpfs before switching root.

The unpacking is necessary since the machine-id needs to be there really early or systemd will create a new one and will also stop the boot from failing due to dbus being started before its configuration is in place.

Directory layout:

The main script is ./preprocess.pl, which will turn container.conf files into container.sh files which can then be run to do the actual work.

The commands subfolder holds most of the possible commands available for use in the container.conf files.

All other folders contain descriptions on how to set up one image. "base" is the first image, all others are directly or indirectly derived from "base".

The images that go onto real hardware/are used for a container are prefixed with "system-", all others with "type-" as they contain a common basis for a whole type of machines.

E.g. "system-example" is derived from "type-baremetal" which in turn is derived from "base".

Commands for container.conf

Most available commands are stored in the commands subfolder. In addition there are two more commands "SH" and "POST". SH will put its arguments verbatime into container.sh while "POST" will make sure that its arguments will be run at the end of the image creation of this and all derived images.

Examples:

SH echo Test

will put "echo Test" into container.sh

POST SH echo Test

will put "echo Test" at the end of container.sh (and all container.sh files that are derived from this one).

How to create an image?

Run ./preprocess.pl on the container.conf file you want to create. Check the container.sh file that is created. Run that.

Pitfalls

This is a incomplete list of things that will most likely go wrong if you try this at home:-)

  • There is no dependency handling at this time. You need to make sure the base image was successfully created before running container.sh.

  • The container.sh script tries to create btrfs subvolumes in /mnt/btrfs-playground, so you need a btrfs subvolume there

  • ARCH_PACSTRAP and ARCH_PACMAN have config files in commands/config/ARCH_PACSTRAP that you will most likely need to edit

  • The configuration is probably wrong for your use cases, so you will need to go over all files in commands/config and the images with a fine-toothed comb.

What to do with the images?

Container images

Once you have images you can run them with systemd-nspawn.

Bare-metal images and stateless boots

Or you can install these onto a VM/real hardware. The images assume the following layout of the harddisk of that machine:

  • An EFI boot partition (using gummiboot or similar boot loader, mounted on /boot)
  • A partition with label "swap_c" (which will be used as encrypted swap)
  • A btrfs partition mounted on /mnt/btrfs (with option subvolid=0)
  • Optionally you can have more partitions/drives. These need to be configured in the container.conf script (or in units installed by that file) or they will not be available.

This btrfs partition needs to contain a snapshot called var:<name>:<vendor>:<arch>.

Please make sure the <name> part is unique and no two var snapshots share the name.

Initial setup

Go into /mnt/btrfs-playground/system-example-<timestamp>, tar up the var subfolder there (as root) and extract that into the var:... snapshot.

Transfer the actual System

Put the btrfs subvolume found in /mnt/btrfs-playground/system-example-<timestamp>/usr onto the target machine and make sure to turn it into a read-only snapshot named usr:<vendor>:<arch>:<timestamp>.

This can be done using btrfs send/receive to transfer the /mnt/btrfs-playground/system-example-<timestamp>/usr to the target machine and then doing btrfs subvol snapshot -r usr usr:<vendor>:<arch>:<timestamp> there.

Make it bootable

THIS STEP CAN MAKE ALL INSTALLED OPERATING SYSTEMS UNBOOTABLE, MAKE SURE YOU KNOW WHAT YOU ARE DOING, HAVE BACKUPS AND A RESCUE DISK HANDY

The type-baremetal image contains a script /usr/local/bin/update-boot.pl.

This script will scan /mnt/btrfs for var:... and usr:... subvolumes. It will match up var:... and usr:... snapshots based on <vendor> and <arch>.

The script will then copy the kernel and initrd from all usr:.../lib/modules/boot into the EFI boot partition.

Then it will proceed to create boot loader entries for each combination of <name> (from var:...) and <timestamp> (from usr:...), using information found in usr:.../lib/modules/boot/additional_args and usr:.../lib/modules/boot/root_device.

Afterwards it will clean out all files it does not need anymore. This might remove files necessary for other OSes! You have been warned;-)