The motivation to use BootC
I have a fair amount of servers that I’m (co-)responsible for. To make my life easier I tried serveral managent tools to do the common tasks for all servers as smooth as possible.
The two tools I mainly use at the moment are ansible and cloud-init.
Cloud-init is a great tool to spin up a new server, or to resore an existing one.
ansible is great to do common tasks, like updating servers, installing packages to multiple hosts, but when it comes to thinks like adding a systemd-service to just a view hosts, it never felt natural to me.
The deeper problem is config drift. After months of ad-hoc ansible runs, one-off fixes and small experiments, no two servers look exactly alike anymore. You think you know what’s on a host – until something breaks and you realise it quietly diverged from everything else six months ago.
On the other hand I am using Fedora-Silverblue as my main OS and Daily driver. And I have to admit, that I absolutly love the concept of an immutable OS. When I found out about BootC and it has a similar origin than Silverblue I was really exited.
The concept, to make a server-setup the same way you create a Container-Image, was something I was searching for quite a wile now. So it was clear to me, that I have to start using it for all my hosts.
What makes BootC different from anything I’ve used before is that your entire OS is just a container image. The same tools you use to build your app containers – Containerfiles, registries, image layers – now describe your whole operating system. Every host boots from the exact same image, built from the exact same source. No more jitter.
The update story is where it really clicked for me: you push a new image to your registry, bootc-fetch-apply-updates.service picks it up and applies it on the next reboot. If something breaks, rolling back is a single command. Compare that to an ansible playbook that failed halfway through and left a host in an unknown state – with BootC, you either have the old image or the new one. Nothing in between.
That’s how you define your bootable-image:
# Containerfile
FROM quay.io/fedora/fedora-bootc:latest
RUN dnf install -y neovim tmux wireguard-tools borgbackup rclone \
cockpit cockpit-podman cockpit-storaged cockpit-ws cockpit-ostree \
git lm_sensors sysstat tuned \
vim-enhanced \
glusterfs btop htop wcurl screen \
qemu-guest-agent cloud-init \
&& dnf clean all && \
systemctl enable lm_sensors sysstat tuned fstrim.timer podman.socket podman-auto-update.timer cockpit.socket
and that’s how you build and push it:
podman build --tag registry.example.com/my-os:latest .
podman push registry.example.com/my-os:latest
To switch a running host to your image, or to install it from scratch:
# Switch a running host (takes effect on next reboot)
bootc switch registry.example.com/my-os:latest
# Check the current and staged image
bootc status
From that point on, bootc-fetch-apply-updates.service will pull and stage new versions of the image automatically. A rollback is just as simple:
bootc rollback
or select the old image in the boot-manager.
This is the moment I have been waiting for. My server configs now live in a git repository, get built in CI, and roll out to all hosts without me logging into a single one. ansible still has a place in my toolkit for one-off tasks and things that go beyond OS configuration, but the baseline of every machine is now a Containerfile – and that feels exactly right.
In upcomming posts I will explain how you can create a VM from an image, how you can install the image on bare metal, how you can add system-users, create startup services, and how to set up a CI pipeline that builds and pushes the image automatically. Stay tuned!
Comments
Talk about this post on Mastodon or Bluesky with #m1ch20251114BootcMotivation.
To comment here, reply to the post on Mastodon or on Bluesky.
Loading comments contacts graz.social or mastodon.social (wherever the post is) and Bluesky, see the privacy policy.