Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ etc.

### Building and testing with the composefs backend

bootc has two storage backends: `ostree` (default, production) and `composefs`
(experimental). The composefs backend has several axes of configuration:
bootc has two storage backends: `ostree` and `composefs`.
The composefs backend has several axes of configuration:

| Variable | Values | Notes |
|---|---|---|
Expand Down Expand Up @@ -206,7 +206,7 @@ just validate-composefs-digest
The `build-sealed` target generates test Secure Boot keys in
`target/test-secureboot/` and builds a complete sealed image with all
the sealed composefs settings. See
[experimental-composefs.md](docs/src/bootc-experimental-composefs.7.md) for
[sealed images](docs/src/building/bootc-sealed-images.7.md) for
more information on sealed images.


Expand Down
12 changes: 7 additions & 5 deletions crates/lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,10 @@ pub(crate) enum ContainerOpts {
no_truncate: bool,
},
/// Output the bootable composefs digest for a directory.
#[clap(hide = true)]
///
/// This is the digest that `bootc container ukify` embeds in the kernel
/// command line of a UKI. It is useful for scripting and debugging outside
/// of that flow.
ComputeComposefsDigest {
/// Path to the filesystem root
#[clap(default_value = "/target")]
Expand Down Expand Up @@ -473,7 +476,7 @@ pub(crate) enum ContainerOpts {
/// and RHEL derivatives ship.
///
/// Example:
/// bootc container split-kernel-rootfs --rootfs /target-rootfs --output /out
/// bootc container split-kernel-and-rootfs --rootfs /target-rootfs --output /out
SplitKernelAndRootfs {
/// Operate on the provided rootfs
#[clap(long, default_value = "/")]
Expand Down Expand Up @@ -1088,6 +1091,7 @@ pub(crate) enum Opt {
#[clap(subcommand)]
#[clap(hide = true)]
Internals(InternalsOpts),
#[clap(hide = true)]
ComposefsFinalizeStaged(ComposefsFinalizeStagedOpts),
/// Diff current /etc configuration versus default
#[clap(hide = true)]
Expand All @@ -1102,9 +1106,7 @@ pub(crate) enum Opt {
shell: clap_complete::aot::Shell,
},
#[clap(hide = true)]
DeleteDeployment {
depl_id: String,
},
DeleteDeployment { depl_id: String },
}

/// Ensure we've entered a mount namespace, so that we can remount
Expand Down
2 changes: 1 addition & 1 deletion crates/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
//!
//! ## Storage Backends
//!
//! - [`bootc_composefs`] - Composefs backend implementation (experimental)
//! - [`bootc_composefs`] - Composefs backend implementation
//! - The OSTree backend is implemented via `ostree-ext` and the [`store`] module
//!
//! ## Filesystem and Boot
Expand Down
2 changes: 1 addition & 1 deletion crates/lib/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub enum Bootloader {
/// Use Grub as the bootloader
#[default]
Grub,
/// Use Grub for confidential clusters as the bootloader
/// Use Grub for confidential clusters as the bootloader (experimental)
#[serde(rename = "grub-cc")]
GrubCC,
/// Use SystemdBoot as the bootloader
Expand Down
13 changes: 12 additions & 1 deletion docs/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ additional-js = ["mermaid.min.js", "mermaid-init.js"]
# Preserve published URLs when canonical chapters adopt manual filenames.
[output.html.redirect]
"boot-failure-detection.html" = "bootc-boot-failure-detection.7.html"
"bootc-experimental-composefs.7.html" = "bootc-composefs.7.html"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid: bootc-experimental-composefs.7.html is the most recent published URL (since 09-28, unreleased), so its section links should follow the moved sections too. Fix in dfb63b6 on bot/composefs-stabilize-review, on top of 4831ab5; the built book's redirect page maps the fragments.

git fetch https://github.com/cgwalters-forge/bootc bot/composefs-stabilize-review && git cherry-pick dfb63b6c

Generated-by: https://github.com/cgwalters/#llms

"bootc-images.html" = "bootc-compatible-images.7.html"
"bootc-in-container.html" = "bootc-in-container.7.html"
"bootc-install.html" = "bootc-installation.7.html"
Expand All @@ -34,7 +35,17 @@ additional-js = ["mermaid.min.js", "mermaid-init.js"]
"building/secrets.html" = "bootc-secrets.7.html"
"building/users-and-groups.html" = "bootc-users-and-groups.7.html"
"experimental-bootc-image.html" = "bootc-experimental-image.7.html"
"experimental-composefs.html" = "bootc-experimental-composefs.7.html"
"experimental-composefs.html" = "bootc-composefs.7.html"
"experimental-composefs.html#storage-and-repository-structure" = "bootc-sysroot.7.html#composefs-backend-storage"
"experimental-composefs.html#how-sealed-images-work" = "building/bootc-sealed-images.7.html#how-sealed-images-work"
"experimental-composefs.html#building-sealed-images" = "building/bootc-sealed-images.7.html#building-sealed-images"
"experimental-composefs.html#prerequisites" = "building/bootc-sealed-images.7.html#prerequisites"
"experimental-composefs.html#using-without-secure-boot" = "building/bootc-sealed-images.7.html#using-without-secure-boot"
"experimental-composefs.html#the-bootc-container-ukify-command" = "building/bootc-sealed-images.7.html#the-bootc-container-ukify-command"
"experimental-composefs.html#the-bootc-container-compute-composefs-digest-command" = "building/bootc-sealed-images.7.html#the-bootc-container-compute-composefs-digest-command"
"experimental-composefs.html#external-signing-workflow" = "building/bootc-sealed-images.7.html#external-signing-workflow"
"experimental-composefs.html#bootloader-support" = "bootc-bootloaders.7.html#composefs-backend"
"experimental-composefs.html#installation" = "bootc-installation.7.html#composefs-backend"
"experimental-container-export.html" = "bootc-experimental-container-export.7.html"
"experimental-fsck.html" = "bootc-experimental-fsck.7.html"
"experimental-install-reset.html" = "bootc-experimental-install-reset.7.html"
Expand Down
10 changes: 6 additions & 4 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [Users, groups, SSH keys](building/bootc-users-and-groups.7.md)
- [`man bootc-sysusers-shadow-sync.service`](man/bootc-sysusers-shadow-sync.service.5.md)
- [Kernel arguments](building/bootc-kernel-arguments.7.md)
- [Sealed images](building/bootc-sealed-images.7.md)
- [Secrets](building/bootc-secrets.7.md)
- [Management Services](building/bootc-management-services.7.md)

Expand Down Expand Up @@ -61,6 +62,7 @@
- [`man bootc-container-inspect`](man/bootc-container-inspect.8.md)
- [`man bootc-container-split-kernel-and-rootfs`](man/bootc-container-split-kernel-and-rootfs.8.md)
- [`man bootc-container-ukify`](man/bootc-container-ukify.8.md)
- [`man bootc-container-compute-composefs-digest`](man/bootc-container-compute-composefs-digest.8.md)
- [`man bootc-container-lint`](man/bootc-container-lint.8.md)

# Architecture
Expand All @@ -69,6 +71,10 @@
- [Filesystem](bootc-filesystem.7.md)
- [Filesystem: sysroot](bootc-sysroot.7.md)
- [Container storage](bootc-container-storage.7.md)
- [composefs backend](bootc-composefs.7.md)
- [`man bootc-root-setup.service`](man/bootc-root-setup.service.5.md)
- [`man bootc-setup-root-conf.toml`](man/bootc-setup-root-conf.5.md)
- [`man bootc-composefs-finalize-staged`](man/bootc-composefs-finalize-staged.8.md)
- [Bootloader](bootc-bootloaders.7.md)
- [`man bootc-loader-entries`](man/bootc-loader-entries.8.md)
- [`man bootc-loader-entries-set-options-for-source`](man/bootc-loader-entries-set-options-for-source.8.md)
Expand All @@ -81,11 +87,7 @@
# Experimental features

- [bootc image](bootc-experimental-image.7.md)
- [composefs backend](bootc-experimental-composefs.7.md)
- [`man bootc-composefs-finalize-staged`](man/bootc-composefs-finalize-staged.8.md)
- [unified storage](bootc-experimental-unified-storage.7.md)
- [`man bootc-root-setup.service`](man/bootc-root-setup.service.5.md)
- [`man bootc-setup-root-conf.toml`](man/bootc-setup-root-conf.5.md)
- [fsck](bootc-experimental-fsck.7.md)
- [install reset](bootc-experimental-install-reset.7.md)
- [--progress-fd](bootc-experimental-progress-fd.7.md)
Expand Down
6 changes: 6 additions & 0 deletions docs/src/bootc-bootloaders.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ It is possible to skip bootloader installation entirely by using `--bootloader=n
With this option, users can have explicit control over how the boot loading is handled, without bootc or bootupd intervention.

NOTE: none is only supported for the Ostree backend and not for Composefs. It is also not supported for the s390x architecture. If used with `--generic-image`, it will lead to a generic image that does not have support for any bootloader.

## composefs backend

Whenever the container image has a UKI, bootc automatically selects the composefs backend during installation. The [prerequisites for sealed images](building/bootc-sealed-images.7.md#prerequisites) describe the currently-supported UKI + systemd-boot configuration. Note that having a UKI does not by itself make an install sealed — that also depends on whether [fs-verity enforcement](bootc-composefs.7.md#overview) is on.

Composefs installs using a traditional `vmlinuz`/`initramfs.img` layout instead of a UKI can enforce fs-verity, but are never sealed, since nothing authenticates the root digest. They can use either `bootupd` (GRUB) or systemd-boot. Under the hood, bootc writes standard BLS boot entries for both UKI and traditional kernels; see the [composefs boot module documentation](https://github.com/bootc-dev/bootc/blob/main/crates/lib/src/bootc_composefs/boot.rs) for details on how entry filenames and sort-keys are chosen to sort correctly on both GRUB and systemd-boot.
2 changes: 1 addition & 1 deletion docs/src/bootc-compatible-images.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The Linux kernel (and optionally initramfs) is embedded in the container image;

### Kernel (sealed UKI)

For the composefs backend, the UKI must be located at `/boot/EFI/Linux/$kver.efi`.
For the composefs backend, the UKI must be located at `/boot/EFI/Linux/$kver.efi`. See [sealed images](building/bootc-sealed-images.7.md).

### /ostree symlink and `bootc container lint`

Expand Down
170 changes: 170 additions & 0 deletions docs/src/bootc-composefs.7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# composefs backend

bootc has two storage backends. The default is [ostree](https://github.com/ostreedev/ostree),
and the composefs backend uses [composefs-rs](https://github.com/composefs/composefs-rs)
instead of ostree to store and manage deployments. Both are supported and
covered by the project's [stability guarantees](https://github.com/bootc-dev/bootc/blob/main/RELEASES.md#stability-guarantees).
In particular, the project is committed to upgrading every composefs system
installed since bootc 1.16.0 in place.

The composefs backend is required for [sealed images](building/bootc-sealed-images.7.md),
and the image determines which backend `bootc install` uses; see
[Understanding `bootc install`](bootc-installation.7.md#composefs-backend). Its
on-disk layout is described in [Filesystem: sysroot](bootc-sysroot.7.md#composefs-backend-storage).

## Overview

The composefs backend has two independent integrity controls:

- **fs-verity enforcement.** By default every object in the composefs
repository must have fs-verity enabled, and the root filesystem is only
mounted if its digest matches the one on the kernel command line. Building a
UKI with `--allow-missing-verity` adds a `?` marker to that argument, which
makes fs-verity optional (for filesystems such as XFS that lack it). Both UKI
and traditional kernel/initramfs installs can enforce fs-verity.
- **Boot authentication.** In a *sealed* deployment fs-verity is enforced and
the expected root digest is embedded in a UKI signed for Secure Boot, so
firmware authenticates the digest and the digest authenticates the root
filesystem. A BLS entry or an
unsigned UKI still has fs-verity checked at mount time, but nothing
authenticates the digest itself.

## EROFS formats

composefs-rs can encode the EROFS image for a root filesystem in two formats,
which produce different digests for the same content:

- **V1** is compatible with the C composefs tools and is the default for new
repositories.
- **V2** is the older composefs-rs format, kept as a fallback.

The `composefs.digest=` kernel argument names the format along with the
digest, for example `composefs.digest=v1-sha512-12:<digest>`, so it is
unambiguous. The older bare `composefs=<digest>` argument is not: released
UKIs carry either a V1 or a V2 digest there (see below), so bootc tries both.

By default `bootc container ukify` computes both digests and writes the V1
`composefs.digest=` argument followed by a bare `composefs=` argument with the
V2 digest, for older clients. `--erofs-version=v2` writes only the bare V2
argument.

Each argument names one exact image. Staging fails unless every digest in the
UKI matches an image bootc generated for that container image. At boot,
bootc's initramfs tries the arguments in order and moves on to the next one if
an image is missing, but an image that fails fs-verity checks stops the boot.
bootc never substitutes a different digest.

Existing repositories keep the format configuration recorded in their
metadata; opening one with a newer bootc doesn't convert it.

### The bare `composefs=` argument

Released UKIs have used the bare `composefs=<digest>` argument for different
formats:

- bootc 1.16.0 through 1.16.2 predate format versioning and use the original
composefs-rs encoding that V2 descends from.
- bootc 1.16.3 writes a V2 digest.
- bootc 1.16.4 through 1.16.13 write a **V1** digest: the switch to the V1
format shipped before the `composefs.digest=` argument did.
- Releases after 1.16.13 write V2 there again, after an explicit V1 argument.

So bootc accepts a bare `composefs=` digest that matches either a V1 or a V2
image, and only enforces the format for `composefs.digest=`.

### Upgrading from bootc 1.16

When you update bootc in an image, **regenerate the initramfs before
generating the UKI**. The initramfs contains bootc's own mount logic, and
keeping an old initramfs with a newer bootc is not supported.

For a sealed deployment, sign the new UKI with a key the existing machine
trusts. If the deployment was built with `--allow-missing-verity`, keep that
flag. Then publish the image and run `bootc upgrade` as usual.

What happens next depends on the bootc version doing the staging. A client
that only understands `composefs=`, such as 1.16.0, stages the V2 fallback;
the new initramfs boots it, and the next upgrade (now staged by the new bootc)
moves the system to V1. bootc 1.16.4 and later already understand
`composefs.digest=` and stage V1 directly.

The 1.16.0 path is covered by the `test-49-composefs-1-16-bridge` TMT test for
both sealed and `--allow-missing-verity` UKIs, including rollback and garbage
collection. Upgrades of UKI installs from other releases are not yet tested.

## Supported configurations

The following are supported with the composefs backend:

- `bootc install`, `upgrade`, `switch`, `rollback`, `status`, `usr-overlay`
and soft reboots.
- [`bootc install mount`](man/bootc-install-mount.8.md), for changing an
installed deployment before its first boot.
- Traditional kernel and initramfs installs booted through BLS entries, with
either GRUB (via `bootupd`) or systemd-boot, and UKIs booted with
systemd-boot, including sealed UKIs signed for Secure Boot. See
[Bootloaders](bootc-bootloaders.7.md#composefs-backend).
- Root filesystems with fs-verity support, and filesystems without it (such
as XFS) with fs-verity made optional. Sealed images require fs-verity.
CI covers ext4 and XFS; btrfs is expected to work but is not tested.
- The [EROFS formats](#erofs-formats) and kernel arguments described above.
- The image build commands `bootc container ukify`,
`bootc container split-kernel-and-rootfs` and
`bootc container compute-composefs-digest`, and the initramfs setup
configured by [`setup-root-conf.toml`](man/bootc-setup-root-conf.5.md).

On CentOS Stream 9, only sealed UKIs are tested; traditional kernel installs
require newer dracut and systemd features. Its dracut also doesn't install
`setup-root-conf.toml` into the initramfs automatically.

## Experimental parts

These remain [experimental](https://github.com/bootc-dev/bootc/blob/main/RELEASES.md#stability-guarantees)
and may change or be removed:

- The `grub-cc` bootloader (`--bootloader=grub-cc`).
- UKI addons (`--uki-addon`). Addons are only installed by `bootc install`:
they aren't updated on upgrade, garbage collected, or reverted on
rollback.
- [Unified storage](bootc-experimental-unified-storage.7.md).

## Limitations

- `bootc edit` and [`bootc install reset`](bootc-experimental-install-reset.7.md)
are not yet implemented for the composefs backend.
- There is no `bootc-boot-complete.service` and no boot counting; see
[boot failure detection](bootc-boot-failure-detection.7.md#composefs-backend-boot-failure-detection).
- There is no in-place transition from an ostree system to the composefs
backend yet, so for now a system has to be reinstalled. We fully intend to
support moving to composefs without a reinstall; see
[Future work](#future-work).
- `--bootloader=none` is not supported.
- `--soft-reboot=auto` doesn't fall back to a regular reboot when the new
deployment can't be soft rebooted into; see
[Soft reboots](bootc-upgrades.7.md#soft-reboots).
- Only a single ESP is used (the first one found), and a separate
XBOOTLDR partition is not supported.
- Rollback with GRUB and UKIs assumes exactly two deployments.
- `bootc internals fsck` doesn't yet comprehensively cover the composefs
backend; see [#2497](https://github.com/bootc-dev/bootc/pull/2497).

For building and testing bootc itself with the composefs backend, see
[CONTRIBUTING.md](https://github.com/bootc-dev/bootc/blob/main/CONTRIBUTING.md).

## Future work

- [Unified storage](https://github.com/bootc-dev/bootc/issues/20)
- [Sealed image build UX](https://github.com/bootc-dev/bootc/issues/1498): Streamlined tooling for building sealed images
- In place transitions:
- First: support [factory reset](https://github.com/bootc-dev/bootc/issues/404) from ostree to composefs
- Next: Support copying /etc and /var

## Additional Resources

- See [filesystem.md](bootc-filesystem.7.md) for information about composefs in the standard ostree backend
- See [bootloaders.md](bootc-bootloaders.7.md) for bootloader configuration details
- See [sealed images](building/bootc-sealed-images.7.md) for building UKIs and sealed images
- [composefs-rs](https://github.com/composefs/composefs-rs) - The underlying composefs implementation
- [composefs-rs repository format](https://github.com/composefs/composefs-rs/blob/main/crates/composefs/src/repository_format.rs) - Detailed on-disk layout of the `/composefs` repository
- [Unified Kernel Images specification](https://uapi-group.org/specifications/specs/unified_kernel_image/)
- [ukify documentation](https://www.freedesktop.org/software/systemd/man/latest/ukify.html) - Tool for building UKIs
Loading
Loading