autoarch

2019-11-11 13:50:00

Unattended installation of Arch Linux exactly as you like it

As a software contractor, I work on a variety of codebases and like to maintain a level of isolation between them. I’m going to talk about one of the ways in which I achieve that, which is to have an easy-to-use method which allows me to rapidly replicate the environment I work in.

All of the source code for this project is free to use and licensed under GPLv2. You can clone it from https://git.sr.ht/~esotericnonsense/autoarch.

Below I will describe some of the work that went into creating autoarch.

Using archiso

The Arch Linux development team have created a tool named mkarchiso, along with a set of scripts that can be used to build bootable Arch Linux ISOs.

The repository is available to clone or view at https://git.archlinux.org/archiso.git. It can also be installed via pacman -S archiso.

Within the repository, in the scripts subdirectory, two build scripts are available.

The releng script is used to create the full automated ISO builds which are made available at the download page.

We are personally interested in the baseline script, which produces a minimal ISO with only the packages from the base group: https://www.archlinux.org/groups/x86_64/base.

Getting started

$ pwd
/home/esotericnonsense/git/archiso
$ cd configs/baseline
$ ls
build.sh  isolinux  mkinitcpio.conf  syslinux
$ vim build.sh

The baseline build script contains a number of functions that use the mkarchiso script in order to produce a working ISO.

Note that as of tag v43, the baseline script does not actually function as is due to the removal of the linux package and its’ dependencies from the base group. In order to fix this, add the following line to the make_basefs() function:

mkarchiso -v -w "${work_dir}" -D "${install_dir}" -p linux install

A patch is also available to fix the issue at https://git.esotericnonsense.com/pub/archiso.git/commit/?h=esoteric/baseline-fix. It has been submitted to the arch-releng mailing list.

An image can be built by running:

$ sudo ./build.sh

The work/ and out/ folders will be populated with the working state and final ISO file respectively. Remember to remove these folders before rebuilding.

Pre-requisite modifications

Automatic login

By default, the baseline archiso does not automatically login; one must login as the root user after booting. To rectify this, we can add a make_autologin() function to the build script.

# Enable autologin on tty1
make_autologin() {
    local gettydir
    getty_dir="${work_dir}/airootfs/etc/systemd/system/getty@tty1.service.d"
    mkdir -p "${getty_dir}"
    cat << EOF > "${getty_dir}/autologin.conf"
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear %I 38400 linux
EOF
}

At the bottom of the build script, add the following line:

 run_once make_setup_mkinitcpio
+run_once make_autologin
 run_once make_boot

Automatic network initialization

By default, the baseline archiso does not connect to any network.

The baseline image includes systemd, so we can rectify this by adding a systemd-networkd hook.

# Enable DHCP networking on the ens1 interface
make_networking() {
    local iface
    iface="ens1"
    cat << EOF > "${work_dir}/airootfs/etc/systemd/network/20-wired.network"
[Match]
Name=${iface}

[Network]
DHCP=ipv4
EOF

    mkarchiso -v -w "${work_dir}" -D "${install_dir}" -r \
        "systemctl enable systemd-networkd.service systemd-resolved.service" run

    # Ensure the network is up when we hit the shell prompt
    mkarchiso -v -w "${work_dir}" -D "${install_dir}" -r \
        "systemctl enable systemd-networkd-wait-online.service" run
}

Again, at the bottom of the build script, add the following line:

 run_once make_setup_mkinitcpio
+run_once make_networking
 run_once make_boot

Pacman

By default, the baseline archiso has no mirrors listed and so pacman is therefore unable to install anything. We can fix this:

# Uncomment the servers in the mirrorlist and randomise their order
make_pacman_mirrorlist() {
    local mirrorlist
    mirrorlist="${work_dir}/airootfs/etc/pacman.d/mirrorlist"
    cat "${mirrorlist}" | grep "Server" | sed 's/^#Server/Server/g' | sort -R \
        > "${mirrorlist}.new"
    mv "${mirrorlist}.new" "${mirrorlist}"
}
 run_once make_setup_mkinitcpio
+run_once make_pacman_mirrorlist
 run_once make_boot

We also need to initialize pacman-key so that signed packages can be verified correctly.

# Initialize pacman-key
make_pacman_key_init() {
    mkarchiso -v -w "${work_dir}" -D "${install_dir}" \
        -r "pacman-key --init" run
    mkarchiso -v -w "${work_dir}" -D "${install_dir}" \
        -r "pacman-key --populate archlinux" run
}
 run_once make_setup_mkinitcpio
+run_once make_pacman_key_init
 run_once make_boot

Automatic installation

Now that the above has been taken care of, we can get down to the business of actually having an automatic installation script running.

The following code provides for two options; either cloning the install script and building it into the ISO itself at build time; or cloning the install script on boot/runtime. The latter method may be useful if the installer is expected to change often.

You may wish to change the URL cloned to your own; the one specified here is not guaranteed to remain stable.

make_clone_installer_at_run_time() {
    cat << EOF > "${work_dir}/airootfs/root/autorun.sh"
#!/usr/bin/env bash
set -uxo pipefail
git clone "https://git.esotericnonsense.com/pub/autoarch.git" \
    "\${HOME}/autoarch"
bash "\${HOME}/autoarch/install/main.sh"
EOF
}

make_clone_installer_at_build_time() {
    git clone "https://git.esotericnonsense.com/pub/autoarch.git" \
        "${work_dir}/airootfs/root/autoarch"
    cat << EOF > "${work_dir}/airootfs/root/autorun.sh"
#!/usr/bin/env bash
set -uxo pipefail
bash "\${HOME}/autoarch/install/main.sh"
EOF
}

# Set up automatic install
make_setup_automatic_install() {
    mkarchiso -v -w "${work_dir}" -D "${install_dir}" \
        -p arch-install-scripts -p git install

    # Automatically run the installer on boot
    cat << EOF > "${work_dir}/airootfs/root/.profile"
#!/usr/bin/env bash
set -uxo pipefail

if [[ \$(tty) == "/dev/tty1" ]]; then
    bash "\${HOME}/autorun.sh"
fi
EOF

    # Option 1
    make_clone_installer_at_run_time
    # Option 2
    #make_clone_installer_at_build_time

    chmod +x "${work_dir}/airootfs/root/autorun.sh"
}
 run_once make_setup_mkinitcpio
+run_once make_setup_automatic_install
 run_once make_boot

The install script itself

Now that the above has been taken care of, we can write the actual autoinstall script, which if you have followed the instructions above, should be placed in /root/autoarch/install/main.sh on the finalised ISO.

This however, is out of scope for this blog article. A good idea would be to view the install script used by autoarch itself, a link to which is given at the top of this post.

esotericnonsense (Daniel Edgecumbe)

November 11, 2019