bootc-docs/switch/bootc-switch-technical-guide.md
robojerk 526f1c1afd 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
2025-09-15 14:02:28 -07:00

16 KiB

bootc switch - Technical Guide

Overview

bootc switch is a command for changing the container image reference that a bootc-managed system will boot from. It operates similarly to bootc upgrade but changes the image source rather than updating the current image. This enables blue/green deployments, A/B testing, and controlled rollouts across different image versions.

Purpose

The switch command serves several critical functions:

  1. Image Source Management: Change the container image reference for future boots
  2. Blue/Green Deployments: Switch between different image versions
  3. A/B Testing: Test different image versions on different systems
  4. Controlled Rollouts: Gradually migrate systems to new image versions
  5. Rollback Capability: Switch back to previous image versions

Command Syntax

bootc switch [OPTIONS...] <TARGET>

Basic Usage

# Switch to different image version
bootc switch quay.io/myorg/debian-bootc:v2.0

# Switch and apply immediately
bootc switch --apply quay.io/myorg/debian-bootc:v2.0

# Switch with soft reboot
bootc switch --apply --soft-reboot=auto quay.io/myorg/debian-bootc:v2.0

# Switch with specific transport
bootc switch --transport=oci-archive quay.io/myorg/debian-bootc:v2.0

Command Options

Core Options

Option Description Default Required
TARGET Target image to use for next boot None Yes
--apply Restart/reboot into new target image false No
--quiet Don't display progress false No
--soft-reboot Configure soft reboot behavior None No

Transport Options

Option Description Default Values
--transport Container transport type registry registry, oci, oci-archive, containers-storage

Security Options

Option Description Default
--enforce-container-sigpolicy Enforce container signature policy false

Advanced Options

Option Description Default
--retain Retain reference to currently booted image false

Architecture Overview

1. Switch Command Structure

pub(crate) struct SwitchOpts {
    pub(crate) quiet: bool,                           // Suppress progress output
    pub(crate) apply: bool,                           // Apply and reboot
    pub(crate) soft_reboot: Option<SoftRebootMode>,  // Soft reboot behavior
    pub(crate) transport: String,                     // Container transport
    pub(crate) enforce_container_sigpolicy: bool,    // Signature enforcement
    pub(crate) retain: bool,                          // Retain current image ref
    pub(crate) mutate_in_place: bool,                // In-place mutation (hidden)
    pub(crate) progress: ProgressOptions,            // Progress reporting
}

2. Switch Process Flow

async fn switch(opts: SwitchOpts) -> Result<()> {
    // 1. Parse and validate target image
    let transport = ostree_container::Transport::try_from(opts.transport.as_str())?;
    let imgref = ostree_container::ImageReference {
        transport,
        name: opts.target.to_string(),
    };
    let sigverify = sigpolicy_from_opt(opts.enforce_container_sigpolicy);
    let target = ostree_container::OstreeImageReference { sigverify, imgref };
    let target = ImageReference::from(target);
    
    // 2. Handle in-place mutation (hidden option)
    if opts.mutate_in_place {
        let deployid = switch_origin_inplace(&root, &target).await?;
        println!("Updated {deployid} to pull from {target}");
        return Ok(());
    }
    
    // 3. Get system status
    let sysroot = &get_storage().await?;
    let ostree = sysroot.get_ostree()?;
    let repo = &ostree.repo();
    let (booted_deployment, _deployments, host) = 
        crate::status::get_status_require_booted(ostree)?;
    
    // 4. Create new specification
    let new_spec = {
        let mut new_spec = host.spec.clone();
        new_spec.image = Some(target.clone());
        new_spec
    };
    
    // 5. Check for changes
    if new_spec == host.spec {
        println!("Image specification is unchanged.");
        return Ok(());
    }
    
    // 6. Log switch operation
    tracing::info!(
        message_id = SWITCH_JOURNAL_ID,
        bootc.old_image_reference = old_image,
        bootc.new_image_reference = &target.image,
        "Switching from image {} to {}",
        old_image, target.image
    );
    
    // 7. Pull and stage new image
    let fetched = crate::deploy::pull(repo, &target, None, opts.quiet, prog.clone()).await?;
    
    // 8. Handle image retention
    if !opts.retain {
        // Prune previous ostree ref
        if let Some(booted_origin) = booted_deployment.origin() {
            if let Some(ostree_ref) = booted_origin.optional_string("origin", "refspec")? {
                let (remote, ostree_ref) = ostree::parse_refspec(&ostree_ref)?;
                repo.set_ref_immediate(remote.as_deref(), &ostree_ref, None, cancellable)?;
            }
        }
    }
    
    // 9. Stage new deployment
    let stateroot = booted_deployment.osname();
    crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, prog.clone()).await?;
    
    // 10. Update system status
    sysroot.update_mtime()?;
    
    // 11. Handle soft reboot
    if opts.soft_reboot.is_some() {
        let updated_host = crate::status::get_status(ostree, Some(&booted_deployment))?.1;
        handle_staged_soft_reboot(ostree, opts.soft_reboot, &updated_host)?;
    }
    
    // 12. Apply changes if requested
    if opts.apply {
        crate::reboot::reboot()?;
    }
    
    Ok(())
}

