How to make a custom ISO image with mkimage

From Alpine Linux
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This document explains how to build a custom ISO image using the new mkimage scripts located in aports directory.

Prerequisites

First make sure we have the needed tools

apk add alpine-sdk alpine-conf syslinux xorriso squashfs-tools grub grub-efi doas

For efi you should add the following:

apk add mtools dosfstools grub-efi

Create a user (e.g. build) and add them to the abuild group:

adduser build -G abuild

Give the user root-like permissions:

vi /etc/doas.d/doas.conf

permit :abuild
permit persist :abuild

Change to the build user:

su - build

Then create signing keys (-i installs them in /etc/apk/keys which is required for later)

abuild-keygen -i -a

Tip: Make sure your public keys are placed in /etc/apk/keys/ (example: build-xxxxxxxx.rsa.pub)

ls /etc/apk/keys/

Clone (or update) the git repository.

git clone --depth=1 https://gitlab.alpinelinux.org/alpine/aports.git


Make sure the apk index is up to date (so apk can find the packages):

doas apk update

Make sure your /tmp is large enough. If you have the default 1GB /tmp, then create a local one with:

mkdir -pv ~/tmp
export TMPDIR=~/tmp

Configuration

The mkimg scripts are shipped with pre-configured profiles.

The format is mkimg.$PROFILENAME.sh

In order to have a custom ISO, you should create your own mkimg.$PROFILENAME.sh script.

This is an example used to make a ZFS module, overlayfs (which enables r/w mode for /lib/modules), a serial console output and some other useful apks to build a simple NAS:

export PROFILENAME=nas
cat << EOF > ~/aports/scripts/mkimg.$PROFILENAME.sh
profile_$PROFILENAME() {
        profile_standard
        kernel_cmdline="unionfs_size=512M console=tty0 console=ttyS0,115200"
        syslinux_serial="0 115200"
        kernel_addons="zfs"
        apks="\$apks iscsi-scst zfs-scripts zfs zfs-utils-py
                cciss_vol_status lvm2 mdadm mkinitfs mtools nfs-utils
                parted rsync sfdisk syslinux util-linux xfsprogs
                dosfstools ntfs-3g
                "
        local _k _a
        for _k in \$kernel_flavors; do
                apks="\$apks linux-\$_k"
                for _a in \$kernel_addons; do
                        apks="\$apks \$_a-\$_k"
                done
        done
        apks="\$apks linux-firmware"
}
EOF

Set the script as executable:

chmod +x ~/aports/scripts/mkimg.$PROFILENAME.sh

Making packages available on boot

A package may be made available in the live system by defining the generation of an apkovl which contains a corresponding /etc/apk/world file, and adding that overlay definition to the mkimg-profile, e.g. with `apkovl="genapkovl-mkimgoverlay.sh"`

Note that to *use* your added apks, you have to install them, with apk add.

The definition may be done as in the genapkovl-dhcp.sh example. Copy the relevant parts (including the rc_add lines) into a `genapkovl-mkimgoverlay.sh` file and add the package(s) that should be installed in the live system on separate lines in the file contents for /etc/apk/world.

cp ~/aport/scripts/genapkovl-dhcp.sh ~/aport/scripts/genapkovl-mkimgoverlay.sh

Edit the file to add:

...
mkdir -p "$tmp"/etc/apk
makefile root:root 0644 "$tmp"/etc/apk/world <<EOF
alpine-base
<apk1-service>
<apk2-service>
EOF

...
rc_add <apk1-service> boot
rc_add <apk2-service> boot
...

in the relevant locations.

Then edit the profile build script above and add:

apkovl="aports/scripts/genapkovl-mkimgoverlay.sh"

immediately after the last apks= line.

Create the ISO

mkimage.sh [--tag RELEASE] [--outdir OUTDIR] [--workdir WORKDIR] [--arch ARCH] [--profile PROFILE] [--hostkeys] [--simulate] [--repository REPO] [--extra-repository REPO] [--yaml FILE] mkimage.sh --help options: --arch Specify which architecture images to build (default: x86_64) --hostkeys Copy system apk signing keys to created images --outdir Specify directory for the created images --profile Specify which profiles to build --repository Package repository to use for the image create --extra-repository Add repository to search packages from --simulate Don't execute commands --tag Build images for tag RELEASE --workdir Specify temporary working directory (cache) --yaml known profiles: ali rpi uboot base minirootfs standard vanilla extended virt xen

Tip: You can use the --repository option multiple times, which is very useful when mixing local and official repositories. The --extra-repository option is there only for backward-compatibility.

Create an iso directory in your home dir:

mkdir -p ~/iso

Then create the actual ISO. In this example we will use the edge version x86_64:

sh aports/scripts/mkimage.sh --tag edge \ --outdir ~/iso \ --arch x86_64 \ --repository https://dl-cdn.alpinelinux.org/alpine/edge/main \ --profile $PROFILENAME


Notes:

  • If you want to make a customized installer, you need to create .default_boot_services which will cause mkinitfs to create the defaults for the live image.
  • Several parts of this doc can be automated with a script, like the repository/arch/outdir settings.

Those steps are left to you and your imagination :)

Testing your ISO image

QEMU is useful for a quick test of your newly created ISO image. This ISO build process has been tested to work and generate an ISO with auto-installed APKs as of Nov 20, 2023 with Alpine edge.