Photo credit: Alina Fedorchenko
This is my third post about Image Builder, so I guess you could say that I enjoy using it1. It’s a great way to define a custom cloud image, build it, and (optionally) ship it to a supported cloud provider.
This post covers how to build a customized CentOS Stream 9 image along with a custom repository for additional packages. In this case, that’s Extra Packages for Enterprise Linux (EPEL).
Why do I need a custom image anyway?⌗
Building your own image empowers you to choose which packages you want, which services run at boot time, and where you deploy your image. Some cloud providers may not have an image from the Linux distribution you enjoy most, or they might have an image with the wrong package set.
Some cloud providers build images with too many packages or too few. Sometimes they add
configuration that doesn’t exist in the OS itself. I’ve even found some that alter
cloud-init and force you to log in directly as the
root user. 😱
I enjoy building my own images so I know exactly what it contains and I know that the configuration came from the OS itself.
This post uses CentOS Stream 9 as an example. You will need a physical host, virtual machine, or cloud instance running CentOS Stream 9 first. We start by installing some packages:
$ sudo dnf install osbuild-composer weldr-client
What do these packages contain?
- osbuild-composer ensures you have osbuild, the low-level image build component, along with configuration and an osbuild-composer2 worker that builds the image.
- weldr-client contains the
composer-clicommand line tool that makes it easy to interact with osbuild-composer
One nice thing about this stack is that it starts via systemd’s socket activation and it only runs when you query it. Let’s start the socket now and ensure it comes up on a reboot:
$ sudo systemctl enable --now osbuild-composer.socket
Verify that the API is responding:
$ composer-cli status show API server status: Database version: 0 Database supported: true Schema version: 0 API version: 1 Backend: osbuild-composer Build: NEVRA:osbuild-composer-46-1.el9.x86_64
CentOS Stream 9 has most of the packages I want, but I really love this program called
htop that displays resource usage and allows you to introspect certain processes or
namespaces easily. This package is only available in the EPEL repository, so we need to
add that one to our list of enabled repositories for image builds.
osbuild-composer comes with its own set of repositories in the package and does not use the system’s repositories. You can list all the enabled repositories that it knows about:
# composer-cli sources list AppStream BaseOS RT
If we want to add EPEL, we can dump the configuration from one of these to a file and edit it:
# composer-cli sources info AppStream | tee epel.ini check_gpg = true check_ssl = true id = "AppStream" name = "AppStream" rhsm = false system = true type = "yum-baseurl" url = "https://composes.stream.centos.org/production/latest-CentOS-Stream/compose/AppStream/x86_64/os/"
After editing the EPEL repository file, it should look like this:
check_gpg = true check_ssl = true id = "EPEL9" name = "EPEL9" rhsm = false system = false type = "yum-baseurl" url = "https://mirrors.kernel.org/fedora-epel/9/Everything/x86_64/"
You can use any mirror you prefer, but the kernel mirrors are very fast for me from most locations. Now we need to add this repository:
# composer-cli sources add epel.ini # composer-cli sources list AppStream BaseOS EPEL9 RT
We now have
EPEL9 in our list. 🎉
Define our image⌗
All image definitions, or blueprints, are in TOML format. Here’s my simple one for this post:
# Save this file as image.toml name = "centos9" description = "Major's awesome CentOS 9 image" version = "0.0.1" [[packages]] name = "tmux" [[packages]] name = "vim" # This is the one that comes from EPEL. [[packages]] name = "htop"
Now we push our blueprint and solve the dependencies to ensure we added our EPEL repository properly:
# composer-cli blueprints push image.toml # composer-cli blueprints depsolve centos9 -- SNIP -- 2:vim-filesystem-8.2.2637-16.el9.noarch which-2.21-27.el9.x86_64 xz-5.2.5-7.el9.x86_64 xz-libs-5.2.5-7.el9.x86_64 zlib-1.2.11-33.el9.x86_64 htop-3.1.2-3.el9.x86_64
htop at the end of the list! 🎉
Make the image⌗
The fun part has arrived! Let’s build an image:
# composer-cli compose start centos9 ami --size=4096 Compose ca57fd64-11ea-41d4-b924-9b8f5bdcaf5e added to the queue
This command does a few things:
- Starts an image build with our
centos9blueprint (from the
namesection of my
- Outputs an image type that works well on AWS (Amazon Machine Image, or AMI)
- Limits the image size to 4GB (be sure this is not too large for your preferred instance size)
🤔 Note that you do not need to set the size explicitly here, but I do it as a good measure. When your instance boots,
growpartto expand the storage to fit the disk size in your cloud instance.
growpartwill not shrink the disk at boot time. If you choose a size that is larger than the disk space in your cloud instance, you will likely see an error at provisioning time.
Let’s check the status after a few minutes:
# composer-cli compose status ca57fd64-11ea-41d4-b924-9b8f5bdcaf5e FINISHED Fri May 6 16:16:08 2022 centos9 0.0.1 ami 4096
If you want to get a copy of the image and import it yourself into your favorite cloud, you can do that now:
# composer-cli compose image ca57fd64-11ea-41d4-b924-9b8f5bdcaf5e ca57fd64-11ea-41d4-b924-9b8f5bdcaf5e-image.raw # ls -alh ca57fd64-11ea-41d4-b924-9b8f5bdcaf5e-image.raw -rw-------. 1 root root 2.7G May 6 16:20 ca57fd64-11ea-41d4-b924-9b8f5bdcaf5e-image.raw