Image Reference Handling

1. Transport Types

The switch command supports multiple container transport types:

Registry Transport (default)

bootc switch quay.io/myorg/debian-bootc:v2.0

OCI Archive Transport

bootc switch --transport=oci-archive /path/to/image.tar

OCI Transport

bootc switch --transport=oci oci:quay.io/myorg/debian-bootc:v2.0

Containers Storage Transport

bootc switch --transport=containers-storage containers-storage:quay.io/myorg/debian-bootc:v2.0

2. Image Reference Parsing

let transport = ostree_container::Transport::try_from(opts.transport.as_str())?;
let imgref = ostree_container::ImageReference {
    transport,
    name: opts.target.to_string(),
};
let sigverify = sigpolicy_from_opt(opts.enforce_container_sigpolicy);
let target = ostree_container::OstreeImageReference { sigverify, imgref };

Process:

  1. Transport Parsing: Convert string to transport enum
  2. Image Reference: Create container image reference
  3. Signature Verification: Configure signature policy
  4. OSTree Reference: Convert to OSTree image reference

In-Place Mutation

1. In-Place Switch Implementation

pub(crate) fn switch_origin_inplace(root: &Dir, imgref: &ImageReference) -> Result<String> {
    const SWITCH_INPLACE_JOURNAL_ID: &str = "3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7";
    
    tracing::info!(
        message_id = SWITCH_INPLACE_JOURNAL_ID,
        bootc.image.reference = &imgref.image,
        bootc.image.transport = &imgref.transport,
        bootc.switch_type = "in_place",
        "Performing in-place switch to image: {}",
        imgref
    );
    
    // Find deployment directory
    let deploy_dir = find_deployment_directory(root)?;
    
    // Update origin file
    let origin_path = deploy_dir.join("origin");
    let mut origin = std::fs::read_to_string(&origin_path)?;
    
    // Update image reference in origin
    update_origin_image_reference(&mut origin, imgref)?;
    
    // Write updated origin
    std::fs::write(&origin_path, origin)?;
    
    // Extract deployment ID
    let deploy_id = extract_deployment_id(&deploy_dir)?;
    
    Ok(deploy_id)
}

Purpose: Directly modify the booted deployment's origin file Use Cases:

  • Anaconda %post scripts
  • System installation scenarios
  • Emergency image switching

State Management

1. Specification Updates

let new_spec = {
    let mut new_spec = host.spec.clone();
    new_spec.image = Some(target.clone());
    new_spec
};

Process:

  1. Clone Current Spec: Copy existing host specification
  2. Update Image Reference: Set new target image
  3. Preserve Other Settings: Keep boot order and other settings

2. Change Detection

if new_spec == host.spec {
    println!("Image specification is unchanged.");
    return Ok(());
}

Purpose: Avoid unnecessary operations when no changes are made Benefits: Performance optimization, clear user feedback

3. Image Retention

if !opts.retain {
    // Prune previous ostree ref
    if let Some(booted_origin) = booted_deployment.origin() {
        if let Some(ostree_ref) = booted_origin.optional_string("origin", "refspec")? {
            let (remote, ostree_ref) = ostree::parse_refspec(&ostree_ref)?;
            repo.set_ref_immediate(remote.as_deref(), &ostree_ref, None, cancellable)?;
        }
    }
}

Purpose: Manage OSTree references for disk space optimization Behavior:

  • Default: Remove previous image reference
  • With --retain: Keep previous image reference

Logging and Monitoring

1. Switch Operation Logging

const SWITCH_JOURNAL_ID: &str = "7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1";

tracing::info!(
    message_id = SWITCH_JOURNAL_ID,
    bootc.old_image_reference = old_image,
    bootc.new_image_reference = &target.image,
    bootc.new_image_transport = &target.transport,
    "Switching from image {} to {}",
    old_image, target.image
);

Purpose: Track image switching operations Fields:

  • message_id: Unique identifier for switch operations
  • bootc.old_image_reference: Previous image reference
  • bootc.new_image_reference: New image reference
  • bootc.new_image_transport: Transport type used

2. In-Place Switch Logging

const SWITCH_INPLACE_JOURNAL_ID: &str = "3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7";

tracing::info!(
    message_id = SWITCH_INPLACE_JOURNAL_ID,
    bootc.image.reference = &imgref.image,
    bootc.image.transport = &imgref.transport,
    bootc.switch_type = "in_place",
    "Performing in-place switch to image: {}",
    imgref
);

Purpose: Track in-place switch operations Fields:

  • message_id: Unique identifier for in-place switches
  • bootc.image.reference: Target image reference
  • bootc.image.transport: Transport type used
  • bootc.switch_type: Operation type identifier

Usage Patterns

1. Blue/Green Deployments

# Deploy to green environment
bootc switch quay.io/myorg/debian-bootc:green

# Switch back to blue if needed
bootc switch quay.io/myorg/debian-bootc:blue

2. A/B Testing

