bootc-image-builder
A container to create disk images from bootc container inputs, especially oriented towards Fedora/CentOS bootc or derivatives.
๐จ Installationโ
Have podman installed on your system. Either through your systems package manager if you're on Linux or through Podman Desktop if you are on macOS or Windows. If you want to run the resulting virtual machine(s) or installer media you can use qemu.
A very nice GUI extension for Podman Desktop is also available. The command line examples below can be all handled by Podman Desktop.
On macOS, the podman machine must be running in rootful mode:
$ podman machine stop # if already running
Waiting for VM to exit...
Machine "podman-machine-default" stopped successfully
$ podman machine set --rootful
$ podman machine start
โ Prerequisitesโ
If you are on a system with SELinux enforced: The package osbuild-selinux or equivalent osbuild SELinux policies must be installed in the system running
bootc-image-builder.
๐ Examplesโ
The following example builds a centos-bootc:stream9 bootable container into a QCOW2 image for the architecture you're running
the command on. However, be sure to see the upstream documentation
for more general information! Note that outside of initial experimentation, it's recommended to build a derived container image
(or reuse a derived image built via someone else) and then use this project to make a disk image from your custom image.
The generic base images do not include a default user. This example injects a user configuration file by adding a volume-mount for the local file to the bootc-image-builder container.
The following command will create a QCOW2 disk image. First, create ./config.toml as described above to configure user access.
# Ensure the image is fetched
sudo podman pull quay.io/centos-bootc/centos-bootc:stream9
mkdir output
sudo podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v ./config.toml:/config.toml:ro \
-v ./output:/output \
-v /var/lib/containers/storage:/var/lib/containers/storage \
quay.io/centos-bootc/bootc-image-builder:latest \
--type qcow2 \
--use-librepo=True \
quay.io/centos-bootc/centos-bootc:stream9
Note that some images (like fedora) do not have a default root
filesystem type. In this case adds the switch --rootfs <type>,
e.g. --rootfs btrfs.
Rootlessโ
There is experimental support for rootless builds in bootc-image-builder. To perform a rootless build KVM is used. The above example can be tried like so:
# Ensure the image is fetched
podman pull quay.io/fedora/fedora-bootc:latest
mkdir output
podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v ./config.toml:/config.toml:ro \
-v ./output:/output \
-v ~/.local/share/containers/storage:/var/lib/containers/storage \
quay.io/centos-bootc/bootc-image-builder:latest \
--in-vm \
--type qcow2 \
--use-librepo=True \
--rootfs ext4 \
quay.io/fedora/fedora-bootc:latest
Note the mounting of the users container storage, addition of the --in-vm argument and the removal of sudo in the commands.
Running the resulting QCOW2 file on Linux (x86_64)โ
A virtual machine can be launched using qemu-system-x86_64 or with virt-install as shown below;
however there is more information about virtualization and other
choices in the Fedora/CentOS bootc documentation.
qemu-system-x86_64โ
qemu-system-x86_64 \
-M accel=kvm \
-cpu host \
-smp 2 \
-m 4096 \
-bios /usr/share/OVMF/OVMF_CODE.fd \
-serial stdio \
-snapshot output/qcow2/disk.qcow2
virt-installโ
sudo virt-install \
--name fedora-bootc \
--cpu host \
--vcpus 4 \
--memory 4096 \
--import --disk ./output/qcow2/disk.qcow2,format=qcow2 \
--os-variant fedora-eln
Running the resulting QCOW2 file on macOS (aarch64)โ
This assumes qemu was installed through homebrew.
qemu-system-aarch64 \
-M accel=hvf \
-cpu host \
-smp 2 \
-m 4096 \
-bios /opt/homebrew/Cellar/qemu/8.1.3_2/share/qemu/edk2-aarch64-code.fd \
-serial stdio \
-machine virt \
-snapshot output/qcow2/disk.qcow2
๐ Argumentsโ
Usage:
sudo podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v ./output:/output \
-v /var/lib/containers/storage:/var/lib/containers/storage \
quay.io/centos-bootc/bootc-image-builder:latest \
<imgref>
Flags:
--chown string chown the ouput directory to match the specified UID:GID
--output string artifact output directory (default ".")
--progress string type of progress bar to use (e.g. verbose,term) (default "auto")
--rootfs string Root filesystem type. If not given, the default configured in the source container image is used.
--target-arch string build for the given target architecture (experimental)
--type stringArray image types to build [ami, anaconda-iso, bootc-installer, gce, iso, qcow2, raw, vhd, vmdk] (default [qcow2])
--version version for bootc-image-builder
Global Flags:
--log-level string logging level (debug, info, error); default error
-v, --verbose Switch to verbose mode
Detailed description of optional flagsโ
| Argument | Description | Default Value |
|---|---|---|
| --chown | chown the output directory to match the specified UID:GID | โ |
| --output | output the artifact into the given output directory | . |
| --progress | Show progress in the given format, supported: verbose,term,debug. If empty it is auto-detected | auto |
| --rootfs | Root filesystem type. Overrides the default from the source container. Supported values: ext4, xfs, btrfs | โ |
| --type | Image type to build (can be passed multiple times) | qcow2 |
| --target-arch | Target arch to build | โ |
| --log-level | Change log level (debug, info, error) | error |
| -v,--verbose | Switch output/progress to verbose mode (implies --log-level=info) | false |
| --use-librepo | Download rpms using librepo (faster and more robust) | false |
The --type parameter can be given multiple times and multiple
outputs will be produced. Note that comma or space separating the
image-typeswill not work, but this example will: --type qcow2 --type ami.
๐ก Tip: Flags in bold are the most important ones.
๐พ Image typesโ
The following image types are currently available via the --type argument:
| Image type | Target environment |
|---|---|
ami | Amazon Machine Image |
qcow2 (default) | QEMU |
vmdk | VMDK usable in vSphere, among others |
bootc-installer | An installer ISO image based on the specified bootc container image. |
anaconda-iso | An unattended Anaconda installer that installs to the first disk found. Built from RPMs. |
raw | Unformatted raw disk. |
vhd | vhd usable in Virtual PC, among others |
gce | GCE |
pxe-tar-xz | A stateless image useful in PXE network boot environments |
๐พ Image Type Requirementsโ
pxe-tar-xzโ
The container image being built must have the dracut-live and squashfs-tools packages installed as well as a rebuilding the initramfs with the 'dmsquash-live' module. See osbuild documentation for more information and a sample Containerfile.
๐พ Target architectureโ
Specify the target architecture of the system on which the disk image will be installed on. By default,
bootc-image-builder will build for the native host architecture. The target architecture
must match an available architecture of the bootc-image-builder image you are using to build the disk image.
Navigate to the centos-image-builder repository tags page
and hover over the Tux icons to see the supported target architectures.
The architecture of the bootc OCI image and the bootc-image-builder image must match. For example, when building
a non-native architecture bootc OCI image, say, building for x86_64 from an arm-based Mac, it is possible to run
podman build with the --platform linux/amd64 flag. In this case, to then build a disk image from the same arm-based Mac,
you should provide --target-arch amd64 when running the bootc-image-builder command.
Progress typesโ
The following progress types are supported:
- verbose: No spinners or progress bar, just information and full osbuild output
- term: Terminal based output, spinner, progressbar and most details of osbuild are hidden
- debug: Details how the progress is called, mostly useful for bugreports
Note that when no value is given the progress is auto-detected baed on the environment. When stdin is a terminal the "term" progress is used, otherwise "verbose". The output of verbose is exactaly the same as it was before progress reporting was implemented.
โ๏ธ Cloud uploadersโ
Amazon Machine Images (AMIs)โ
Prerequisitesโ
In order to successfully import an AMI into your AWS account, you need to have the vmimport service role configured on your account with the following additional permissions:
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::amzn-s3-demo-import-bucket",
"arn:aws:s3:::amzn-s3-demo-import-bucket/*",
"arn:aws:s3:::amzn-s3-demo-export-bucket",
"arn:aws:s3:::amzn-s3-demo-export-bucket/*"
]
},
Replace amzn-s3-demo-import-bucket in the ARN with the bucket name.
Flagsโ
AMIs can be automatically uploaded to AWS by specifying the following flags:
| Argument | Description |
|---|---|
| --aws-ami-name | Name for the AMI in AWS |
| --aws-bucket | Target S3 bucket name for intermediate storage when creating AMI |
| --aws-region | Target region for AWS uploads |
Notes:
- These flags must all be specified together. If none are specified, the AMI is exported to the output directory.
- The bucket must already exist in the selected region, bootc-image-builder will not create it if it is missing.
- The output volume is not needed in this case. The image is uploaded to AWS and not exported.
AWS credentials fileโ
If you already have a credentials file (usually in $HOME/.aws/credentials) you need to forward the
directory to the container
For example:
$ sudo podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v $HOME/.aws:/root/.aws:ro \
-v /var/lib/containers/storage:/var/lib/containers/storage \
--env AWS_PROFILE=default \
quay.io/centos-bootc/bootc-image-builder:latest \
--type ami \
--aws-ami-name centos-bootc-ami \
--aws-bucket fedora-bootc-bucket \
--aws-region us-east-1 \
quay.io/centos-bootc/centos-bootc:stream9
Notes:
- you can also inject ALL your AWS configuration parameters with
--env AWS_*
see the AWS CLI documentation for more information about other environment variables
AWS credentials via environmentโ
AWS credentials can be specified through two environment variables:
| Variable name | Description |
|---|---|
| AWS_ACCESS_KEY_ID | AWS access key associated with an IAM account. |
| AWS_SECRET_ACCESS_KEY | Specifies the secret key associated with the access key. This is essentially the "password" for the access key. |
Those should not be specified with --env as plain value, but you can silently hand them over with --env AWS_* or
save these variables in a file and pass them using the --env-file flag for podman run.
For example:
$ cat aws.secrets
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
$ sudo podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v /var/lib/containers/storage:/var/lib/containers/storage \
--env-file=aws.secrets \
quay.io/centos-bootc/bootc-image-builder:latest \
--type ami \
--aws-ami-name centos-bootc-ami \
--aws-bucket centos-bootc-bucket \
--aws-region us-east-1 \
quay.io/centos-bootc/centos-bootc:stream9
๐ฝ Volumesโ
The following volumes can be mounted inside the container:
| Volume | Purpose | Required |
|---|---|---|
/output | Used for storing the resulting artifacts | โ |
/store | Used for the osbuild store | No |
/rpmmd | Used for the DNF cache | No |
๐ Build configโ
A build config is a TOML (or JSON) file with customizations for the resulting image. The config file is mapped into the container directory to /config.toml. The customizations are specified under a customizations object.
The build config is a Blueprint file, documented in the osbuild.org User Guide. Note that not all Blueprint options are supported in bootc-image-builder. Refer to the bootc tab for information on whether a specific customization is supported.
As an example, let's show how you can add a user to the image:
Firstly create a file ./config.toml and put the following content into it:
[[customizations.user]]
name = "alice"
password = "bob"
key = "ssh-rsa AAA ... user@email.com"
groups = ["wheel"]
Then, run bootc-image-builder with the following arguments:
sudo podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v ./config.toml:/config.toml:ro \
-v ./output:/output \
-v /var/lib/containers/storage:/var/lib/containers/storage \
quay.io/centos-bootc/bootc-image-builder:latest \
--type qcow2 \
quay.io/centos-bootc/centos-bootc:stream9
The configuration can also be passed in via stdin when --config -
is used. Only JSON configuration is supported in this mode.
Additionally, images can embed a build config file, either as
config.json or config.toml in the /usr/lib/bootc-image-builder
directory. If this exist, and contains filesystem or disk
customizations, then these are used by default if no such
customization are specified in the regular build config.
Users (user, array)โ
Possible fields:
| Field | Use | Required |
|---|---|---|
name | Name of the user | โ |
password | Unencrypted password | No |
key | Public SSH key contents | No |
groups | An array of secondary to put the user into | No |
Example:
{
"customizations": {
"user": [
{
"name": "alice",
"password": "bob",
"key": "ssh-rsa AAA ... user@email.com",
"groups": [
"wheel",
"admins"
]
}
]
}
}
Kernel Arguments (kernel, mapping)โ
{
"customizations": {
"kernel": {
"append": "mitigations=auto,nosmt"
}
}
}
Filesystems (filesystem, array)โ
The filesystem section of the customizations can be used to set the minimum size of the base partitions (/ and /boot) as well as to create extra partitions with mountpoints under /var.
[[customizations.filesystem]]
mountpoint = "/"
minsize = "10 GiB"
[[customizations.filesystem]]
mountpoint = "/var/data"
minsize = "20 GiB"
{
"customizations": {
"filesystem": [
{
"mountpoint": "/",
"minsize": "10 GiB"
},
{
"mountpoint": "/var/data",
"minsize": "20 GiB"
}
]
}
}