Skip to content

Commit b17ca33

Browse files
committed
docs: Enhance installation documentation with DPS and provisioning flow
Add comprehensive documentation for the installation process, with particular focus on the Discoverable Partitions Specification (DPS) and first-boot provisioning. Main documentation (bootc-install.md): - Add DPS section explaining partition type GUIDs and auto-discovery - Add table showing when DPS vs explicit root= kargs are used - Add provisioning and first boot section covering cloud-init, Ignition, SSH key injection, and custom provisioning - Document the .bootc-aleph.json provenance file - Fix typos ('boot install' -> 'bootc install', 'pased' -> 'passed') Man page (bootc-install-to-disk.8.md): - Document partition layout conceptually (avoiding specific sizes/GUIDs that may change between versions) - Explain root filesystem discovery with systemd-gpt-auto-generator Rustdoc for install.rs: - Add comprehensive module documentation - Document all installation modes (to-disk, to-filesystem, to-existing-root, reset) - Explain OSTree vs Composefs storage backends - Document key types (State, RootSetup, SourceInfo, SELinuxFinalState) - List configuration paths and submodules Rustdoc for discoverable_partition_specification.rs: - Explain how bootc uses DPS for partition creation - Document automatic root discovery mechanism - Describe composefs and sealed boot integration Assisted-by: OpenCode (Claude Sonnet 4) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent d790891 commit b17ca33

4 files changed

Lines changed: 370 additions & 7 deletions

File tree

crates/lib/src/discoverable_partition_specification.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,68 @@
66
//! UAPI Group's Discoverable Partitions Specification.
77
//!
88
//! Reference: <https://uapi-group.org/specifications/specs/discoverable_partitions_specification/>
9+
//!
10+
//! # Overview
11+
//!
12+
//! The Discoverable Partitions Specification (DPS) defines standardized partition
13+
//! type GUIDs that enable automatic discovery and mounting of partitions without
14+
//! explicit configuration. This is a key enabler for bootc's installation process
15+
//! and for modern systemd-based initramfs implementations.
16+
//!
17+
//! # How bootc uses DPS
18+
//!
19+
//! When `bootc install to-disk` creates partitions, it sets the appropriate DPS
20+
//! partition type GUID based on the target CPU architecture. This enables several
21+
//! important capabilities:
22+
//!
23+
//! ## Automatic root discovery
24+
//!
25+
//! With a DPS-aware bootloader and initramfs (containing `systemd-gpt-auto-generator`),
26+
//! the root filesystem can be discovered and mounted automatically without requiring
27+
//! a `root=` kernel argument. The initramfs:
28+
//!
29+
//! 1. Reads the EFI `LoaderDevicePartUUID` variable to identify the boot disk
30+
//! 2. Scans the GPT for a partition with the architecture-specific root type GUID
31+
//! 3. Mounts that partition as the root filesystem
32+
//!
33+
//! ## Architecture-specific partition types
34+
//!
35+
//! Each CPU architecture has its own root partition type GUID. This prevents
36+
//! accidentally booting a system on incompatible hardware. bootc uses
37+
//! [`this_arch_root`] to select the correct GUID at compile time.
38+
//!
39+
//! ## Composefs and sealed boot
40+
//!
41+
//! When using the composefs backend with UKIs (Unified Kernel Images), bootc can
42+
//! omit the `root=` kernel argument entirely. This enables:
43+
//!
44+
//! - Measured boot: The kernel command line is part of the UKI signature
45+
//! - Simplified image building: No machine-specific kernel arguments needed
46+
//! - systemd-repart integration: Future support for declarative partition management
47+
//!
48+
//! # Partition types included
49+
//!
50+
//! This module defines constants for:
51+
//!
52+
//! - **Root partitions**: Architecture-specific root filesystem partitions
53+
//! - **USR partitions**: Separate `/usr` partitions (included for spec completeness; not currently used by bootc)
54+
//! - **Verity partitions**: dm-verity hash partitions for integrity verification
55+
//! - **Verity signature partitions**: Signed verity root hashes
56+
//! - **Special partitions**: ESP, XBOOTLDR, swap, home, var, etc.
57+
//!
58+
//! # Usage (internal)
59+
//!
60+
//! This is an internal module. Within bootc, it is used like:
61+
//!
62+
//! ```ignore
63+
//! use crate::discoverable_partition_specification::{this_arch_root, ESP};
64+
//!
65+
//! // Get the root partition type GUID for the current architecture
66+
//! let root_type: &str = this_arch_root();
67+
//!
68+
//! // ESP GUID is architecture-independent
69+
//! let esp_type: &str = ESP;
70+
//! ```
971
1072
// ============================================================================
1173
// ROOT PARTITIONS

crates/lib/src/install.rs

Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,141 @@
11
//! # Writing a container to a block device in a bootable way
22
//!
3-
//! This module supports installing a bootc-compatible image to
4-
//! a block device directly via the `install` verb, or to an externally
5-
//! set up filesystem via `install to-filesystem`.
3+
//! This module implements the core installation logic for bootc, enabling a container
4+
//! image to be written to storage in a bootable form. It bridges the gap between
5+
//! OCI container images and traditional bootable Linux systems.
6+
//!
7+
//! ## Overview
8+
//!
9+
//! The installation process transforms a container image into a bootable system by:
10+
//!
11+
//! 1. **Preparing the environment**: Validating we're running in a privileged container,
12+
//! handling SELinux re-execution if needed, and loading configuration.
13+
//!
14+
//! 2. **Setting up storage**: Either creating partitions (`to-disk`) or using
15+
//! externally-prepared filesystems (`to-filesystem`).
16+
//!
17+
//! 3. **Deploying the image**: Pulling the container image into an ostree repository
18+
//! and creating a deployment, or setting up a composefs-based root.
19+
//!
20+
//! 4. **Installing the bootloader**: Using bootupd, systemd-boot, or zipl depending
21+
//! on architecture and configuration.
22+
//!
23+
//! 5. **Finalizing**: Trimming the filesystem, flushing writes, and freezing/thawing
24+
//! the journal.
25+
//!
26+
//! ## Installation Modes
27+
//!
28+
//! ### `bootc install to-disk`
29+
//!
30+
//! Creates a complete bootable system on a block device. This is the simplest path
31+
//! and handles partitioning automatically using the Discoverable Partitions
32+
//! Specification (DPS). The partition layout includes:
33+
//!
34+
//! - **ESP** (EFI System Partition): Required for UEFI boot
35+
//! - **BIOS boot partition**: For legacy boot on x86_64
36+
//! - **Boot partition**: Optional, used when LUKS encryption is enabled
37+
//! - **Root partition**: Uses architecture-specific DPS type GUIDs for auto-discovery
38+
//!
39+
//! ### `bootc install to-filesystem`
40+
//!
41+
//! Installs to a pre-mounted filesystem, allowing external tools to handle complex
42+
//! storage layouts (RAID, LVM, custom LUKS configurations). The caller is responsible
43+
//! for creating and mounting the filesystem, then providing appropriate `--karg`
44+
//! options or mount specifications.
45+
//!
46+
//! ### `bootc install to-existing-root`
47+
//!
48+
//! "Alongside" installation mode that converts an existing Linux system. The boot
49+
//! partition is wiped and replaced, but the root filesystem content is preserved
50+
//! until reboot. Post-reboot, the old system is accessible at `/sysroot` for
51+
//! data migration.
52+
//!
53+
//! ### `bootc install reset`
54+
//!
55+
//! Creates a new stateroot within an existing bootc system, effectively providing
56+
//! a factory-reset capability without touching other stateroots.
57+
//!
58+
//! ## Storage Backends
59+
//!
60+
//! ### OSTree Backend (Default)
61+
//!
62+
//! Uses ostree-ext to convert container layers into an ostree repository. The
63+
//! deployment is created via `ostree admin deploy`, and bootloader entries are
64+
//! managed via BLS (Boot Loader Specification) files.
65+
//!
66+
//! ### Composefs Backend (Experimental)
67+
//!
68+
//! Alternative backend using composefs overlayfs for the root filesystem. Provides
69+
//! stronger integrity guarantees via fs-verity and supports UKI (Unified Kernel
70+
//! Images) for measured boot scenarios.
71+
//!
72+
//! ## Discoverable Partitions Specification (DPS)
73+
//!
74+
//! As of bootc 1.11, partitions are created with DPS type GUIDs from the
75+
//! [UAPI Group specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/).
76+
//! This enables:
77+
//!
78+
//! - **Auto-discovery**: systemd-gpt-auto-generator can mount partitions without
79+
//! explicit configuration
80+
//! - **Architecture awareness**: Root partition types are architecture-specific,
81+
//! preventing cross-architecture boot issues
82+
//! - **Future extensibility**: Enables systemd-repart for declarative partition
83+
//! management
84+
//!
85+
//! See [`crate::discoverable_partition_specification`] for the partition type GUIDs.
86+
//!
87+
//! ## Installation Flow
88+
//!
89+
//! The high-level flow is:
90+
//!
91+
//! 1. **CLI entry** → [`install_to_disk`], [`install_to_filesystem`], or [`install_to_existing_root`]
92+
//! 2. **Preparation** → [`prepare_install`] validates environment, handles SELinux, loads config
93+
//! 3. **Storage setup** → (to-disk only) [`baseline::install_create_rootfs`] partitions and formats
94+
//! 4. **Deployment** → [`install_to_filesystem_impl`] branches to OSTree or Composefs backend
95+
//! 5. **Bootloader** → [`crate::bootloader::install_via_bootupd`] or architecture-specific installer
96+
//! 6. **Finalization** → [`finalize_filesystem`] trims, flushes, and freezes the filesystem
97+
//!
98+
//! For a visual diagram of this flow, see the bootc documentation.
99+
//!
100+
//! ## Key Types
101+
//!
102+
//! - [`State`]: Immutable global state for the installation, including source image
103+
//! info, SELinux state, configuration, and composefs options.
104+
//!
105+
//! - [`RootSetup`]: Represents the prepared root filesystem, including mount paths,
106+
//! device information, boot partition specs, and kernel arguments.
107+
//!
108+
//! - [`SourceInfo`]: Information about the source container image, including the
109+
//! ostree-container reference and whether SELinux labels are present.
110+
//!
111+
//! - [`SELinuxFinalState`]: Tracks SELinux handling during installation (enabled,
112+
//! disabled, host-disabled, or force-disabled).
113+
//!
114+
//! ## Configuration
115+
//!
116+
//! Installation is configured via TOML files loaded from multiple paths in
117+
//! systemd-style priority order:
118+
//!
119+
//! - `/usr/lib/bootc/install/*.toml` - Distribution/image defaults
120+
//! - `/etc/bootc/install/*.toml` - Local overrides
121+
//!
122+
//! Files are merged alphanumerically, with higher-numbered files taking precedence.
123+
//! See [`config::InstallConfiguration`] for the schema.
124+
//!
125+
//! Key configurable options include:
126+
//! - Root filesystem type (xfs, ext4, btrfs)
127+
//! - Allowed block setups (direct, tpm2-luks)
128+
//! - Default kernel arguments
129+
//! - Architecture-specific overrides
130+
//!
131+
//! ## Submodules
132+
//!
133+
//! - [`baseline`]: The "baseline" installer for simple partitioning (to-disk)
134+
//! - [`config`]: TOML configuration parsing and merging
135+
//! - [`completion`]: Post-installation hooks for external installers (Anaconda)
136+
//! - [`osconfig`]: SSH key injection and OS configuration
137+
//! - [`aleph`]: Installation provenance tracking (.bootc-aleph.json)
138+
//! - `osbuild`: Helper APIs for bootc-image-builder integration
6139
7140
// This sub-module is the "basic" installer that handles creating basic block device
8141
// and filesystem setup.