# Switch subset of systems to version B
bootc switch quay.io/myorg/debian-bootc:v2.0-beta

# Monitor and switch back if issues
bootc switch quay.io/myorg/debian-bootc:v1.0-stable

3. Controlled Rollouts

# Switch to new version
bootc switch quay.io/myorg/debian-bootc:v2.0

# Apply immediately
bootc switch --apply quay.io/myorg/debian-bootc:v2.0

# Apply with soft reboot
bootc switch --apply --soft-reboot=auto quay.io/myorg/debian-bootc:v2.0

4. Emergency Rollbacks

# Quick rollback to previous version
bootc switch quay.io/myorg/debian-bootc:v1.0 --apply

# Rollback with retention
bootc switch --retain quay.io/myorg/debian-bootc:v1.0

Integration with Other Commands

1. Relationship to bootc upgrade

Similarities:

  • Both pull and stage container images
  • Both support --apply and --soft-reboot options
  • Both use the same deployment staging process

Differences:

  • upgrade: Updates current image to newer version
  • switch: Changes image source to different image

2. Relationship to bootc rollback

Complementary:

  • switch: Change to different image version
  • rollback: Revert to previous deployment

Usage:

# Switch to new version
bootc switch quay.io/myorg/debian-bootc:v2.0

# If issues, rollback
bootc rollback

3. Relationship to bootc status

Status Display:

# Check current status
bootc status

# Switch to new image
bootc switch quay.io/myorg/debian-bootc:v2.0

# Check updated status
bootc status

Error Handling

1. Image Validation Errors

// Invalid transport
Error: Invalid transport type 'invalid'

// Image not found
Error: Image not found in registry

// Signature verification failed
Error: Signature verification failed

2. System State Errors

// System not bootc compatible
Error: System is not bootc compatible

// No changes detected
Image specification is unchanged.

// Deployment not found
Error: No deployment directory found

3. Network and Registry Errors

// Registry connectivity
Error: Failed to connect to registry

// Authentication failed
Error: Authentication failed

// Image pull failed
Error: Failed to pull image

Security Considerations

1. Signature Verification

# Enforce signature policy
bootc switch --enforce-container-sigpolicy quay.io/myorg/debian-bootc:v2.0

Purpose: Ensure image authenticity and integrity Requirements: Valid signature policy in /etc/containers/policy.json

2. Transport Security

Registry Transport: Uses HTTPS and authentication OCI Archive: Local file system access Containers Storage: Local container storage

3. Image Validation

  • Schema Validation: Validates image configuration
  • Compatibility Check: Ensures image is bootc-compatible
  • Signature Verification: Validates image signatures

Performance Considerations

1. Image Pulling

  • Layer Caching: Reuses existing layers when possible
  • Incremental Updates: Only downloads changed layers
  • Parallel Downloads: Downloads layers in parallel

2. Staging Process

  • Atomic Staging: All-or-nothing staging process
  • Rollback Capability: Maintains previous deployment
  • Status Updates: Efficient status management

3. Disk Space Management

  • Reference Pruning: Removes old image references by default
  • Retention Option: Keep references with --retain
  • Cleanup: Automatic cleanup of unused layers

Troubleshooting

1. Common Issues

Image Not Found

# Check image exists
podman pull quay.io/myorg/debian-bootc:v2.0

# Check registry connectivity
curl -I https://quay.io/v2/

Signature Verification Failed

# Check signature policy
cat /etc/containers/policy.json

# Verify image signatures
podman inspect quay.io/myorg/debian-bootc:v2.0

System Not Compatible

# Check system status
bootc status

# Check bootc compatibility
bootc status --json | jq '.status.booted'

2. Debug Commands

# Enable debug logging
RUST_LOG=debug bootc switch quay.io/myorg/debian-bootc:v2.0

# Check system logs
journalctl -u bootc-fetch-apply-updates.service

# Verify image
podman inspect quay.io/myorg/debian-bootc:v2.0

Best Practices

1. Image Management

  • Use Semantic Versioning: Clear version numbering
  • Test Before Switch: Validate images in staging
  • Monitor After Switch: Watch for issues post-switch
  • Keep Rollback Ready: Maintain previous versions

2. Deployment Strategy

  • Blue/Green: Use different image tags
  • Canary Deployments: Gradual rollout
  • A/B Testing: Compare different versions
  • Emergency Procedures: Quick rollback capability

3. Monitoring and Logging

  • Track Switch Operations: Monitor journal logs
  • Set Up Alerts: Notify on switch failures
  • Monitor System Health: Watch for issues
  • Document Changes: Keep change records

Future Enhancements

1. Planned Features

  • Userspace Restart: For kernel-unchanged switches
  • Rollback Automation: Automatic rollback on failure
  • Switch Scheduling: Time-based switching
  • Health Checks: Pre/post switch validation

2. Integration Improvements

  • API Support: REST API for switching
  • Web Interface: Web-based image management
  • Configuration Management: Declarative switching
  • Audit Logging: Comprehensive audit trails

This technical guide provides comprehensive understanding of the bootc switch system's architecture, implementation, and usage patterns.