Creating images with libguestfs
The first step in creating a secure and regularly updated app for VM Squared is automating a repeatable build. Automated app builds enable you to easily ship security fixes, which ensure that your new VMs have a secure and fully-featured image.
In order to create an automated app for VM Squared we will describe the process for building the disk image that will be used to deploy the VM running your app.
We will be using libguestfs to build our disk image for the app.
Basics of libguestfs
Libguestfs enables us to customize existing Linux disk images to add packages, scripts and configuration settings.
The final image will contain an operating system, customized to include the following:
A contextualization package (
one-context
)When a VM is instantiated, it will be contextualized by VM Squared. This is when the VM’s individual configuration is applied, such as networking and SSH keys.
We will use the latest one-context package from the addon-context-linux repo.
A
firstboot
scriptThis script will be executed when the VM is first booted up after being instantiated in VM Squared.
This can be used to perform any configuration or setup that cannot be applied at build time, such as editing VM’s config files with any input provided by the user during setup.
App files
Anything needed for your app, such as packages, code, templates, configuration files etc.
Requirements
You will need:
- Linux system capable of running libguestfs.
- Packages are available for Fedora, Red Hat, Debian and Ubuntu.
- Target OS VM image in
RAW
orQCOW2
format. - Disk space to store and manipulate your chosen image.
Image preparation
To keep things simple, we’ll create a Debian image with one-context and Grafana installed. The Grafana admin username & password will be set in VM Squared.
Writing a build.sh script
It’s not really a script
It’s mostly a virt-builder
command broken into multiple lines for readability , convenience and reproducible results.
Contents of build.sh
:
app_name='grafana'
root_password="correcthorsebatterystaple"
base_image='debian-11'
context_package='https://github.com/OpenNebula/addon-context-linux/releases/download/v6.6.0/one-context_6.6.0-1.deb'
image_format='qcow2'
output_file="$app_name-$base_image.$image_format"
virt-builder $base_image \
--format $image_format \
--install curl,gnupg \
--run-command "wget $context_package" \
--run-command 'apt update ; dpkg -i /root/one-context_*deb || apt-get install -fy' \
--run-command 'curl https://packages.grafana.com/gpg.key | apt-key add -' \
--run-command 'echo "deb https://packages.grafana.com/oss/deb stable main" | tee -a /etc/apt/sources.list.d/grafana.list' \
--install grafana \
--upload local-config/grafana.ini:/etc/grafana/grafana.ini \
--firstboot firstboot.sh \
--root-password password:$root_password \
--output $output_file && echo "Successfully built image: $output_file at $(date)"
Running scripts at boot
This script refers to some files that don’t exist yet, so we’ll make them:
The file firstboot.sh
was specified with --firstboot
which runs this script when the image first boots up, after being instantiated in VM Squared.
With the user’s inputs during setup, we can finish configuring the app.
The output of this script will be written to /root/virt-sysprep-firstboot.log
Contents of firstboot.sh
:
#!/usr/bin/env bash
# Wait until one_env has been populated and source it to get the user's inputs
while [[ ! -s "/run/one-context/one_env" ]]; do
echo "Waiting for one_env to be populated..."
sleep 1
done
source /run/one-context/one_env
sed -i "s/admin_user =.*#MANAGED-BY-HC/admin_user = $GRAFANA_ADMIN_USERNAME #MANAGED-BY-HC/g" /etc/grafana/grafana.ini
sed -i "s/admin_password =.*#MANAGED-BY-HC/admin_password = $GRAFANA_ADMIN_PASSWORD #MANAGED-BY-HC/g" /etc/grafana/grafana.ini
systemctl enable grafana-server --now
systemctl status grafana-server | cat
Uploading files to image
We can also upload files to the image with the --upload
parameter.
The file local-config/grafana.ini
was specified as an upload.
[security]
admin_user = admin #MANAGED-BY-HC
admin_password = VM Squared?m0nitoring #MANAGED-BY-HC
Build the image
With all our files in place, we can run the build script:
build.sh
Successful output:
[ 1.0] Downloading: http://builder.libguestfs.org/debian-11.xz
[ 1.6] Planning how to build this image
[ 1.6] Uncompressing
[ 5.5] Converting raw to qcow2
[ 6.3] Opening the new disk
[ 9.6] Installing packages: curl gnupg
[ 30.7] Running: wget https://github.com/OpenNebula/addon-context-linux/releases/download/v6.6.0/one-context_6.6.0-1.deb
[ 31.3] Running: apt update ; dpkg -i /root/one-context_*deb || apt-get install -fy
[ 32.2] Running: curl https://packages.grafana.com/gpg.key | apt-key add -
[ 32.7] Running: echo "deb https://packages.grafana.com/oss/deb stable main" | tee -a /etc/apt/sources.list.d/grafana.list
[ 32.7] Installing packages: grafana
[ 39.2] Uploading: local-config/grafana.ini to /etc/grafana/grafana.ini
[ 39.3] Installing firstboot script: firstboot.sh
[ 39.4] Setting passwords
[ 40.0] Finishing off
Output file: grafana-debian-11.qcow2
Output size: 6.0G
Output format: qcow2
Total usable space: 6.4G
Free space: 5.0G (77%)
Successfully built image: grafana-debian-11.qcow2 at Wed 22 Feb 13:57:19 GMT 2023
You can now upload the built image to VM Squared as an Operating System image, and Create your VM Template