Initial commit: Comprehensive Debian bootc documentation

- Complete documentation for all bootc commands and subcommands
- Debian-specific adaptations and workarounds
- Manual installation methods to bypass bootc reliability issues
- Technical guides with Rust source code analysis
- Flowcharts and external command references
- Hidden command documentation (bootc internals, state, etc.)
- Composefs integration analysis
- Base image creation guides (with and without bootc binary)
- Management scripts and automation
- Comprehensive troubleshooting and examples
This commit is contained in:
robojerk 2025-09-15 14:02:28 -07:00
commit 526f1c1afd
67 changed files with 34174 additions and 0 deletions

View file

@ -0,0 +1,422 @@
# bootc External Commands Reference
## Overview
This document provides a comprehensive reference for all external commands used by bootc during the installation process. These commands are executed by bootc to perform various system operations that cannot be handled internally.
## Required Commands
### 1. ostree - OSTree Repository Management
**Purpose**: Manages OSTree repositories for atomic updates and deployments
**Package**: `ostree`
**Key Commands Used**:
```bash
# Initialize OSTree filesystem
ostree admin init-fs --modern .
# Configure repository settings
ostree config --repo ostree/repo set sysroot.bootloader none
ostree config --repo ostree/repo set sysroot.bootprefix true
ostree config --repo ostree/repo set sysroot.readonly true
# Parse commit information
ostree --repo=/ostree/repo rev-parse --single
# Read commit metadata
ostree read-commit <commit-hash>
```
**Configuration Files**:
- Repository config: `ostree/repo/config`
- Deployment config: `ostree/deploy/*/var/lib/ostree/config`
**Error Handling**:
- Repository corruption detection
- Commit validation
- Configuration validation
### 2. bootupd - Bootloader Management
**Purpose**: Manages bootloader installation and configuration
**Package**: `bootupd`
**Key Commands Used**:
```bash
# Install bootloader
bootupctl install
# Generate bootloader configuration
bootupctl generate
# Check bootloader status
bootupctl status
# Update bootloader
bootupctl update
```
**Configuration Files**:
- Bootloader state: `/boot/bootupd-state.json`
- GRUB config: `/boot/grub2/grub.cfg`
- EFI config: `/boot/efi/EFI/*/grub.cfg`
**Architecture Support**:
- x86_64: GRUB2
- aarch64: GRUB2
- s390x: zipl (via separate implementation)
### 3. podman - Container Runtime
**Purpose**: Container runtime for running bootc installation
**Package**: `podman`
**Required Flags**:
```bash
podman run --rm --privileged --pid=host \
-v /var/lib/containers:/var/lib/containers \
-v /dev:/dev \
--security-opt label=type:unconfined_t \
<image> bootc install to-disk /dev/target
```
**Container Environment Variables**:
- `CONTAINER_ENGINE=podman`
- `CONTAINER_IMAGE_ID=<image-id>`
- `CONTAINER_IMAGE=<image-name>`
- `CONTAINER_ROOTLESS=<0|1>`
### 4. Filesystem Management Commands
#### fstrim - Filesystem Optimization
**Purpose**: Trim filesystem to optimize performance
**Package**: `util-linux`
**Command Used**:
```bash
fstrim --quiet-unsupported -v /target
```
**Options**:
- `--quiet-unsupported`: Suppress errors for unsupported filesystems
- `-v`: Verbose output
#### mount/umount - Filesystem Mounting
**Purpose**: Mount and unmount filesystems
**Package**: `util-linux`
**Commands Used**:
```bash
# Mount filesystem
mount /dev/target /mnt
# Remount read-only
mount -o remount,ro /target
# Unmount filesystem
umount -R /target
```
#### fsfreeze - Filesystem Freeze/Thaw
**Purpose**: Freeze and thaw filesystems for consistency
**Package**: `util-linux`
**Commands Used**:
```bash
# Freeze filesystem
fsfreeze -f /target
# Thaw filesystem
fsfreeze -u /target
```
## Optional Commands
### 1. cryptsetup - LUKS Encryption
**Purpose**: Handle LUKS encrypted devices
**Package**: `cryptsetup`
**Commands Used**:
```bash
# Close LUKS device
cryptsetup close <device-name>
# Open LUKS device
cryptsetup open <device> <name>
# Create LUKS device
cryptsetup luksFormat <device>
```
**Integration**:
- TPM2-LUKS support via systemd-cryptenroll
- LUKS device detection and management
- Encryption key handling
### 2. grub2-mkconfig - GRUB Configuration
**Purpose**: Generate GRUB configuration files
**Package**: `grub2-tools`
**Commands Used**:
```bash
# Generate GRUB configuration
grub2-mkconfig -o /boot/grub2/grub.cfg
# Generate EFI configuration
grub2-mkconfig -o /boot/efi/EFI/*/grub.cfg
```
**Configuration Files**:
- GRUB config: `/etc/default/grub`
- GRUB scripts: `/etc/grub.d/*`
- Generated config: `/boot/grub2/grub.cfg`
### 3. dracut - Initramfs Generation
**Purpose**: Generate initramfs for boot
**Package**: `dracut`
**Commands Used**:
```bash
# Generate initramfs
dracut --force /boot/initramfs-<version>.img <version>
# Regenerate with specific modules
dracut --add-drivers <modules> --force
```
**Integration**:
- Initramfs generation during container build
- Module detection and inclusion
- Boot-time filesystem setup
### 4. Filesystem Creation Commands
#### mkfs.* - Filesystem Creation
**Purpose**: Create various filesystem types
**Package**: `util-linux`, `e2fsprogs`, `xfsprogs`, `btrfs-progs`
**Commands Used**:
```bash
# Create XFS filesystem
mkfs.xfs /dev/target
# Create ext4 filesystem
mkfs.ext4 /dev/target
# Create Btrfs filesystem
mkfs.btrfs /dev/target
```
**Configuration**:
- Filesystem type determined by install config
- Default type: XFS
- Configurable via `/usr/lib/bootc/install/*.toml`
## Command Execution Patterns
### 1. Task Execution
```rust
// From install.rs - Task execution pattern
Task::new("Operation description", "command")
.args(["arg1", "arg2"])
.cwd(target_directory)?
.run()?;
```
### 2. Command with Capture
```rust
// From install.rs - Command with stderr capture
Command::new("command")
.args(["arg1", "arg2"])
.cwd_dir(target_directory)
.run_capture_stderr()?;
```
### 3. Async Command Execution
```rust
// From install.rs - Async command execution
let result = tokio::task::spawn_blocking(move || {
Command::new("command")
.args(["arg1", "arg2"])
.run()
}).await??;
```
## Error Handling
### 1. Command Not Found
**Detection**: Process exit code 127
**Handling**: Check package installation
**Recovery**: Install required package
### 2. Permission Denied
**Detection**: Process exit code 13
**Handling**: Check user privileges
**Recovery**: Run with appropriate privileges
### 3. Resource Exhaustion
**Detection**: Process exit code 28
**Handling**: Check disk space, memory
**Recovery**: Free up resources
### 4. Filesystem Errors
**Detection**: Process exit code 1
**Handling**: Check filesystem state
**Recovery**: Repair filesystem if possible
## Security Considerations
### 1. Command Injection Prevention
- All commands use structured arguments
- No shell interpretation
- Input validation and sanitization
### 2. Privilege Escalation
- Commands run with minimal required privileges
- SELinux context preservation
- Capability dropping where possible
### 3. Resource Limits
- Disk space validation before operations
- Memory usage monitoring
- File descriptor limits
## Performance Optimization
### 1. Parallel Execution
- Independent commands run in parallel
- I/O operations optimized
- Resource usage balanced
### 2. Caching
- OSTree repository caching
- Container image layer caching
- Configuration caching
### 3. Resource Management
- Temporary file cleanup
- Memory usage optimization
- Disk I/O optimization
## Debugging Commands
### 1. System Information
```bash
# Check OSTree status
ostree admin status
# Check bootloader status
bootupctl status
# Check filesystem usage
df -h
# Check mounted filesystems
mount | grep -E "(ostree|boot)"
```
### 2. Container Information
```bash
# List container images
podman images
# Check container storage
podman system df
# Inspect container image
podman inspect <image>
```
### 3. Boot Information
```bash
# Check kernel command line
cat /proc/cmdline
# Check bootloader entries
ls /boot/loader/entries/
# Check EFI variables
efibootmgr -v
```
## Troubleshooting
### 1. Common Issues
**OSTree Repository Corruption**:
```bash
# Repair repository
ostree admin init-fs --modern .
```
**Bootloader Installation Failure**:
```bash
# Reinstall bootloader
bootupctl install --force
```
**Filesystem Mount Issues**:
```bash
# Check mount options
mount | grep <device>
# Remount with correct options
mount -o remount,<options> <device>
```
### 2. Log Analysis
**Systemd Journal**:
```bash
# Check bootc logs
journalctl -u bootc*
# Check installation logs
journalctl -f | grep bootc
```
**OSTree Logs**:
```bash
# Check OSTree operations
journalctl -u ostree*
# Check repository operations
ostree log <commit>
```
This reference provides comprehensive information about all external commands used by bootc, their purposes, usage patterns, and troubleshooting approaches.

View file

@ -0,0 +1,282 @@
# bootc Installation Process Flowchart
## High-Level Installation Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ bootc Installation Process │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Phase 1: Preparation │
├─────────────────────────────────────────────────────────────────┤
│ 1.1 Container Environment Detection │
│ ├─ Check podman runtime │
│ ├─ Validate container execution info │
│ └─ Verify privileged access │
│ │
│ 1.2 Privilege and Namespace Validation │
│ ├─ Require --pid=host flag │
│ ├─ Validate host user namespace │
│ └─ Check root privileges │
│ │
│ 1.3 SELinux State Management │
│ ├─ Detect SELinux policy in container │
│ ├─ Check host SELinux state │
│ └─ Re-execute if needed for proper labeling │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Phase 2: Filesystem Setup │
├─────────────────────────────────────────────────────────────────┤
│ 2.1 OSTree Repository Initialization │
│ ├─ Check for existing ostree/repo │
│ ├─ Run: ostree admin init-fs --modern . │
│ ├─ Configure repository settings │
│ └─ Set up stateroot │
│ │
│ 2.2 Container Image Deployment │
│ ├─ Prepare container image for pull │
│ ├─ Check disk space requirements │
│ ├─ Pull image into OSTree repository │
│ ├─ Deploy container to target filesystem │
│ └─ Set up deployment metadata │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Phase 3: Bootloader Setup │
├─────────────────────────────────────────────────────────────────┤
│ 3.1 Bootupd Integration │
│ ├─ Detect target architecture │
│ ├─ Configure bootloader type │
│ └─ Install via bootupd │
│ │
│ 3.2 Architecture-Specific Bootloaders │
│ ├─ x86_64/aarch64: GRUB2 via bootupd │
│ ├─ s390x: zipl │
│ └─ Other: Platform-specific │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Phase 4: Kernel Configuration │
├─────────────────────────────────────────────────────────────────┤
│ 4.1 Kernel Argument Processing │
│ ├─ Extract kargs from OSTree root │
│ ├─ Merge install config kargs │
│ ├─ Apply container image kargs.d │
│ └─ Add CLI-specified kargs │
│ │
│ 4.2 Initramfs Integration │
│ ├─ Locate kernel: /usr/lib/modules/$kver/vmlinuz │
│ ├─ Locate initramfs: /usr/lib/modules/$kver/initramfs.img │
│ └─ Configure bootloader entries │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Phase 5: Finalization │
├─────────────────────────────────────────────────────────────────┤
│ 5.1 Filesystem Optimization │
│ ├─ Run: fstrim --quiet-unsupported -v /target │
│ ├─ Run: mount -o remount,ro /target │
│ └─ Run: fsfreeze -f /target && fsfreeze -u /target │
│ │
│ 5.2 Cleanup and Validation │
│ ├─ Close file descriptors │
│ ├─ Unmount target filesystem │
│ ├─ Close LUKS devices (if any) │
│ └─ Validate installation │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Installation Complete │
└─────────────────────────────────────────────────────────────────┘
```
## Detailed Installation Modes
### 1. to-disk Installation Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ bootc install to-disk │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 1. Validate Target Device │
│ ├─ Check if device is block device or file │
│ ├─ Handle loopback device if --via-loopback │
│ └─ Validate device permissions │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 2. Create Filesystem │
│ ├─ Determine filesystem type from config │
│ ├─ Run: mkfs.$fstype /dev/target │
│ └─ Set up partition table if needed │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 3. Mount and Deploy │
│ ├─ Mount: /dev/target /mnt │
│ ├─ Run: bootc install to-filesystem /mnt │
│ └─ Configure kernel arguments │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 4. Finalize │
│ ├─ Unmount: umount -R /mnt │
│ ├─ Close LUKS devices │
│ └─ Close loopback devices │
└─────────────────────────────────────────────────────────────────┘
```
### 2. to-filesystem Installation Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ bootc install to-filesystem │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 1. Validate Target Filesystem │
│ ├─ Check if target is directory │
│ ├─ Verify it's a mountpoint │
│ ├─ Detect if already OSTree system │
│ └─ Handle alongside installation │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 2. Clean Target (if needed) │
│ ├─ Wipe mode: Remove all contents │
│ ├─ Alongside mode: Clean boot directories │
│ └─ Default: Require empty root directory │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 3. Deploy Container Image │
│ ├─ Initialize OSTree repository │
│ ├─ Pull container image │
│ ├─ Deploy to target filesystem │
│ └─ Configure bootloader │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 4. Finalize │
│ ├─ Run: bootc install finalize │
│ ├─ Optimize filesystem │
│ └─ Validate installation │
└─────────────────────────────────────────────────────────────────┘
```
### 3. to-existing-root Installation Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ bootc install to-existing-root │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 1. Mount Host Root │
│ ├─ Mount: /:/target (if not already mounted) │
│ ├─ Detect existing OSTree system │
│ └─ Find physical root in /sysroot │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 2. Clean Boot Directories │
│ ├─ Remove existing bootloader configuration │
│ ├─ Clean /boot directory │
│ └─ Clean /boot/efi directory (if exists) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 3. Deploy Alongside │
│ ├─ Initialize OSTree repository │
│ ├─ Deploy container image │
│ ├─ Configure bootloader │
│ └─ Set up cleanup service │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 4. Setup Cleanup │
│ ├─ Create bootc-destructive-cleanup.service │
│ ├─ Configure for first boot cleanup │
│ └─ Preserve existing data in /sysroot │
└─────────────────────────────────────────────────────────────────┘
```
## Error Handling Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ Error Detection │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 1. Validation Errors │
│ ├─ Container environment issues │
│ ├─ Privilege/permission errors │
│ └─ SELinux policy conflicts │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 2. Resource Errors │
│ ├─ Insufficient disk space │
│ ├─ Memory allocation failures │
│ └─ File descriptor limits │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 3. Deployment Errors │
│ ├─ Container image pull failures │
│ ├─ OSTree repository issues │
│ └─ Bootloader installation failures │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 4. Recovery Actions │
│ ├─ Rollback OSTree deployment │
│ ├─ Restore bootloader configuration │
│ └─ Clean up partial installation │
└─────────────────────────────────────────────────────────────────┘
```
## External Command Dependencies
### Required Commands
- `ostree` - OSTree repository management
- `bootupd` - Bootloader management
- `podman` - Container runtime
- `fstrim` - Filesystem optimization
- `mount`/`umount` - Filesystem mounting
- `fsfreeze` - Filesystem freeze/thaw
### Optional Commands
- `cryptsetup` - LUKS encryption
- `grub2-mkconfig` - GRUB configuration
- `dracut` - Initramfs generation
- `mkfs.*` - Filesystem creation
This flowchart provides a comprehensive view of the bootc installation process, showing the sequential phases, decision points, and error handling paths.

View file

@ -0,0 +1,462 @@
# bootc Installation Source Code Analysis
## Overview
This document provides a detailed analysis of the bootc installation process based on the source code examination. The analysis covers the key components, data structures, and execution flow of the installation system.
## Core Data Structures
### 1. State Management
```rust
// From install.rs:373-390
pub(crate) struct State {
pub(crate) source: SourceInfo,
pub(crate) selinux_state: SELinuxFinalState,
pub(crate) config_opts: InstallConfigOpts,
pub(crate) target_imgref: ostree_container::OstreeImageReference,
pub(crate) prepareroot_config: HashMap<String, String>,
pub(crate) install_config: Option<config::InstallConfiguration>,
pub(crate) root_ssh_authorized_keys: Option<String>,
pub(crate) host_is_container: bool,
pub(crate) container_root: Dir,
pub(crate) tempdir: TempDir,
}
```
**Key Components**:
- `source`: Container image information and metadata
- `selinux_state`: SELinux configuration state
- `target_imgref`: Target image reference for updates
- `prepareroot_config`: OSTree prepareroot configuration
- `install_config`: Installation-specific configuration
### 2. Source Information
```rust
// From install.rs:360-370
pub(crate) struct SourceInfo {
pub(crate) imageref: ostree_container::ImageReference,
pub(crate) digest: Option<String>,
pub(crate) selinux: bool,
pub(crate) in_host_mountns: bool,
}
```
**Purpose**: Encapsulates information about the source container image
**Key Fields**:
- `imageref`: Container image reference
- `digest`: Image digest for verification
- `selinux`: SELinux policy presence
- `in_host_mountns`: Host mount namespace access
### 3. Root Setup
```rust
// From install.rs:928-942
pub(crate) struct RootSetup {
#[cfg(feature = "install-to-disk")]
luks_device: Option<String>,
device_info: bootc_blockdev::PartitionTable,
physical_root_path: Utf8PathBuf,
physical_root: Dir,
rootfs_uuid: Option<String>,
skip_finalize: bool,
boot: Option<MountSpec>,
kargs: Vec<String>,
}
```
**Purpose**: Manages target filesystem setup and configuration
**Key Fields**:
- `device_info`: Partition table information
- `physical_root`: Target filesystem directory
- `rootfs_uuid`: Root filesystem UUID
- `boot`: Boot filesystem mount specification
- `kargs`: Kernel arguments
## Installation Flow Analysis
### 1. Preparation Phase
#### Container Environment Detection
```rust
// From install.rs:520-538
pub(crate) fn from_container(
root: &Dir,
container_info: &ContainerExecutionInfo,
) -> Result<Self> {
if !container_info.engine.starts_with("podman") {
anyhow::bail!("Currently this command only supports being executed via podman");
}
if container_info.imageid.is_empty() {
anyhow::bail!("Invalid empty imageid");
}
let imageref = ostree_container::ImageReference {
transport: ostree_container::Transport::ContainerStorage,
name: container_info.image.clone(),
};
let digest = crate::podman::imageid_to_digest(&container_info.imageid)?;
Self::new(imageref, Some(digest), root, true)
}
```
**Key Operations**:
1. Validate podman runtime
2. Extract image reference from container environment
3. Resolve image digest
4. Detect SELinux policy presence
#### Privilege Validation
```rust
// From install.rs:1061-1082
fn require_host_pidns() -> Result<()> {
if rustix::process::getpid().is_init() {
anyhow::bail!("This command must be run with the podman --pid=host flag")
}
tracing::trace!("OK: we're not pid 1");
Ok(())
}
fn require_host_userns() -> Result<()> {
let proc1 = "/proc/1";
let pid1_uid = Path::new(proc1)
.metadata()
.with_context(|| format!("Querying {proc1}"))?
.uid();
ensure!(pid1_uid == 0, "{proc1} is owned by {pid1_uid}, not zero; this command must be run in the root user namespace");
tracing::trace!("OK: we're in a matching user namespace with pid1");
Ok(())
}
```
**Validation Steps**:
1. Check process ID (not PID 1)
2. Verify host user namespace access
3. Validate root privileges
### 2. OSTree Initialization
#### Repository Setup
```rust
// From install.rs:591-694
async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result<(Storage, bool)> {
let sepolicy = state.load_policy()?;
let sepolicy = sepolicy.as_ref();
let rootfs_dir = &root_setup.physical_root;
let cancellable = gio::Cancellable::NONE;
let stateroot = state.stateroot();
let has_ostree = rootfs_dir.try_exists("ostree/repo")?;
if !has_ostree {
Task::new("Initializing ostree layout", "ostree")
.args(["admin", "init-fs", "--modern", "."])
.cwd(rootfs_dir)?
.run()?;
} else {
println!("Reusing extant ostree layout");
let path = ".".into();
let _ = crate::utils::open_dir_remount_rw(rootfs_dir, path)
.context("remounting target as read-write")?;
crate::utils::remove_immutability(rootfs_dir, path)?;
}
// ... repository configuration
}
```
**Key Operations**:
1. Check for existing OSTree repository
2. Initialize repository if needed
3. Configure repository settings
4. Set up stateroot
5. Configure SELinux labeling
#### Repository Configuration
```rust
// From install.rs:624-629
for (k, v) in DEFAULT_REPO_CONFIG.iter() {
Command::new("ostree")
.args(["config", "--repo", "ostree/repo", "set", k, v])
.cwd_dir(rootfs_dir.try_clone()?)
.run_capture_stderr()?;
}
```
**Default Configuration**:
- `sysroot.bootloader=none`
- `sysroot.bootprefix=true`
- `sysroot.readonly=true`
### 3. Container Image Deployment
#### Image Pulling
```rust
// From install.rs:755-769
let pulled_image = match prepare_for_pull(repo, &spec_imgref, Some(&state.target_imgref))
.await?
{
PreparedPullResult::AlreadyPresent(existing) => existing,
PreparedPullResult::Ready(image_meta) => {
check_disk_space(root_setup.physical_root.as_fd(), &image_meta, &spec_imgref)?;
pull_from_prepared(&spec_imgref, false, ProgressWriter::default(), *image_meta).await?
}
};
```
**Process**:
1. Prepare image for pulling
2. Check disk space requirements
3. Pull image into OSTree repository
4. Handle already present images
#### Deployment
```rust
// From install.rs:826-836
let mut options = ostree_container::deploy::DeployOpts::default();
options.kargs = Some(kargs.as_slice());
options.target_imgref = Some(&state.target_imgref);
options.proxy_cfg = proxy_cfg;
options.skip_completion = true;
options.no_clean = has_ostree;
let imgstate = crate::utils::async_task_with_spinner(
"Deploying container image",
ostree_container::deploy::deploy(&sysroot, stateroot, &src_imageref, Some(options)),
)
.await?;
```
**Deployment Options**:
- Kernel arguments configuration
- Target image reference
- Proxy configuration
- Completion skipping
- Cleanup control
### 4. Bootloader Installation
#### Bootupd Integration
```rust
// From install.rs:1337-1343
crate::bootloader::install_via_bootupd(
&rootfs.device_info,
&rootfs.physical_root_path,
&state.config_opts,
&deployment_path.as_str(),
)?;
```
**Architecture Support**:
- x86_64/aarch64: GRUB2 via bootupd
- s390x: zipl implementation
- Other: Platform-specific
### 5. Kernel Argument Processing
#### Argument Collection
```rust
// From install.rs:773-825
let kargsd = crate::bootc_kargs::get_kargs_from_ostree_root(
&sysroot.repo(),
merged_ostree_root.downcast_ref().unwrap(),
std::env::consts::ARCH,
)?;
let kargsd = kargsd.iter().map(|s| s.as_str());
let install_config_kargs = state
.install_config
.as_ref()
.and_then(|c| c.kargs.as_ref())
.into_iter()
.flatten()
.map(|s| s.as_str());
let kargs = root_setup
.kargs
.iter()
.map(|v| v.as_str())
.chain(install_config_kargs)
.chain(kargsd)
.chain(state.config_opts.karg.iter().flatten().map(|v| v.as_str()))
.collect::<Vec<_>>();
```
**Argument Sources (Priority Order)**:
1. Root filesystem kargs
2. Install configuration kargs
3. Container image kargs.d files
4. CLI-specified kargs
### 6. Filesystem Finalization
#### Optimization Process
```rust
// From install.rs:1033-1058
pub(crate) fn finalize_filesystem(
fsname: &str,
root: &Dir,
path: impl AsRef<Utf8Path>,
) -> Result<()> {
let path = path.as_ref();
// fstrim ensures the underlying block device knows about unused space
Task::new(format!("Trimming {fsname}"), "fstrim")
.args(["--quiet-unsupported", "-v", path.as_str()])
.cwd(root)?
.run()?;
// Remounting readonly will flush outstanding writes
Task::new(format!("Finalizing filesystem {fsname}"), "mount")
.cwd(root)?
.args(["-o", "remount,ro", path.as_str()])
.run()?;
// Finally, freezing (and thawing) the filesystem will flush the journal
for a in ["-f", "-u"] {
Command::new("fsfreeze")
.cwd_dir(root.try_clone()?)
.args([a, path.as_str()])
.run_capture_stderr()?;
}
Ok(())
}
```
**Finalization Steps**:
1. Trim filesystem (fstrim)
2. Remount read-only
3. Freeze and thaw filesystem
4. Flush journal
## Error Handling Patterns
### 1. Contextual Error Handling
```rust
// From install.rs:393-404
#[context("Loading SELinux policy")]
pub(crate) fn load_policy(&self) -> Result<Option<ostree::SePolicy>> {
if !self.selinux_state.enabled() {
return Ok(None);
}
let r = lsm::new_sepolicy_at(&self.container_root)?
.ok_or_else(|| anyhow::anyhow!("SELinux enabled, but no policy found in root"))?;
tracing::debug!("Loaded SELinux policy: {}", r.csum().unwrap());
Ok(Some(r))
}
```
### 2. Resource Validation
```rust
// From install.rs:696-715
fn check_disk_space(
repo_fd: impl AsFd,
image_meta: &PreparedImportMeta,
imgref: &ImageReference,
) -> Result<()> {
let stat = rustix::fs::fstatvfs(repo_fd)?;
let bytes_avail: u64 = stat.f_bsize * stat.f_bavail;
if image_meta.bytes_to_fetch > bytes_avail {
anyhow::bail!(
"Insufficient free space for {image} (available: {bytes_avail} required: {bytes_to_fetch})",
bytes_avail = ostree_ext::glib::format_size(bytes_avail),
bytes_to_fetch = ostree_ext::glib::format_size(image_meta.bytes_to_fetch),
image = imgref.image,
);
}
Ok(())
}
```
### 3. Graceful Degradation
```rust
// From install.rs:1001-1029
pub(crate) fn reexecute_self_for_selinux_if_needed(
srcdata: &SourceInfo,
override_disable_selinux: bool,
) -> Result<SELinuxFinalState> {
if srcdata.selinux {
let host_selinux = crate::lsm::selinux_enabled()?;
let r = if override_disable_selinux {
println!("notice: Target has SELinux enabled, overriding to disable");
SELinuxFinalState::ForceTargetDisabled
} else if host_selinux {
setup_sys_mount("selinuxfs", SELINUXFS)?;
let g = crate::lsm::selinux_ensure_install_or_setenforce()?;
SELinuxFinalState::Enabled(g)
} else {
SELinuxFinalState::HostDisabled
};
Ok(r)
} else {
Ok(SELinuxFinalState::Disabled)
}
}
```
## Performance Optimizations
### 1. Async Operations
```rust
// From install.rs:1538-1543
let rootfs = tokio::task::spawn_blocking(move || {
baseline::install_create_rootfs(&state, block_opts)
})
.await??;
```
### 2. Parallel Processing
- Container image pulling
- Filesystem operations
- Bootloader installation
### 3. Resource Management
- Temporary directory cleanup
- File descriptor management
- Memory usage optimization
## Security Considerations
### 1. SELinux Integration
- Policy detection and loading
- Context preservation
- Labeling operations
### 2. Privilege Management
- Minimal privilege requirements
- Capability dropping
- Namespace isolation
### 3. Input Validation
- Command argument validation
- Path sanitization
- Resource limit enforcement
## Testing and Validation
### 1. Unit Tests
```rust
// From install.rs:2064-2153
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn install_opts_serializable() {
let c: InstallToDiskOpts = serde_json::from_value(serde_json::json!({
"device": "/dev/vda"
}))
.unwrap();
assert_eq!(c.block_opts.device, "/dev/vda");
}
}
```
### 2. Integration Tests
- End-to-end installation testing
- Error condition testing
- Performance testing
### 3. Validation Steps
- Container image integrity
- Filesystem compatibility
- Bootloader support
- Kernel compatibility
This analysis provides a comprehensive understanding of the bootc installation process from a source code perspective, covering the key components, execution flow, and implementation details.

View file

@ -0,0 +1,425 @@
# bootc Technical Installation Guide
## Overview
This document provides a comprehensive technical explanation of how bootc installs container images as bootable operating systems. bootc bridges the gap between OCI/Docker container images and bootable host systems by providing installation mechanisms that create traditional Linux boot environments from container images.
## Architecture Overview
bootc operates in two distinct modes:
1. **Container Mode**: When run inside a container (during build), behaves like any other container
2. **Host Mode**: When installed to a physical/virtual machine, becomes the bootable OS
The installation process transforms a container image into a bootable system with:
- Bootloader configuration
- Kernel and initramfs setup
- Root filesystem deployment
- OSTree repository initialization
## Installation Commands
### Primary Installation Commands
1. **`bootc install to-disk`** - Direct installation to a block device
2. **`bootc install to-filesystem`** - Installation to an existing mounted filesystem
3. **`bootc install to-existing-root`** - Convert existing Linux system to bootc
4. **`bootc install finalize`** - Post-installation finalization
### Command Structure
```bash
bootc install [COMMAND] [OPTIONS] [TARGET]
```
## Technical Installation Process
### Phase 1: Preparation and Validation
#### 1.1 Container Environment Detection
```rust
// From install.rs:519-538
pub(crate) fn from_container(
root: &Dir,
container_info: &ContainerExecutionInfo,
) -> Result<Self> {
if !container_info.engine.starts_with("podman") {
anyhow::bail!("Currently this command only supports being executed via podman");
}
// ... validation logic
}
```
**External Commands Required:**
- `podman` - Container runtime (required)
- `ostree` - OSTree repository management
- `bootupd` - Bootloader management
#### 1.2 Privilege and Namespace Validation
```rust
// From install.rs:1061-1082
fn require_host_pidns() -> Result<()> {
if rustix::process::getpid().is_init() {
anyhow::bail!("This command must be run with the podman --pid=host flag")
}
Ok(())
}
```
**Required Container Flags:**
- `--privileged` - Full host access
- `--pid=host` - Host process namespace
- `--security-opt label=type:unconfined_t` - SELinux bypass
#### 1.3 SELinux State Management
```rust
// From install.rs:1001-1029
pub(crate) fn reexecute_self_for_selinux_if_needed(
srcdata: &SourceInfo,
override_disable_selinux: bool,
) -> Result<SELinuxFinalState> {
// SELinux policy detection and re-execution logic
}
```
### Phase 2: Filesystem Setup
#### 2.1 OSTree Repository Initialization
```rust
// From install.rs:591-694
async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result<(Storage, bool)> {
let has_ostree = rootfs_dir.try_exists("ostree/repo")?;
if !has_ostree {
Task::new("Initializing ostree layout", "ostree")
.args(["admin", "init-fs", "--modern", "."])
.cwd(rootfs_dir)?
.run()?;
}
// ... repository configuration
}
```
**External Commands:**
- `ostree admin init-fs --modern` - Initialize OSTree filesystem
- `ostree config set` - Configure repository settings
#### 2.2 Container Image Deployment
```rust
// From install.rs:718-892
async fn install_container(
state: &State,
root_setup: &RootSetup,
sysroot: &ostree::Sysroot,
has_ostree: bool,
) -> Result<(ostree::Deployment, InstallAleph)> {
// Pull container image into OSTree repository
let pulled_image = match prepare_for_pull(repo, &spec_imgref, Some(&state.target_imgref)).await? {
PreparedPullResult::AlreadyPresent(existing) => existing,
PreparedPullResult::Ready(image_meta) => {
check_disk_space(root_setup.physical_root.as_fd(), &image_meta, &spec_imgref)?;
pull_from_prepared(&spec_imgref, false, ProgressWriter::default(), *image_meta).await?
}
};
// ... deployment logic
}
```
### Phase 3: Bootloader Installation
#### 3.1 Bootupd Integration
```rust
// From install.rs:1337-1343
crate::bootloader::install_via_bootupd(
&rootfs.device_info,
&rootfs.physical_root_path,
&state.config_opts,
&deployment_path.as_str(),
)?;
```
**External Commands:**
- `bootupctl install` - Install bootloader
- `bootupctl generate` - Generate bootloader configuration
#### 3.2 Architecture-Specific Bootloaders
- **x86_64/aarch64**: GRUB2 via bootupd
- **s390x**: zipl (IBM Z)
- **Other**: Platform-specific implementations
### Phase 4: Kernel and Initramfs Setup
#### 4.1 Kernel Argument Processing
```rust
// From install.rs:773-825
let kargsd = crate::bootc_kargs::get_kargs_from_ostree_root(
&sysroot.repo(),
merged_ostree_root.downcast_ref().unwrap(),
std::env::consts::ARCH,
)?;
```
**Kernel Arguments Sources (in order):**
1. Root filesystem kargs
2. Install configuration kargs
3. Container image kargs.d files
4. CLI-specified kargs
#### 4.2 Initramfs Integration
- Kernel location: `/usr/lib/modules/$kver/vmlinuz`
- Initramfs location: `/usr/lib/modules/$kver/initramfs.img`
- Generated by dracut during container build
### Phase 5: Filesystem Finalization
#### 5.1 Filesystem Optimization
```rust
// From install.rs:1033-1058
pub(crate) fn finalize_filesystem(
fsname: &str,
root: &Dir,
path: impl AsRef<Utf8Path>,
) -> Result<()> {
// fstrim - optimize filesystem
Task::new(format!("Trimming {fsname}"), "fstrim")
.args(["--quiet-unsupported", "-v", path.as_str()])
.cwd(root)?
.run()?;
// Remount read-only
Task::new(format!("Finalizing filesystem {fsname}"), "mount")
.cwd(root)?
.args(["-o", "remount,ro", path.as_str()])
.run()?;
// Freeze/thaw for journal flush
for a in ["-f", "-u"] {
Command::new("fsfreeze")
.cwd_dir(root.try_clone()?)
.args([a, path.as_str()])
.run_capture_stderr()?;
}
}
```
**External Commands:**
- `fstrim` - Trim filesystem for optimization
- `mount -o remount,ro` - Remount read-only
- `fsfreeze` - Freeze/thaw for journal flush
## Installation Modes
### 1. to-disk Installation
**Process Flow:**
1. Create filesystem on target device
2. Mount target device
3. Deploy container image to mounted filesystem
4. Install bootloader
5. Unmount and finalize
**External Commands:**
```bash
mkfs.$filesystem_type /dev/target
mount /dev/target /mnt
bootc install to-filesystem --karg=root=UUID=<uuid> /mnt
umount /mnt
```
### 2. to-filesystem Installation
**Process Flow:**
1. Validate target filesystem
2. Initialize OSTree repository
3. Deploy container image
4. Configure bootloader
5. Finalize filesystem
**Use Cases:**
- Integration with external installers (Anaconda)
- Custom partitioning schemes
- Cloud image generation
### 3. to-existing-root Installation
**Process Flow:**
1. Mount host root filesystem
2. Clean boot directories
3. Deploy alongside existing system
4. Configure bootloader
5. Set up cleanup service
**Special Considerations:**
- Preserves existing data in `/sysroot`
- Requires `--acknowledge-destructive` flag
- Sets up cleanup service for first boot
## External Dependencies
### Required System Commands
| Command | Purpose | Package |
|---------|---------|---------|
| `ostree` | OSTree repository management | ostree |
| `bootupd` | Bootloader management | bootupd |
| `podman` | Container runtime | podman |
| `fstrim` | Filesystem optimization | util-linux |
| `mount` | Filesystem mounting | util-linux |
| `umount` | Filesystem unmounting | util-linux |
| `fsfreeze` | Filesystem freeze/thaw | util-linux |
### Optional Commands
| Command | Purpose | Package |
|---------|---------|---------|
| `cryptsetup` | LUKS encryption | cryptsetup |
| `grub2-mkconfig` | GRUB configuration | grub2-tools |
| `dracut` | Initramfs generation | dracut |
## Configuration Files
### 1. Install Configuration
Location: `/usr/lib/bootc/install/*.toml`
```toml
[install.filesystem.root]
type = "xfs"
[install.filesystem.boot]
type = "ext4"
```
### 2. Kernel Arguments
Location: `/usr/lib/bootc/kargs.d/*.toml`
```toml
[kargs]
append = ["console=ttyS0", "quiet"]
prepend = ["rd.luks.uuid=12345678-1234-1234-1234-123456789abc"]
```
### 3. OSTree Configuration
Location: `ostree/repo/config`
```ini
[core]
repo_version=1
mode=bare
[sysroot]
bootloader=none
bootprefix=true
readonly=true
```
## Security Considerations
### 1. SELinux Integration
- Automatic policy detection
- Re-execution for proper labeling
- Target system SELinux configuration
### 2. Container Security
- Requires privileged container execution
- Host mount namespace access
- Device access for installation
### 3. Filesystem Security
- Atomic operations where possible
- Proper file permissions
- SELinux labeling
## Error Handling and Recovery
### 1. Disk Space Validation
```rust
// From install.rs:696-715
fn check_disk_space(
repo_fd: impl AsFd,
image_meta: &PreparedImportMeta,
imgref: &ImageReference,
) -> Result<()> {
let stat = rustix::fs::fstatvfs(repo_fd)?;
let bytes_avail: u64 = stat.f_bsize * stat.f_bavail;
if image_meta.bytes_to_fetch > bytes_avail {
anyhow::bail!(
"Insufficient free space for {image} (available: {bytes_avail} required: {bytes_to_fetch})",
// ... error details
);
}
}
```
### 2. Rollback Capability
- OSTree provides atomic rollback
- Bootloader configuration backup
- Deployment state tracking
### 3. Validation Steps
- Container image integrity
- Filesystem compatibility
- Bootloader support
- Kernel compatibility
## Performance Considerations
### 1. Parallel Operations
- Container image pulling
- Filesystem operations
- Bootloader installation
### 2. Disk I/O Optimization
- OSTree repository configuration
- Filesystem trimming
- Write optimization
### 3. Memory Usage
- Container image caching
- OSTree repository management
- Temporary file handling
## Debugging and Troubleshooting
### 1. Logging
- Structured logging with tracing
- Journal integration
- Progress reporting
### 2. Common Issues
- Insufficient disk space
- SELinux policy conflicts
- Bootloader installation failures
- Container image access issues
### 3. Debug Commands
```bash
# Check OSTree repository
ostree admin status
# Verify bootloader
bootupctl status
# Check container image
podman images
# Validate filesystem
lsblk -f
```
## Future Enhancements
### 1. Planned Features
- Dynamic ConfigMap injection
- Enhanced rollback mechanisms
- Multi-architecture support
- Cloud integration improvements
### 2. API Evolution
- Stable CLI interface
- REST API for management
- Configuration management
- Monitoring integration
---
This technical guide provides the foundation for understanding bootc's installation process. The system is designed to be robust, secure, and maintainable while providing the flexibility needed for various deployment scenarios.