docs/src/bootc-install.md

Lines changed: 151 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ This requires running the container via `--privileged`; it uses the running Linu
2626
on the host to write the file content from the running container image; not the kernel
2727
inside the container.
2828

29-
There are two sub-commands: `bootc install to-disk` and `boot install to-filesystem`.
29+
There are two sub-commands: `bootc install to-disk` and `bootc install to-filesystem`.
3030

3131
However, nothing *else* (external) is required to perform a basic installation
3232
to disk - the container image itself comes with a baseline self-sufficient installer
@@ -217,7 +217,7 @@ podman run --rm --privileged -v /dev:/dev -v /var/lib/containers:/var/lib/contai
217217
bootc install to-existing-root
218218
```
219219

220-
It is assumed in this command that the target rootfs is pased via `-v /:/target` at this time.
220+
It is assumed in this command that the target rootfs is passed via `-v /:/target` at this time.
221221

222222
As noted above, the data in `/boot` will be wiped, but everything else in the existing
223223
operating `/` is **NOT** automatically cleaned up. This can
@@ -346,6 +346,84 @@ This argument is mainly useful for 3rd-party tooling for building disk images fr
346346
containers (e.g. based on [osbuild](https://github.com/osbuild/osbuild)).
347347

348348

349+
## Discoverable Partitions Specification (DPS)
350+
351+
As of bootc 1.11, the default partitioning layout for `bootc install to-disk` uses the
352+
[Discoverable Partitions Specification (DPS)](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/)
353+
from the UAPI Group. This is an important foundation for modern Linux systems.
354+
355+
### What is DPS?
356+
357+
The Discoverable Partitions Specification defines well-known partition type GUIDs for
358+
different purposes (root filesystem, ESP, swap, /home, etc.) and for different CPU
359+
architectures. When partitions use these standardized type GUIDs, systemd and other
360+
tools can automatically discover and mount them without explicit configuration.
361+
362+
Each supported CPU architecture has its own root partition type GUID. See the
363+
[DPS specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/)
364+
for the complete list of partition types.
365+
366+
### How bootc uses DPS
367+
368+
When `bootc install to-disk` creates partitions, it sets the appropriate DPS partition
369+
type GUID based on the target architecture. This enables:
370+
371+
1. **Automatic root discovery**: With a DPS-aware bootloader and initramfs, the root
372+
filesystem can be discovered automatically without a `root=` kernel argument.
373+
This is handled by [systemd-gpt-auto-generator](https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html).
374+
375+
2. **Sealed/verified boot paths**: When using composefs with UKIs (Unified Kernel Images),
376+
bootc can omit the `root=` kernel argument entirely. The initramfs uses DPS to find
377+
the root partition, and composefs provides integrity verification.
378+
379+
3. **Future systemd-repart integration**: DPS partition types allow systemd-repart to
380+
automatically grow or create partitions based on declarative configuration.
381+
382+
### When is DPS used vs explicit kernel arguments?
383+
384+
| Installation Mode | Root Discovery Method |
385+
|-------------------|----------------------|
386+
| `to-disk` | Explicit `root=UUID=...` karg |
387+
| `to-filesystem --root-mount-spec=""` | DPS auto-discovery (no `root=` karg) |
388+
| `to-filesystem` (default) | Uses filesystem UUID as `root=UUID=...` karg |
389+
| `to-existing-root` | Inherits from existing system |
390+
391+
For `to-disk`, bootc always injects a `root=UUID=<uuid>` kernel argument for
392+
compatibility, even though the partition type is set to the DPS GUID. This
393+
ensures the system boots on initramfs implementations that don't support
394+
DPS auto-discovery.
395+
396+
For `to-filesystem`, the `--root-mount-spec=""` option (empty string) can be
397+
used to omit the `root=` kernel argument entirely, enabling DPS auto-discovery.
398+
This is useful when the bootloader and initramfs both support the
399+
[Boot Loader Interface](https://systemd.io/BOOT_LOADER_INTERFACE/).
400+
401+
### Bootloader requirements for DPS auto-discovery
402+
403+
DPS auto-discovery requires a bootloader that implements the Boot Loader
404+
Interface and sets the `LoaderDevicePartUUID` EFI variable. Supported
405+
bootloaders include:
406+
407+
- **GRUB 2.12+** with the `bli` module (included in Fedora 43+, requires EFI boot)
408+
- **systemd-boot** (always supports the Boot Loader Interface)
409+
410+
Older GRUB versions (without the `bli` module) do not set this variable and
411+
DPS auto-discovery will not work.
412+
413+
### Implications for external installers
414+
415+
If you're building tooling that uses `bootc install to-filesystem`, you should:
416+
417+
1. **Set appropriate partition types**: Use the DPS type GUID for the root partition
418+
when creating partitions externally.
419+
420+
2. **Consider auto-discovery**: If your bootloader and initramfs support DPS, you
421+
may be able to omit `root=` kernel arguments entirely.
422+
423+
3. **Use `rootflags` for mount options**: Prefer the `rootflags=` kernel argument
424+
over `/etc/fstab` for root mount options, as this works better with composefs
425+
and DPS auto-discovery.
426+
349427
## Finding and configuring the physical root filesystem
350428

351429
On a bootc system, the "physical root" is different from
@@ -393,3 +471,74 @@ Installation software such as [Anaconda](https://github.com/rhinstaller/anaconda
393471
do this today to implement generic `%post` scripts and the like.
394472

395473
However, it is very likely that a generic bootc API to do this will be added.
474+
475+
## Provisioning and first boot
476+
477+
After `bootc install` completes, the system is ready for first boot. A key
478+
design principle is that **minimal machine-specific configuration should be
479+
injected at install time**. Instead, most configuration should happen at
480+
runtime—either at first boot or on every boot—using standard Linux mechanisms.
481+
482+
This approach has several benefits:
483+
484+
- **Simpler installation**: The install process doesn't need to know about
485+
every possible configuration option
486+
- **Better fits the container model**: Configuration logic lives in the
487+
container image, not in external tooling
488+
- **Easier updates**: Runtime configuration naturally applies to updated
489+
deployments
490+
491+
### Install-time configuration
492+
493+
When some machine-specific data must be provided at install time, the preferred
494+
approaches depend on your boot setup:
495+
496+
- **Type 1 BLS setups**: Use `bootc install --karg` to inject kernel arguments.
497+
For example, `--karg ip=192.168.1.100::192.168.1.1:255.255.255.0:host1::none`
498+
for static IP configuration, or `--karg console=ttyS0,115200` for serial console.
499+
500+
- **UKI setups**: Use [UKI addons](https://uapi-group.org/specifications/specs/unified_kernel_image/#addon-uki-format)
501+
(additional signed PE binaries containing extra kernel arguments or initrd content)
502+
to provide machine-specific configuration while preserving the signed UKI.
503+
504+
### Runtime configuration approaches
505+
506+
Since bootc systems are standard Linux systems, any provisioning tool that
507+
works on Linux will work with bootc. Common approaches include:
508+
509+
- **cloud-init**: If included in your container image, runs at first boot to
510+
configure users, SSH keys, networking, and run custom scripts
511+
- **Ignition**: Runs in the initramfs before the real root is mounted; used
512+
by Fedora CoreOS-style systems
513+
- **systemd-firstboot**: Configures locale, timezone, hostname, etc. on first boot
514+
- **Custom systemd services**: Use `ConditionFirstBoot=yes` for one-time setup,
515+
or run on every boot for dynamic configuration
516+
517+
The choice of provisioning tool depends on your base image and deployment
518+
environment—bootc itself is agnostic.
519+
520+
### SSH key injection
521+
522+
For simple SSH access without a full provisioning system, bootc provides the
523+
`--root-ssh-authorized-keys` option:
524+
525+
```bash
526+
bootc install to-disk --root-ssh-authorized-keys /path/to/authorized_keys /dev/sda
527+
```
528+
529+
This writes a systemd-tmpfiles configuration that ensures the SSH keys are
530+
present on every boot, even if `/root` is a tmpfs.
531+
532+
### The `.bootc-aleph.json` file
533+
534+
After installation, bootc writes a JSON file at the root of the physical
535+
filesystem (`.bootc-aleph.json`) containing installation provenance information:
536+
537+
- The source image reference and digest
538+
- Installation timestamp
539+
- bootc version
540+
- Kernel version
541+
- SELinux state
542+
543+
This file is useful for auditing and understanding how a system was provisioned.
544+
From the booted system, this file is accessible at `/sysroot/.bootc-aleph.json`.

0 commit comments

Comments
 (0)