Design principles
- Relatively simple design
- bash script: components, configurations, recipes
- Alpine Linux chroot install script
- debootstrap and ansible for setting up the VM image
- systemd-nspawn for building in a sandbox
- Isolated builds
- most build tasks executed in systemd-nspawn sandbox based on Alpine Linux
- read-only view of the configurations
- Lightweight
- container sandbox much faster than full OS virtualization
- Fast
- building mostly in tmpfs (requires 8-16 GB of RAM depending on OS size)
- if not enough memory is provided, builds on disk (still needs 2-4 GB of RAM)
- CI/CD friendly
- dependency tracking -> incremental rebuilds
- cached task inputs and outputs
- Few dependencies
- basic core Linux userspace utilities / busybox + systemd
- Can produce a VM for building itself
- a bit slower, depending on the build target, up to 16GB of VM RAM needed
Basic structure
- alpine-installer - derived from https://github.com/alpinelinux/alpine-chroot-install - installer for the 'builder' task
- build.sh - the "brains", a build system for various components
- configs/
- assets/
- shared/
- *.sh - the scripts for building components (e.g. busybox or kernel), usually launches sandboxes for simple build tasks
- *.conf - default INI style configuration files for components (defines e.g. component version, source url, checksum + other stuff)
- componentname/* - other component related files needed to build the component
- configurations/
- configurationname/*.conf - INI style configuration files for components (overrides
configs/shared/*.conf
), the idea is to provide a shared special config for multiple recipes - configurationname/componentname/* - other component related files needed to build the component (overrides
configs/shared/componentname/*
)
- configurationname/*.conf - INI style configuration files for components (overrides
- recipes/
*.sh - "build plan" for a distro image- recipe/*.conf - INI style configuration files for components, overrides
configs/shared/*.conf
andconfigs/configurations/*.conf
, special configs for a specific recipe - recipe/recipename/componentname/* - other component related files needed to build the component (overrides
configs/shared/componentname/*
andconfigs/configurations/configurationname/componentname/*
)
- configs/
graph TB
subgraph "Configuration structure"
configs --> assets
configs --> shared
shared --> sharedsh[:comp:.sh]
shared --> sharedconfigs[:comp:.conf]
shared --> shcomponent[:comp:]
configs --> configurations --> configuration[:configuration:]
configuration --> csh[:comp:.sh]
configuration --> cconfigs[:comp:.conf]
configuration --> ccomponent[:comp:]
configs --> recipes
recipes --> rsh[:recipe:.sh]
recipes --> recipe[:recipe:]
recipe --> resh[:comp:.sh]
recipe --> reconfigs[:comp:.conf]
recipe --> recomponent[:comp:]
end
Components
The component script describes how the component is built and installed.
Each component.sh
script is accompanied with a component.conf
The script and the default configuration is located in configs/shared
.
Fields
Each component.conf
file must define
VERSION=<versionstring>
Each component.conf
file may also define
SRCURL=<source url, if downloading files with 'dobuild pkg'>
SRCCHECKSUM=<sha1sum of the downloaded source file>
HOMEPAGE=<link to the upstream download page, check for updates manually>
Each component.sh
file must define
function build() { ... } -- builds the component
Each component.sh
file may also define
function init() { ... } -- define environments
- DEPS="" -- space separated list of elements{param, params}
- TARGET=<output of the component build script,
located in packages/{build,out},
by default depends on where the config override is found>
function fetch() { ... } -- fetches the source file from SRCURL
function description() { ... } -- prints the component description
function reconfigure() { ... } -- functionality for reconfiguring the component
function install() { ... } -- functionality for installing the component
graph TB
subgraph "Component dependencies"
start --> distova
start --> bootdisk
distova --> userstorage
distova --> bootvmdk
bootdisk_prepare --> image_application
bootdisk --> initramfs
bootdisk --> kernel
bootdisk --> linux_firmware
bootvmdk --> metadata
bootvmdk --> bootdisk
image_application --> image_custom
image_application --> image_platform
image_application --> preload_pkgs
image_application --> preload_debs
image_base --> preload_debs
image_platform --> squashfstools
image_platform --> image_base
image_platform --> preload_pkgs
image_platform --> vboxguest
image_platform --> preload_debs
initramfs --> metadata
initramfs --> vbox
kernel --> linux_firmware
metadata --> bootdisk_prepare
metadata --> image_application
metadata --> kernel
vbox --> vboxguest
vbox --> kernel
end
graph TB
subgraph "Not in use anymore"
bootdisk_compress --> bootdisk
end
graph TB
subgraph "Initramfs utitilies"
initramfs --> busybox
initramfs --> column
initramfs --> dialog
initramfs --> e2fsprogs
initramfs --> htop
initramfs --> mc
initramfs --> nbdclient
initramfs --> ntfs3g
initramfs --> squashfstools
end
The following are extracted from the sources with:
grep description -A1 *|grep echo|sed 's/^/ * /g;s/- echo "/: */g;s/"$/*/g'|sort
Initramfs + utils
- busybox: Compiles busybox (variant: $COMPONENTCONFIG). Busybox provides a wide set of core utilities used in the initramfs systems.
- column: Compiles 'column'. The utility is used for pretty printing stuff in the initramfs.
- dialog: Compiles 'dialog'. The utility is used for the initramfs menu system.
- e2fsprogs: Compiles 'dumpe2fs', 'e2fsck', 'mke2fs', and 'resize2fs'. The utilities are used for manipulating ext4 systems in the initramfs.
- gdisk: Compiles 'gdisk'. The utility is used to fix the partition table on USB sticks larger than the default image.
- htop: Compiles 'htop'. The utility is available in the initramfs.
- initramfs: Build the initramfs. Always contains basic Linux terminfo, build metadata file, configured kernel modules and initramfs configs and scripts
- mc: Compiles 'mc' and 'mcedit'. The utilities are available in the initramfs.
- nbdclient: Compiles 'nbd-client'. The utility is used to mount NBD shares (e.g. PXE boot) in the initramfs.
- ntfs3g: Compiles 'ntfs-3g'. The utility is used to mount ntfs drives in the initramfs.
- squashfstools: Compiles 'mksquashfs' and 'unsquashfs'. Could be used in a rescue initramfs. The 'mksquashfs' utility is being used for generating compressed spawn-container images.
General infrastructure
- bootdisk_prepare: Prepares the bootdisk. This is the main disk for virtual machines ('userstorage' is the other). For USB media, this contains everything. The size of the image and the partitions varies depending on the size of the rootfs. The partition layout is a MBR+GPT hybrid. Note that the configuration is split in multiple .conf files and refers to the previous stages.
- bootdisk: Builds a bootable disk image using syslinux as a bootloader, provided initramfs and kernel + amd/intel ucode blobs + other configured boot disk contents.
- bootvmdk: Converts the RAW bootdisk image into a vmware vmdk file, version 4.
- builder: Builds a relatively small squashfs compressed Alpine installation used for sandboxing further build stages.
- distova: Generates a distributable OVA file from the bootvmdk + userstorage combo. Also fixes the OVA version number since vmware can't import files generated with the same vmware tools, yay.
- metadata: Generates the metadata file listing build specific key-values. The metadata also considers git history and unstaged files so a rebuild is needed after toying around with the local repository.
Platform, application, and other images
- image_application: Builds the 3rd stage target Debian system (variant: $COMPONENTCONFIG) based on Ansible rules & 'platform' image. Stores a deb cache in builddir/cache or uses a previous stage deb cache. Compresses the output with squashfs.
- image_base: Builds the 1st stage target Debian system using debootstrap. The image contains opensshd & ansible for remote configuration and dbus/systemd parts for systemd-nspawn local administration. Stores a deb cache in builddir/cache. Compresses the output with squashfs.
- image_custom: Builds a custom OS image. Compresses the output with squashfs.
- image_platform: Builds the 2nd stage target Debian system (variant: $COMPONENTCONFIG) based on Ansible rules & 'base' image. Stores a deb cache in builddir/cache or uses a previous stage deb cache. Compresses the output with squashfs.
- userstorage: Generates an empty disk with a single full size ext4 partition for user storage. The disk image is then converted to VMDK.
Kernel and modules
- kernel: Compiles the Linux kernel (variant: $COMPONENTCONFIG). The resulting kernel and modules are stored in builddir/kernel and dstdir/kernelmodules.
- linux_firmware: Builds a squashfs image of the redistributable firmware, based on kernel org sources and gentoo ebuild.
- nvidia: Compiles the proprietary nvidia kernel modules to dstdir/kernelmodules.
- vbox: Compiles the virtualbox guest utils kernel modules to dstdir/kernelmodules. Sadly the mainline versions are incompatible with the userspace guest utils.
Other
- bootdisk_compress: Compresses the boot disk for release. The empty user partition mostly contains zeros so there are plenty of reasons to compress.
- openjfx: Compiles Alpine/musl compatible OpenJFX runtime.
- preload_debs: Preloads and caches list of deb files to speed up subsequent builds
- preload_pkgs: Preloads and caches list of files to speed up subsequent builds.
- vboxguest: Extracts the guest utils (both kernel and user space) from Virtualbox guest ISO distribution.
Configurations
Located in configs/configurations
.
Shared sets of configurations files
- buildvm: configuration for building a VM that can be used to run build.sh on any system
- minimal: a definition of busybox{minimal} used by utuvm-usb && utuvm-vbox
- rescue: a definition of initramfs, originally intented for rescue shells
- unixcourse: a definition of lightweight builder image for the UNIX course
- usb: utuvm-usb specific bootdisk, bootdisk_prepare, image_platform (platform applications), initramfs, and kernel
- vm: utuvm-vm specific bootdisk, bootdisk_prepare, image_platform (platform applications), initramfs, and kernel
Recipes
Located in configs/recipes
.
- utuvm-builder: configuration for building a VM that can be used to run build.sh on any system
- default target: distova
- utuvm-usb: defines the USB platform (native x86-64 Linux)
- default target: bootdisk_compress
- utuvm-vbox: defines the virtual platform (virtualbox, vmware, qemu, ...)
- default target: distova
Platforms
Hardware platforms
Located in configs/recipes
, configs/shared/image_platform/
, configs/configurations/{buildvm,vbox,usb}
.
- USB: recipe utuvm-usb, image_platform usb
- VM: recipe utuvm-vbox, image_platform virtual, vbox (virtualbox kernel drivers)
- Build VM: recipe utuvm-builder, image_platform buildvm
Application platforms
Located in configs/recipes
, configs/shared/image_application/
.
plain
: does not contains any application specific stuff, only the platform imagejava
: contains the platform + Java application imageminimega
: contains the platform + CPP & Web & mobile & declarative application imageslatex
: contains the platform + Java application imagemega
: containsjava
+minimega
Deprecated application platforms
- CPP: contains the platform + C/C++ application images
- Webmob: contains the platform + Web & mobile application images
Ansible configuration
Base image
Doesn't actually use Ansible. Constructed with debootstrap. See
configs/shared/image_base.conf
for the package list.
Platform image
The "platform" image contain all common functionality for a VM or USB distro.
See configs/shared/image_platform/
(and also the overriding configs
in configs/configurations/*
). Ansible files can be searched with find configs/ -type f -name '*.yaml'|sort
.
Contents of configs/shared/image_platform/
:
Location | Description |
---|---|
. |
contains the main ansible script: playbook-install-platform.yaml |
library |
contains the ansible scripts |
systemfiles |
system-wide (root) owned files - copied by playbook-conf-basesystem.yaml |
systemfiles/common |
misc stuff copied to /etc/ |
systemfiles/usrlocal |
scripts copied to /usr/local/ , e.g. backgrounds, system/helper scripts |
userfiles |
files for /home/utu - copied by playbook-conf-user.yaml |
userfiles/common |
bookmarks, xorg startup script, desktop entries |
userfiles/manuals |
manuals (pdf) |
userfiles/xfce_config |
xfce configuration |
Application image
The high level functionality (e.g. Java SDK) belongs to the "application" image.
See configs/shared/image_application/
(and also the overriding configs
in configs/configurations/*
). Ansible files can be searched with find configs/ -type f -name '*.yaml'|sort
.
Ansible library
library/playbook-clean-system.yaml
library/playbook-conf-basesystem.yaml
library/playbook-conf-user.yaml
library/playbook-install-seadrive.yaml
library/playbook-install-slim.yaml
library/playbook-postconf-usb.yaml
library/playbook-postconf-virtual.yaml
library/playbook-prepare-common-usb.yaml
library/playbook-prepare-common-virtual.yaml
library/playbook-prepare-common.yaml
playbook-conf.yaml
playbook-prepare-usb.yaml
playbook-prepare-virtual.yaml
System/common
systemfiles/common/20-wired.network
systemfiles/common/fixnet.service
systemfiles/common/locale.sh
systemfiles/common/pulsevolume.service
systemfiles/common/taustapun.jpg
systemfiles/common/taustasin.jpg
System/usrlocal
systemfiles/usrlocal/configurator.sh
systemfiles/usrlocal/fixnet.sh
systemfiles/usrlocal/gitk-browse.sh
systemfiles/usrlocal/install-qemu-additions.sh
systemfiles/usrlocal/install-vbox-guestadditions.sh
systemfiles/usrlocal/pulsevolume.sh
systemfiles/usrlocal/spawn-container
User/common
userfiles/common/bookmarks
userfiles/common/doxygen.desktop
userfiles/common/git.config
userfiles/common/gitk.desktop
userfiles/common/locale.conf
userfiles/common/xsessionrc
User/manuals
userfiles/manuals/git_guide_en.pdf
userfiles/manuals/Opiskelijan_opas.pdf
userfiles/manuals/pieni_git_opas_fi.pdf
User/xfce4
userfiles/xfce_config/keyboards.xml
userfiles/xfce_config/thunar.xml
userfiles/xfce_config/xfce4-desktop.xml
userfiles/xfce_config/xfce4-keyboard-shortcuts.xml
userfiles/xfce_config/xfce4-panel.xml
userfiles/xfce_config/xfce4-session.xml
userfiles/xfce_config/xfwm4.xml
Using
Lauching build.sh (note that if you have a system with X11 started up,
a graphical user interface will be shown instead - use unset DISPLAY
to hide it):
Another help screen when a recipe has been selected:
Error message when a recipe and operation has been selected without
specifying mandatory settings (here, BUILDVERSION
):
The deps
command can be used to see what needs to be done for the
(here, default) build target:
In this screenshot, the system has been successfully built so nothing needs to be done, everything in printed in light green:
This command demonstrates how we can also build just a subgoal instead of the default main goal: