Creating a configuration
The following illustrates how to create a custom build configuration and guides through the available configuration directives with examples.
The directives are further described in the build configuration reference.
Custom build configuration
Assuming a FreeBSD target-vm is to be created,
the following steps will allow bootstrapping the guest
and allow for arbitrary command executing for e.g. installing
addtional packages.
- Create a new directory for the to be built virtual machine and create a build configuration file:
mkdir -p my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13
cd my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13
touch build.xml
- For this howto, also copy the
filesdirectory from thefreebsd-13.0configuration in the example repository. It includes a bootloader and afirstrunscript for thetarget-vmlater used here. Copy it from thevm-builderrepository path:- at
examples/vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files - to your
my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13directory.
- at
- In the beginning, the file
build.xmlwill have the following contents:
<config>
</config>
- Since we want to build a virtual machine, we need to specify it's
architecture, name and version. The first in this example being
x86_64, the name would befreebsd-13.0and for the version we may use todays date2024-04-13. The updated configuration file looks like the following now:
<config>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
</config>
- The
target-vmis not yet formated, bootable and has no files on it's virtual hard disk. Doing these boostrapping steps is done by abuild-vm. A referencebuild-vmis provided by thevm-builderproject. Importing and building it is described in the getting started page. We can use it by adding it with thebuild-vmdirective:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
</config>
- In order to make use of the
build-vm, copy it from the example repository:- at
examples/vm-repo/configs/x86_64/linux-busybox - to your repository at
my-vm-repo/configs/x86_64/linux-busybox
- at
Creating a disk
The build configuration in it's current state does execute any jobs on the
target-vms image. Providing a list of jobs will allow us to manipulate
it. If no image file is present, we start by creating it with the
create-disk job. Specifying the size attribute is required. This
creates a raw disk image with a size of 4G:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
</jobs>
</config>
Partition table
Having a disk file, we can now give it a partion label. The type is
required. Here we set it to msdos:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
</jobs>
</config>
Partitioning
Having a partition table at hand, we may now add a primary partition starting at an offset of 1MB and a size of 2500MB:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
</jobs>
</config>
Formatting
After adding a partition, we may now format it with FreeBSDs native ufs file system:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
</jobs>
</config>
Installing a bootloader
Let us install the GRUB2 bootloader and copy the master boot
record data to the disk, to make it bootable. The files boot.img and
core.img are binary files present in the files directory we copied
at the start of the howto:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
</jobs>
</config>
Copying files
The provided GRUB2 bootloader binary will search for it's configuration
at /boot/grub/grub.cfg in the first partition. Let us copy that file
onto the disk. You may find that file in the files directory as well:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
</jobs>
</config>
Downloading files
The current configuration will make the bootloader complain, that
no kernel could be found. It's time to populate the file system a
kernel and the base files. For convenience the vm-builder can
download those files with the fetch job and compare their hash
to avoid file corruptions. If the files already exist at the specified
path in the files directory, they will be used instead. In the
next step, we will extract those files:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/kernel.txz" path="kernel.txz" retry="3" hash="d08c54610a8ed40de103accd6171fc8abc59e0594d4e8bb8ecf8f8cf2fc8feb55422a1ee58996b6e42364140fa8bc8505d42758579da064018e98330209fc35c" hash-algorithm="sha512"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/base.txz" path="base.txz" retry="3" hash="faae230c12d8028c050de551656bb86435b5414aa605c20aaff3ac149816a3d711bbdbe867823f9ae6cb02bb56d9092a92f5913c1d07aa3ba86ef6484ce0e417" hash-algorithm="sha512"/>
</jobs>
</config>
Extracting files
The downloaded archive are then extracted
to the disk using the tar-in job. The build-vm does not have
any knowledge on how and where the target-vm would mount it's
partitions. You thus have to specify the target partition for
archive extraction:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/kernel.txz" path="kernel.txz" retry="3" hash="d08c54610a8ed40de103accd6171fc8abc59e0594d4e8bb8ecf8f8cf2fc8feb55422a1ee58996b6e42364140fa8bc8505d42758579da064018e98330209fc35c" hash-algorithm="sha512"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/base.txz" path="base.txz" retry="3" hash="faae230c12d8028c050de551656bb86435b5414aa605c20aaff3ac149816a3d711bbdbe867823f9ae6cb02bb56d9092a92f5913c1d07aa3ba86ef6484ce0e417" hash-algorithm="sha512"/>
<tar-in partition="1" source="kernel.txz" target="/"/>
<tar-in partition="1" source="base.txz" target="/"/>
</jobs>
</config>
Network configuration
The copy-in job let's us copy files and directories to the
target-vm. We will use this, to copy the interfaces and
resolv.conf files, which FreeBSD uses for configuring network
related options.
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/kernel.txz" path="kernel.txz" retry="3" hash="d08c54610a8ed40de103accd6171fc8abc59e0594d4e8bb8ecf8f8cf2fc8feb55422a1ee58996b6e42364140fa8bc8505d42758579da064018e98330209fc35c" hash-algorithm="sha512"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/base.txz" path="base.txz" retry="3" hash="faae230c12d8028c050de551656bb86435b5414aa605c20aaff3ac149816a3d711bbdbe867823f9ae6cb02bb56d9092a92f5913c1d07aa3ba86ef6484ce0e417" hash-algorithm="sha512"/>
<tar-in partition="1" source="kernel.txz" target="/"/>
<tar-in partition="1" source="base.txz" target="/"/>
<copy-in partition="1" source="interfaces" target="/etc/network/interfaces"/>
<copy-in partition="1" source="resolv.conf" target="/etc/resolv.conf"/>
</jobs>
</config>
Mount configuration
The FreeBSD kernel will look for a file at /etc/fstab for information
on how to mount the partition the created earlier. We copy it into the
disk image as well:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/kernel.txz" path="kernel.txz" retry="3" hash="d08c54610a8ed40de103accd6171fc8abc59e0594d4e8bb8ecf8f8cf2fc8feb55422a1ee58996b6e42364140fa8bc8505d42758579da064018e98330209fc35c" hash-algorithm="sha512"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/base.txz" path="base.txz" retry="3" hash="faae230c12d8028c050de551656bb86435b5414aa605c20aaff3ac149816a3d711bbdbe867823f9ae6cb02bb56d9092a92f5913c1d07aa3ba86ef6484ce0e417" hash-algorithm="sha512"/>
<tar-in partition="1" source="kernel.txz" target="/"/>
<tar-in partition="1" source="base.txz" target="/"/>
<copy-in partition="1" source="interfaces" target="/etc/network/interfaces"/>
<copy-in partition="1" source="resolv.conf" target="/etc/resolv.conf"/>
<copy-in partition="1" source="fstab" target="/etc/fstab"/>
</jobs>
</config>
Firstrun script
Now the target-vm is ready to boot! Though we still can not use
the run job, to execute arbitrary commands. For that, a firstrun script
is provided, which reads the commands provided by us and executes them.
Copying it to this specific location, makes FreeBSD run in on every boot:
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/kernel.txz" path="kernel.txz" retry="3" hash="d08c54610a8ed40de103accd6171fc8abc59e0594d4e8bb8ecf8f8cf2fc8feb55422a1ee58996b6e42364140fa8bc8505d42758579da064018e98330209fc35c" hash-algorithm="sha512"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/base.txz" path="base.txz" retry="3" hash="faae230c12d8028c050de551656bb86435b5414aa605c20aaff3ac149816a3d711bbdbe867823f9ae6cb02bb56d9092a92f5913c1d07aa3ba86ef6484ce0e417" hash-algorithm="sha512"/>
<tar-in partition="1" source="kernel.txz" target="/"/>
<tar-in partition="1" source="base.txz" target="/"/>
<copy-in partition="1" source="interfaces" target="/etc/network/interfaces"/>
<copy-in partition="1" source="resolv.conf" target="/etc/resolv.conf"/>
<copy-in partition="1" source="fstab" target="/etc/fstab"/>
<copy-in partition="1" source="firstrun" target="/usr/local/etc/rc.d/firstrun.sh"/>
</jobs>
</config>
Arbitray commands
The last job for executing custom commands, namely the run job is usable now.
It furthermore allows for enabling or disabling network access, specifying whether to
use virtio virtual hardware or legacy virtual hardware, and the amount of ram. For
the sake of checking, if the firstrun script works as expected, we use a command to
print out the installed operating systems version
<config>
<build-vm arch="x86_64" name="linux-busybox" version="2024-05-23"/>
<target-vm arch="x86_64" name="freebsd-13.0" version="2024-04-13"/>
<jobs>
<create-disk size="4G"/>
<label type="msdos"/>
<partition type="primary" start="1MB" size="2500MB"/>
<format partition="1" type="ufs2" label="" uuid=""/>
<dd file="boot.img" bs="446" count="1"/>
<dd file="core.img" bs="512" seek="1"/>
<copy-in partition="1" source="grub.cfg" target="/boot/grub/grub.cfg"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/kernel.txz" path="kernel.txz" retry="3" hash="d08c54610a8ed40de103accd6171fc8abc59e0594d4e8bb8ecf8f8cf2fc8feb55422a1ee58996b6e42364140fa8bc8505d42758579da064018e98330209fc35c" hash-algorithm="sha512"/>
<fetch url="https://download.freebsd.org/ftp/releases/amd64/13.3-RELEASE/base.txz" path="base.txz" retry="3" hash="faae230c12d8028c050de551656bb86435b5414aa605c20aaff3ac149816a3d711bbdbe867823f9ae6cb02bb56d9092a92f5913c1d07aa3ba86ef6484ce0e417" hash-algorithm="sha512"/>
<tar-in partition="1" source="kernel.txz" target="/"/>
<tar-in partition="1" source="base.txz" target="/"/>
<copy-in partition="1" source="interfaces" target="/etc/network/interfaces"/>
<copy-in partition="1" source="resolv.conf" target="/etc/resolv.conf"/>
<copy-in partition="1" source="fstab" target="/etc/fstab"/>
<copy-in partition="1" source="firstrun" target="/usr/local/etc/rc.d/firstrun.sh"/>
<run virtio="yes" network="yes" ram="1G" file="kernel.txz" command="uname -a"/>
</jobs>
</config>
Importing and building
Now we will import this configuration file by specifying it's repositories directory as the path:
vm-builder import --path my-vm-repo
This validates and copies the contents of the my-vm-repo directory to the path ~/.uvm/repos:
~/.uvm/repos/my-vm-repo
~/.uvm/repos/my-vm-repo/configs
~/.uvm/repos/my-vm-repo/configs/x86_64
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/resolv.conf
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/interfaces
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/grub.cfg
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/boot.img
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/core.img
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/fstab
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/files/firstrun
~/.uvm/repos/my-vm-repo/configs/x86_64/freebsd-13.0/2024-04-13/build.xml
After the build configuration is imported, we may build it:
vm-builder build --repo my-vm-repo --arch x86_64 --name freebsd-13.0 --version 2024-04-13
At the end of the build process, the path to the virtual machine image is printed:
...
The image can be found at:
/home/user/.uvm/images/my-vm-repo/x86_64/freebsd-13.0/2024-04-13/disk0.img
Run it with:
qemu-system-x86_64 -bios /usr/share/seabios/bios.bin -enable-kvm -cpu host -m 1G -smp 2 -drive file=/home/user/.uvm/images/my-vm-repo/x86_64/freebsd-13.0/2024-04-13/disk0.img,format=raw,if=virtio
Cleaning up build directory at: /home/user/.uvm/images/my-vm-repo/x86_64/freebsd-13.0/2024-04-13/build