Creating the Anaconda boot.iso with lorax

Fedora 22 is almost here, so I thought I'd write a couple posts on how to use lorax and livemedia-creator to create bootable Fedora images. I'll start with lorax. It is used to create the Anaconda boot.iso which is used to install systems using a network connection. You can also automate your installations by using the boot.iso with a kickstart file. Lorax is part of the current release-engineering workflow and is used to create the boot.iso/netinst Anaconda installer image. Pungi also uses the results from lorax when creating the DVD including package repositories.

Lorax documentation can be found here and is currently a work in progress. The command line arguments are best documented by lorax --help right now. Lorax source is available on github and is maintained by Will Woods and I.

Lorax Installation

Installation is easy, just run sudo dnf install lorax from a Fedora 22 system and all the needed dependencies will be installed.

It is best to use the version of lorax that matches the Fedora release you are creating the iso for. It doesn't have a complex set of dependencies, but sometimes the templates have release specific logic in them.

Create a boot.iso

To create a boot.iso you need to pass lorax a few things: Product name, version, release, and the repositories to install the rpms from. You can speed up repeated builds by using a local proxy and passing it to lorax using the --proxy argument.

Building a simple generic boot.iso is as easy as running:

sudo -i
setenforce 0
lorax -p Fedora-Generic -v 22 -r 22 \
- -s http://dl.fedoraproject.org/pub/fedora/linux/development/22/x86_64/os/ \
- -s http://dl.fedoraproject.org/pub/fedora/linux/updates/testing/22/x86_64/ \
./results/

The new boot.iso will be in ./results/images/boot.iso with the rest of the build results (things like the kernel and initramfs images) also in ./results/. You can quickly test the new iso with:

qemu-kvm -m 1024 -smp 2 -cdrom ./results/images/boot.iso

How does Lorax work?

Lorax installs rpms into a directory, configures the system, and then removes files that aren't needed. It then creates a squashfs filesystem of the directory and builds a bootable iso around it using a kernel and a generic initramfs. The kernel and initramfs are independent of the host system, the boot.iso will use whatever kernel is installed from the selected repositories.

Lorax uses templates to select which packages are installed, what to remove after the rpm installation, how to create the iso, and the directory tree containing the images.

The templates are Mako templates with some custom commands added to make it easier to install packages and remove files. You can run arbitrary python code inside the template by using the <% %> tags or control structures. Templates are stored in /usr/share/lorax/ or in a location specified by passing a custom --config file that points to a new location.

Installing packages

Lorax first uses runtime-install.tmpl to select packages to be installed. It mostly contains installpkg commands, with some arch specific tests in a few places. The end of it must be run_pkg_transaction to install the packages into the installroot.

A bit of the template looks like this:

installpkg anaconda anaconda-widgets
installpkg kexec-tools-anaconda-addon
## anaconda deps that aren't in the RPM
installpkg tmux
installpkg iscsi-initiator-utils

## kernel and firmware
installpkg kernel
installpkg grubby
%if basearch != "s390x":
    installpkg *-firmware
    installpkg b43-openfwwf
%endif

## actually install all the requested package
run_pkg_transaction

Post-installation setup

After all the packages are installed (709 of them as of this writing), the runtime-postinstall.tmpl template is run. It modifies the contents of the installroot, handling things like settings up the yum repos for Anaconda, setting up configuration files for various things, enabling anaconda at boot time using systemd and tmux, disabling systemd services that are unneeded or that will interfere with Anaconda.

eg. setting up sshd for the boot.iso:

## set up sshd
install ${configdir}/sshd_config.anaconda etc/ssh
install ${configdir}/pam.sshd etc/pam.d/sshd
install ${configdir}/pam.sshd etc/pam.d/login
install ${configdir}/pam.sshd etc/pam.d/remote

## Make logind activate anaconda-shell@.service on switch to empty VT
symlink anaconda-shell@.service lib/systemd/system/autovt@.service
replace "#ReserveVT=6" "ReserveVT=2" etc/systemd/logind.conf

Cleanup and file removal

At this point the installroot is complete, but it contains quite a few extras that really aren't needed at installation time. In order to reduce the size of the boot.iso lorax runs the runtime-cleanup.tmpl template on it, and removes files and packages that are unneeded. For example:

## no sound support, thanks
removepkg alsa* flac gstreamer-tools libsndfile pulseaudio* sound-theme-freedesktop
removepkg midisport-firmware

## remove unused themes, theme engines, icons, etc.
removefrom gtk2 /usr/${libdir}/gtk-2.0/*/{engines,printbackends}/*
removefrom gtk2 /usr/share/themes/*

It also removes many of the kernel modules that aren't needed during installation, things like joystick, bluetooth and sound.

Once all the extras are removed lorax creates a squashfs image containing an ext4 filesystem. In Fedora 22 this is copied to LiveOS/squashfs.img and is used as the stage2 of the boot process.

Iso creation

Lorax then creates new generic initramfs images using dracut for each of the kernels installed in the installroot. It also generates the upgrade.img that is used by fedup in the upgrade process.

The final step is for lorax to execute an architecture specific template, like x86.tmpl, to create the iso bootloader directory, install kernels and initrds. The bootloader templates from /usr/share/lorax/config_files/ are modified to show the Product and Version that was passed to lorax. Finally mkisofs is called to create the boot.iso and the .treeinfo is written to the result's directory tree.

The results directory will look like this:

results/:
.discinfo EFI  images  isolinux  LiveOS .treeinfo

results/EFI:
BOOT

results/EFI/BOOT:
BOOTX64.EFI  fonts  grub.cfg  grubx64.efi  MokManager.efi

results/EFI/BOOT/fonts:
unicode.pf2

results/images:
boot.iso  efiboot.img  macboot.img  pxeboot

results/images/pxeboot:
initrd.img  upgrade.img  vmlinuz

results/isolinux:
boot.msg   initrd.img    isolinux.cfg  libcom32.c32  memtest     upgrade.img   vmlinuz
grub.conf  isolinux.bin  ldlinux.c32   libutil.c32   splash.png  vesamenu.c32

results/LiveOS:
squashfs.img

Running from a git clone

If you want to run lorax from a git clone instead of using the release package you need to setup the paths correctly, and pass it a configuration file that points to the ./share/ directory inside your clone.

Create a file named lorax.conf that with this in it:

[lorax]
sharedir=/home/user/lorax/share

Replace the path with the path to your git clone of the lorax source.

Now you can run lorax directly from the clone by setting the PATH and PYTHONPATH environmental variables:

PATH=./src/sbin/:$PATH PYTHONPATH=./src/ ./src/sbin/lorax
lorax -p Fedora-Generic -v 22 -r 22 \
- -s http://dl.fedoraproject.org/pub/fedora/linux/development/22/x86_64/os/ \
- -s http://dl.fedoraproject.org/pub/fedora/linux/updates/testing/22/x86_64/ \
- --config=lorax.conf \
./results/