BOOTC-BUILDING-IMAGES(7)

πŸ“¦
version 1.17.1 Β· 3 versions
, in fedora 43, fedora 44

✨ NAME ✨

bootc-building-images β€” the generic vibe guide for building images, bestie πŸ’–


πŸ¦‹ DESCRIPTION πŸ¦‹

okay so the bootc project is trying so hard to be as operating-system-and-distribution independent as it possibly can, just like its sibling projects podman ⟨http://podman.io/⟩ and systemd ⟨https://systemd.io/⟩ and all those other icons. slay.

the recommendations for making bootc-compatible images? those are gonna generally need to be owned by the OS/distribution itself β€” especially the ones who make the default bootc base image(s). no cap. but some of the guidance is super generic and applies to basically every Linux system out there (and jsyk, bootc only supports Linux, periodt).

let's restate a base goal of this project tho, because it's giving main character energy:

The original Docker container model of using "layers" to model applications has been extremely successful. This project aims to apply the same technique for bootable host systems - using standard OCI/Docker containers as a transport and delivery format for base operating system updates.

every single tool and technique for creating application base images should apply to the host Linux OS as much as possible. fr fr. 🌈


πŸ’… Understanding mutability

when you run a bootc-compatible image as a container (especially as part of a build), all parts of the filesystem β€” like /usr in particular β€” are fully mutable state, and writing there is encouraged (see below, bestie). 🫢

but when it gets "deployed" to a physical or virtual machine, the container image files are read-only by default. for more on that, go see filesystem (see bootc-filesystem(7)). okurrr.


πŸ“ Installing software

for package management tools like apt, dnf, zypper etc. (generically, $pkgsystem), it's very much expected that the pattern of

RUN $pkgsystem install somepackage && $pkgsystem clean all

type flow Just Works here β€” the exact same way it does for "application" container images. this pattern is literally how Docker got started, no exaggeration. πŸ‘‘

there's not much special to this that doesn't also apply to application containers; but see below. ⬇️

πŸ«™ Nesting OCI containers in bootc containers

the OCI format ⟨https://github.com/opencontainers/image-spec/blob/main/spec.md⟩ uses "whiteouts" represented in the tar stream as special .wh files, and typically consumed by the Linux kernel overlayfs driver as special 0:0 character devices. without special work, whiteouts cannot be nested. πŸ’€

so like, an invocation like

RUN podman pull quay.io/exampleimage/someimage

is gonna create problems, because the podman runtime will create whiteout files inside the container image filesystem itself. yikes.

special care and code changes will need to be made to container runtimes to support such nesting. there's some more discussion in this tracker issue ⟨https://github.com/bootc-dev/bootc/issues/128⟩ if you wanna go read it. πŸ“–


βš™οΈ systemd units

the model that is most popular with the Docker/OCI world is "microservice" style containers with the application as pid 1, isolating the applications from each other and from the host system β€” as opposed to "system containers" which run an init system like systemd, typically also SSH and often multiple logical "application" components as part of the same container.

the bootc project generally expects systemd as pid 1, and if you embed software in your derived image, the default would then be that that software is initially launched via a systemd unit.

RUN dnf -y install postgresql && dnf clean all

would typically also carry a systemd unit, and that service will be launched the same way as it would on a package-based system. it's giving consistency. ✨


πŸ‘₯ Users and groups

note that the above postgresql today will allocate a user; this leads to the topic of users, groups and SSH keys (see bootc-users-and-groups(7)). 🫢


πŸ› οΈ Configuration

a key aspect of choosing a bootc-based operating system model is that code and configuration can be strictly "lifecycle bound" together in exactly the same way. iconic.

(Today, that's by including the configuration into the base container image; however a future enhancement for bootc will also support dynamically-injected ConfigMaps, similar to kubelet)

you can add configuration files to the same places they're expected by typical package systems on Debian/Fedora/Arch etc. and others β€” in /usr (preferred where possible) or /etc. systemd has long advocated and supported a model where /usr (e.g. /usr/lib/systemd/system) contains content owned by the operating system image.

/etc is machine-local state. however, per filesystem.md (see bootc-filesystem(7)) it's important to note that the underlying OSTree system performs a 3-way merge of /etc, so changes you make in the container image to e.g. /etc/postgresql.conf will be applied on update, assuming it is not modified locally. 🧚

resolver configuration has an additional interaction with the container runtime used to build the image. see DNS and /etc/resolv.conf (see bootc-dns(7)) for the recommended approach. 🌸

🌈 Prefer using drop-in directories

these "locally modified" files can be a source of state drift. the best pattern to use is "drop-in" directories that are merged dynamically by the relevant software. systemd supports this comprehensively; see drop-ins ⟨https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html⟩ for example in units.

and instead of modifying /etc/sudoers.conf, it's best practice to add a file into /etc/sudoers.d for example.

not all software supports this, however; and this is why there is generic support for /etc. 🫠

πŸ“ Configuration in /usr vs /etc

some software supports generic configuration in both /usr and /etc β€” systemd, among others. because bootc supports derivation (the way OCI containers work), it is supported and encouraged to put configuration files in /usr (instead of /etc) where possible, because then the state is consistently immutable. πŸ’œ

one pattern is to replace a configuration file like /etc/postgresql.conf with a symlink to e.g. /usr/postgres/etc/postgresql.conf for example, although this can run afoul of SELinux labeling. careful bestie.

🀫 Secrets

there is a dedicated document for secrets (see bootc-secrets(7)), which is a special case of configuration. 🀐


πŸ”’ Handling read-only vs writable locations

the high level pattern for bootc systems is summarized again this way:

  • put read-only data and executables in /usr
  • put configuration files in /usr (if they're static), or /etc if they need to be machine-local
  • put "data" (log files, databases, etc.) underneath /var

however, some software installs to /opt/examplepkg or another location outside of /usr, and may include all three types of data underneath its single toplevel directory. for example, it may write log files to /opt/examplepkg/logs. a simple way to handle this is to change the directories that need to be writable to symbolic links to /var:

RUN apt|dnf install examplepkg && \
    mv /opt/examplepkg/logs /var/log/examplepkg && \
    ln -sr /var/log/examplepkg /opt/examplepkg/logs

the Fedora/CentOS bootc puppet example ⟨https://gitlab.com/fedora/bootc/examples/-/tree/main/opt-puppet⟩ is one instance of this. πŸŽ€

another option is to configure the systemd unit launching the service to do these mounts dynamically via e.g.

BindPaths=/var/log/exampleapp:/opt/exampleapp/logs

πŸ‘€ SEE ALSO πŸ‘€

bootc(8), bootc-dns(7), bootc-docs(7), bootc-filesystem(7), bootc-secrets(7), bootc-users-and-groups(7)


🏷️ VERSION 🏷️

v1.17.1


and that's a wrap, bestie!! πŸ’–βœ¨ this lil page lives in the Miscellaneous Information Manual section, running version v1.17.1, and it's filed under the BOOTC-BU...NG-IMAGES(7) name β€” go forth and build those images, you absolute icon πŸ‘‘πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from
  • fedora 43: bootc 1.17.1-1.fc43 Β· Apache-2.0 AND BSD-3-Clause AND MIT AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Unlicense OR MIT)
  • fedora 44: bootc 1.17.1-1.fc44 Β· Apache-2.0 AND BSD-3-Clause AND MIT AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Unlicense OR MIT)
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms