deb-bootc-image-builder-new/docs/calmares-installer.md
2025-09-05 07:10:12 -07:00

37 KiB

Calamares Installer Integration

Overview

This document explores integrating Calamares installer support into the debian-bootc-image-builder project. Calamares is a modern, distribution-independent installer framework that offers a graphical interface and modular architecture, making it potentially more suitable for bootc integration than the traditional debian-installer.

How Calamares Works: Building Installer ISOs

Basic Concept

Calamares is not a tool that builds ISOs directly. Instead, it's an installer framework that runs on a live system (like a live CD/USB) to install the operating system to a target disk.

Typical Workflow

  1. Create Live System: Build a live CD/USB with your desired OS (e.g., using live-build for Debian)
  2. Install Calamares: Add Calamares installer to the live system
  3. Configure Calamares: Set up modules and configuration files
  4. Create ISO: Package the live system with Calamares into an installer ISO
  5. User Experience: Boot ISO → Calamares GUI runs → User installs OS to disk

Example: Debian Live with Calamares

# 1. Create Debian live system
lb config --distribution trixie --architectures amd64
lb build

# 2. Add Calamares to the live system
# (This happens during the live-build process)

# 3. Configure Calamares modules
# Edit calamares.conf and module configs

# 4. Result: installer.iso that boots to Calamares GUI

Key Points

  • Calamares runs on live system: It's the installer that runs when you boot the ISO
  • Not an ISO builder: You use other tools (like live-build) to create the ISO
  • Modular installer: Each installation step is handled by a separate module
  • Configuration-driven: Behavior controlled by YAML config files

Integration with bootc-image-builder

For our project, we would:

  1. Use OSBuild to create a live system with Calamares
  2. Configure Calamares with a custom bootc module
  3. Generate installer ISO that boots to Calamares GUI
  4. User installs bootc container via Calamares interface

Integration Architecture Options

Approach: Extend the existing debian-bootc-image-builder container to support ISO generation

Architecture:

debian-bootc-image-builder container
├── OSBuild (disk images: qcow2, ami, vmdk, raw)
├── Calamares (installer ISOs: debian-installer, calamares)
├── APT integration
├── Configuration system
└── CLI interface

Implementation:

# Single container handles both disk images and installer ISOs
debian-bootc-image-builder build --type qcow2 container:latest
debian-bootc-image-builder build --type calamares container:latest

Advantages:

  • Unified interface: Single tool for all image types
  • Shared configuration: Same config system for all outputs
  • Simplified deployment: One container to manage
  • Consistent UX: Same CLI and error handling
  • Shared dependencies: OSBuild, APT, container tools

Challenges:

  • Container size: Larger container with more dependencies
  • Complexity: More features in single container
  • Build time: Longer build times with more components

Option 2: Separate ISO Container

Approach: Create dedicated container for installer ISO generation

Architecture:

debian-bootc-image-builder container
├── OSBuild (disk images only)
├── APT integration
└── CLI interface

debian-installer-builder container
├── Calamares
├── live-build
├── ISO generation tools
└── Custom bootc module

Implementation:

# Two separate containers
debian-bootc-image-builder build --type qcow2 container:latest
debian-installer-builder build --type calamares container:latest

Advantages:

  • Focused containers: Each container has specific purpose
  • Smaller containers: Reduced size and complexity
  • Independent development: Can develop features separately
  • Specialized tools: Optimized for each use case

Challenges:

  • Two tools to maintain: Separate codebases and containers
  • Configuration duplication: Need to sync config systems
  • User confusion: Two different tools to learn
  • Deployment complexity: Two containers to manage

Option 3: Hybrid Approach

Approach: Core container + optional ISO generation extension

Architecture:

debian-bootc-image-builder (core)
├── OSBuild (disk images)
├── APT integration
└── CLI interface

debian-bootc-image-builder:iso (extension)
├── Inherits from core
├── Calamares
├── live-build
└── ISO generation tools

Implementation:

# Core container for disk images
debian-bootc-image-builder build --type qcow2 container:latest

# Extended container for installer ISOs
debian-bootc-image-builder:iso build --type calamares container:latest

Advantages:

  • Flexible deployment: Use core only or with ISO support
  • Shared base: Common functionality in base container
  • Optional complexity: ISO features only when needed
  • Incremental development: Add ISO support later

Challenges:

  • Container management: Multiple related containers
  • Version synchronization: Keep base and extension in sync
  • Documentation complexity: Need to document both variants

Why Single Container is Best

1. Unified User Experience

# Single tool for all image types
debian-bootc-image-builder build --type qcow2 container:latest
debian-bootc-image-builder build --type ami container:latest
debian-bootc-image-builder build --type calamares container:latest
debian-bootc-image-builder build --type debian-installer container:latest

2. Shared Configuration System

# .config/registry.yaml - works for all image types
registries:
  development:
    base_url: "git.raines.xyz"
    namespace: "debian"

# Same config for disk images and installer ISOs
containers:
  bootc_base: "{registry}/{namespace}/debian-bootc:{version}"

3. Consistent CLI and Error Handling

  • Same validation system for all image types
  • Same progress reporting and diagnostics
  • Same error messages and troubleshooting

4. Shared Dependencies

  • OSBuild (used by both disk images and live systems)
  • APT integration (package resolution for both)
  • Container tools (podman, etc.)
  • Configuration system

Implementation Strategy

Phase 1: Extend Existing Container

  1. Add Calamares dependencies to existing Containerfile
  2. Add ISO generation tools (live-build, etc.)
  3. Extend CLI to support installer image types
  4. Add Calamares configuration to existing config system

Phase 2: Custom Bootc Module

  1. Develop Calamares bootc module in Python
  2. Integrate with existing APT and container systems
  3. Test end-to-end ISO generation and installation

Phase 3: Production Ready

  1. Optimize container size (multi-stage builds, cleanup)
  2. Comprehensive testing across all image types
  3. Documentation for all features

Container Structure

# Containerfile
FROM debian:trixie-slim

# Base dependencies (existing)
RUN apt-get update && apt-get install -y \
    podman \
    qemu-utils \
    apt \
    systemd \
    # ... existing packages

# ISO generation dependencies (new)
RUN apt-get install -y \
    calamares \
    live-build \
    debootstrap \
    # ... ISO-specific packages

# Copy application
COPY . /app
WORKDIR /app

# Single entrypoint handles all image types
ENTRYPOINT ["/app/bin/debian-bootc-image-builder"]

CLI Extension

# Extended CLI supports all image types
debian-bootc-image-builder build --type qcow2 container:latest
debian-bootc-image-builder build --type ami container:latest
debian-bootc-image-builder build --type calamares container:latest
debian-bootc-image-builder build --type debian-installer container:latest

# Same validation, progress reporting, and error handling
debian-bootc-image-builder build --verbose --diagnose --type calamares container:latest

Benefits of Single Container Approach

  1. Simplified Development: One codebase, one container, one deployment
  2. Consistent UX: Same CLI, config, and error handling for all image types
  3. Shared Infrastructure: Leverage existing APT, OSBuild, and config systems
  4. Easier Maintenance: Single container to update and maintain
  5. Better Testing: Can test all image types together
  6. User-Friendly: One tool to learn and use

Container Size Optimization

To address the "larger container" concern:

  1. Multi-stage builds: Separate build and runtime stages
  2. Dependency cleanup: Remove build tools in final stage
  3. Shared base images: Use common base for related containers
  4. Optional features: Make ISO generation optional via build flags

This approach gives you the best of both worlds: unified user experience with the flexibility to optimize container size as needed.

Calamares Architecture

Core Design Principles

Calamares is designed as a distribution-independent installer framework with the following key characteristics:

  • Modular Architecture: Composed of multiple modules handling different installation aspects
  • Graphical Interface: Modern Qt-based GUI for user-friendly installation
  • Highly Customizable: Extensive branding, theming, and configuration options
  • Distribution-Agnostic: Works across various Linux distributions
  • Advanced Partitioning: Both manual and automated partitioning capabilities

Module System

Calamares uses a modular architecture where each installation step is handled by a separate module:

Core Modules

  • Partitioning: Disk partitioning and filesystem creation
  • Users: User account creation and configuration
  • Bootloader: GRUB installation and configuration
  • Network: Network configuration during installation
  • Packages: Package installation and management
  • Services: System service configuration

Custom Modules

  • Python Modules: Easy to develop and customize
  • C++ Modules: For performance-critical operations
  • Configuration-Driven: Modules can be enabled/disabled via configuration

Configuration System

Calamares uses YAML-based configuration files:

# calamares.conf
modules-search: [ local ]

instances:
- id:       partition
  module:   partition
  config:   partition.conf

- id:       users
  module:   users
  config:   users.conf

Integration Approaches

Approach: Create a custom Calamares module for bootc installation

Advantages:

  • Native Integration: Built into Calamares workflow
  • User Experience: Graphical interface for bootc installation
  • Modular Design: Fits Calamares architecture perfectly
  • Configuration: Can be configured via YAML

Implementation:

  1. Create bootc module: Python or C++ module for bootc installation
  2. Integrate with partitioning: Work with existing partition module
  3. Container download: Handle container registry access
  4. Installation process: Call bootc install at appropriate time

Option 2: Package Installation Module

Approach: Use existing package installation module with custom packages

Advantages:

  • Leverage existing: Use proven package installation
  • Simpler implementation: Less custom code needed

Challenges:

  • Limited flexibility: Harder to customize bootc installation
  • Package dependencies: Must create bootc packages

Option 3: Post-Installation Script

Approach: Use Calamares to install base system, then run bootc installation

Advantages:

  • Simple integration: Minimal Calamares modification
  • Proven approach: Similar to existing workflows

Challenges:

  • Two-stage process: More complex user experience
  • Error handling: Harder to handle bootc installation failures

Technical Implementation

Custom Bootc Module Development

Based on analysis of Fedora's kickstart and Ignition approaches, here's how to create a comprehensive bootc-install module for Calamares:

Module Structure

# bootc.py - Custom Calamares module
import libcalamares
import subprocess
import json
import os
import tempfile
from pathlib import Path

def run():
    """Main module execution"""
    # Get configuration from Calamares
    config = libcalamares.globalstorage.value("bootcConfig")
    container_url = config.get("containerUrl")
    registry_auth = config.get("registryAuth", {})
    install_options = config.get("installOptions", {})
    
    # Set up registry authentication
    setup_registry_auth(registry_auth)
    
    # Download and install container
    install_bootc_container(container_url, install_options)
    
    return None

def setup_registry_auth(auth_config):
    """Set up registry authentication based on Fedora patterns"""
    if not auth_config:
        return
    
    # Create /etc/ostree/auth.json (from Fedora kickstart approach)
    auth_dir = Path("/etc/ostree")
    auth_dir.mkdir(parents=True, exist_ok=True)
    
    auth_data = {
        "auths": auth_config.get("registries", {})
    }
    
    with open(auth_dir / "auth.json", "w") as f:
        json.dump(auth_data, f, indent=2)
    
    # Create registry configuration (from Fedora approach)
    registry_dir = Path("/etc/containers/registries.conf.d")
    registry_dir.mkdir(parents=True, exist_ok=True)
    
    registry_config = ""
    for registry, config in auth_config.get("registries", {}).items():
        if config.get("insecure", False):
            registry_config += f"[[registry]]\nlocation=\"{registry}\"\ninsecure=true\n\n"
    
    if registry_config:
        with open(registry_dir / "bootc.conf", "w") as f:
            f.write(registry_config)

def install_bootc_container(container_url, install_options):
    """Install bootc container using systemd service approach"""
    # Create systemd service for bootc installation (from Ignition approach)
    service_content = f"""[Unit]
Description=Install bootc container
[Service]
Type=oneshot
ExecStart=/usr/bin/bootc install to-disk {install_options.get('target_disk', '/dev/sda')}
Environment=CONTAINER_URL={container_url}
[Install]
WantedBy=multi-user.target
"""
    
    # Write service file
    service_dir = Path("/etc/systemd/system")
    with open(service_dir / "bootc-install.service", "w") as f:
        f.write(service_content)
    
    # Enable and start service
    subprocess.run(["systemctl", "enable", "bootc-install.service"], check=True)
    subprocess.run(["systemctl", "start", "bootc-install.service"], check=True)

Configuration Integration

# bootc.conf - Based on Fedora kickstart ostreecontainer parameters
containerUrl: "quay.io/exampleos/foo:latest"
stateroot: "default"
remote: "default"
transport: "registry"
noSignatureVerification: false

# Registry authentication (from Fedora kickstart %pre sections)
registryAuth:
  registries:
    "quay.io":
      auth: "base64-encoded-credentials"
    "registry.example.com:5000":
      insecure: true

# Installation options (from Fedora approaches)
installOptions:
  target_disk: "/dev/sda"
  target_arch: "amd64"
  rootfs_type: "ext4"
  bootloader: "grub"

Advanced Module Implementation

# bootc_advanced.py - Comprehensive bootc module
import libcalamares
import subprocess
import json
import os
import tempfile
import shutil
from pathlib import Path

class BootcInstaller:
    def __init__(self, config):
        self.config = config
        self.container_url = config.get("containerUrl")
        self.stateroot = config.get("stateroot", "default")
        self.remote = config.get("remote", self.stateroot)
        self.transport = config.get("transport", "registry")
        self.no_sig_verify = config.get("noSignatureVerification", False)
        
    def run(self):
        """Main installation process"""
        try:
            # 1. Set up registry authentication
            self.setup_registry_auth()
            
            # 2. Configure container runtime
            self.configure_container_runtime()
            
            # 3. Install bootc container
            self.install_container()
            
            # 4. Configure bootloader for OSTree
            self.configure_bootloader()
            
            # 5. Set up system services
            self.setup_system_services()
            
        except Exception as e:
            libcalamares.utils.debug(f"Bootc installation failed: {e}")
            return ("Bootc installation failed", str(e))
        
        return None
    
    def setup_registry_auth(self):
        """Set up registry authentication using Fedora patterns"""
        auth_config = self.config.get("registryAuth", {})
        if not auth_config:
            return
        
        # Create /etc/ostree/auth.json (from Fedora kickstart)
        auth_dir = Path("/etc/ostree")
        auth_dir.mkdir(parents=True, exist_ok=True)
        
        auth_data = {
            "auths": auth_config.get("registries", {})
        }
        
        with open(auth_dir / "auth.json", "w") as f:
            json.dump(auth_data, f, indent=2)
        
        # Create registry configuration (from Fedora approach)
        self.create_registry_config(auth_config)
    
    def create_registry_config(self, auth_config):
        """Create registry configuration files"""
        registry_dir = Path("/etc/containers/registries.conf.d")
        registry_dir.mkdir(parents=True, exist_ok=True)
        
        registry_config = ""
        for registry, config in auth_config.get("registries", {}).items():
            if config.get("insecure", False):
                registry_config += f"[[registry]]\nlocation=\"{registry}\"\ninsecure=true\n\n"
        
        if registry_config:
            with open(registry_dir / "bootc.conf", "w") as f:
                f.write(registry_config)
    
    def configure_container_runtime(self):
        """Ensure container runtime is available and configured"""
        # Check if podman is available
        try:
            subprocess.run(["podman", "--version"], check=True, capture_output=True)
        except (subprocess.CalledProcessError, FileNotFoundError):
            raise RuntimeError("Podman is required but not available")
        
        # Configure container runtime for bootc
        self.setup_bootc_environment()
    
    def setup_bootc_environment(self):
        """Set up bootc environment variables and configuration"""
        # Set environment variables for bootc
        os.environ["CONTAINER_URL"] = self.container_url
        os.environ["OSTREE_STATEROOT"] = self.stateroot
        os.environ["OSTREE_REMOTE"] = self.remote
    
    def install_container(self):
        """Install bootc container using systemd service approach"""
        # Create systemd service for bootc installation (from Ignition approach)
        service_content = self.generate_bootc_service()
        
        # Write service file
        service_dir = Path("/etc/systemd/system")
        with open(service_dir / "bootc-install.service", "w") as f:
            f.write(service_content)
        
        # Enable and start service
        subprocess.run(["systemctl", "daemon-reload"], check=True)
        subprocess.run(["systemctl", "enable", "bootc-install.service"], check=True)
        subprocess.run(["systemctl", "start", "bootc-install.service"], check=True)
    
    def generate_bootc_service(self):
        """Generate systemd service for bootc installation"""
        target_disk = self.config.get("installOptions", {}).get("target_disk", "/dev/sda")
        
        service_content = f"""[Unit]
Description=Install bootc container
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/bootc install to-disk {target_disk}
Environment=CONTAINER_URL={self.container_url}
Environment=OSTREE_STATEROOT={self.stateroot}
Environment=OSTREE_REMOTE={self.remote}
Environment=OSTREE_TRANSPORT={self.transport}
"""
        
        if self.no_sig_verify:
            service_content += "Environment=OSTREE_NO_SIGNATURE_VERIFICATION=1\n"
        
        service_content += """
[Install]
WantedBy=multi-user.target
"""
        
        return service_content
    
    def configure_bootloader(self):
        """Configure bootloader for OSTree-based bootc system"""
        # This would integrate with Calamares bootloader module
        # to ensure GRUB is configured for OSTree deployments
        
        bootloader_config = {
            "ostree_enabled": True,
            "stateroot": self.stateroot,
            "remote": self.remote
        }
        
        # Store configuration for bootloader module
        libcalamares.globalstorage.insert("bootcBootloaderConfig", bootloader_config)
    
    def setup_system_services(self):
        """Set up system services for bootc"""
        # Enable bootc-related services
        services = [
            "bootc-update.service",
            "bootc-update.path"
        ]
        
        for service in services:
            try:
                subprocess.run(["systemctl", "enable", service], check=True)
            except subprocess.CalledProcessError:
                # Service might not exist yet, that's okay
                pass

def run():
    """Main module execution"""
    config = libcalamares.globalstorage.value("bootcConfig")
    installer = BootcInstaller(config)
    return installer.run()

Calamares Integration Configuration

# calamares.conf - Main configuration
modules-search: [ local ]

instances:
- id:       partition
  module:   partition
  config:   partition.conf

- id:       bootc
  module:   bootc
  config:   bootc.conf

- id:       bootloader
  module:   bootloader
  config:   bootloader.conf

Bootc Module Configuration

# bootc.conf - Comprehensive configuration
# Based on Fedora ostreecontainer directive parameters
containerUrl: "{{ registry }}/{{ namespace }}/{{ image }}:{{ tag }}"
stateroot: "default"
remote: "default"
transport: "registry"
noSignatureVerification: false

# Registry authentication (from Fedora kickstart %pre sections)
registryAuth:
  registries:
    "quay.io":
      auth: "{{ base64_encoded_credentials }}"
    "registry.example.com:5000":
      insecure: true

# Installation options
installOptions:
  target_disk: "/dev/sda"
  target_arch: "amd64"
  rootfs_type: "ext4"
  bootloader: "grub"

# Integration with other modules
integration:
  partition_module: "partition"
  bootloader_module: "bootloader"
  network_module: "network"

Integration with Existing Modules

  • Partitioning: Coordinate with partition module for disk layout
  • Bootloader: Ensure GRUB is configured for OSTree
  • Users: Handle user creation in bootc environment

Hybrid Approach: Kickstart + Ignition Patterns

Based on the analysis of both Fedora approaches, we can create a hybrid Calamares module that combines the best of both:

Kickstart Pattern Integration

def generate_kickstart_config(self):
    """Generate kickstart configuration for bootc installation"""
    # Based on Fedora ostreecontainer directive
    kickstart_content = f"""# Bootc installation kickstart
text
network --bootproto=dhcp --device=link --activate

# Basic partitioning
clearpart --all --initlabel --disklabel=gpt
reqpart --add-boot
part / --grow --fstype xfs

# Container installation - NO %packages section!
ostreecontainer --url="{self.container_url}" \\
                --stateroot="{self.stateroot}" \\
                --remote="{self.remote}" \\
                --transport="{self.transport}"
"""
    
    if self.no_sig_verify:
        kickstart_content += "                --no-signature-verification\n"
    
    kickstart_content += """
# System configuration
firewall --disabled
services --enabled=sshd
rootpw --iscrypted locked
reboot
"""
    
    return kickstart_content

Ignition Pattern Integration

def generate_ignition_config(self):
    """Generate Ignition configuration for bootc installation"""
    # Based on Fedora CoreOS Ignition approach
    ignition_config = {
        "ignition": {
            "version": "3.4.0"
        },
        "storage": {
            "disks": self.get_disk_config(),
            "filesystems": self.get_filesystem_config(),
            "files": self.get_auth_files()
        },
        "systemd": {
            "units": [
                {
                    "name": "bootc-install.service",
                    "enabled": True,
                    "contents": self.generate_bootc_service()
                }
            ]
        },
        "networkd": {
            "units": self.get_network_config()
        }
    }
    
    return ignition_config

def get_auth_files(self):
    """Generate authentication files (from Fedora patterns)"""
    files = []
    
    # Registry authentication
    if self.config.get("registryAuth"):
        auth_data = {
            "auths": self.config["registryAuth"].get("registries", {})
        }
        
        files.append({
            "path": "/etc/ostree/auth.json",
            "mode": 420,
            "contents": {
                "source": f"data:text/plain;base64,{base64.b64encode(json.dumps(auth_data).encode()).decode()}"
            }
        })
    
    return files

Combined Implementation Strategy

class HybridBootcInstaller:
    def __init__(self, config):
        self.config = config
        self.approach = config.get("installationApproach", "systemd")  # "kickstart", "ignition", "systemd"
        
    def run(self):
        """Main installation process using hybrid approach"""
        if self.approach == "kickstart":
            return self.install_via_kickstart()
        elif self.approach == "ignition":
            return self.install_via_ignition()
        else:  # systemd (default)
            return self.install_via_systemd()
    
    def install_via_kickstart(self):
        """Install using kickstart approach (Fedora COSMIC Atomic pattern)"""
        # Generate kickstart file
        kickstart_content = self.generate_kickstart_config()
        
        # Write kickstart file
        kickstart_path = "/tmp/bootc.ks"
        with open(kickstart_path, "w") as f:
            f.write(kickstart_content)
        
        # Execute kickstart installation
        subprocess.run(["anaconda", "--kickstart", kickstart_path], check=True)
    
    def install_via_ignition(self):
        """Install using Ignition approach (Fedora CoreOS pattern)"""
        # Generate Ignition config
        ignition_config = self.generate_ignition_config()
        
        # Write Ignition file
        ignition_path = "/tmp/bootc.ign"
        with open(ignition_path, "w") as f:
            json.dump(ignition_config, f, indent=2)
        
        # Execute Ignition installation
        subprocess.run(["ignition", "apply", ignition_path], check=True)
    
    def install_via_systemd(self):
        """Install using systemd service approach (recommended)"""
        # This is the approach we implemented above
        return self.install_container()

Configuration for Hybrid Approach

# bootc.conf - Hybrid configuration
# Choose installation approach
installationApproach: "systemd"  # "kickstart", "ignition", "systemd"

# Container configuration (from Fedora ostreecontainer)
containerUrl: "quay.io/exampleos/foo:latest"
stateroot: "default"
remote: "default"
transport: "registry"
noSignatureVerification: false

# Registry authentication (from both Fedora approaches)
registryAuth:
  registries:
    "quay.io":
      auth: "base64-encoded-credentials"
    "registry.example.com:5000":
      insecure: true

# Installation options
installOptions:
  target_disk: "/dev/sda"
  target_arch: "amd64"
  rootfs_type: "ext4"
  bootloader: "grub"

# Approach-specific options
kickstartOptions:
  network_config: "dhcp"
  partitioning: "autopart"
  services: ["sshd"]

ignitionOptions:
  version: "3.4.0"
  network_units: ["00-eth0.network"]
  additional_units: []
  • Network: Manage network access for container download

Calamares Configuration

Main Configuration

# calamares.conf
modules-search: [ local ]

instances:
- id:       partition
  module:   partition
  config:   partition.conf

- id:       bootc
  module:   bootc
  config:   bootc.conf

- id:       bootloader
  module:   bootloader
  config:   bootloader.conf

Bootc-Specific Configuration

# bootc.conf
containerUrl: "{{ registry }}/{{ namespace }}/{{ image }}:{{ tag }}"
downloadPath: "/tmp/bootc-container"
installOptions:
  targetArch: "amd64"
  rootfsType: "ext4"
  bootloader: "grub"

Advantages Over Debian-Installer

1. Modern Architecture

  • Graphical Interface: User-friendly installation experience
  • Modular Design: Easy to extend and customize
  • Configuration-Driven: Flexible configuration system

2. Better Integration Potential

  • Custom Modules: Can create bootc-specific installation module
  • Python Support: Easier to develop custom functionality
  • Active Development: Modern, actively maintained project

3. User Experience

  • Intuitive Interface: Modern GUI vs. text-based installer
  • Progress Feedback: Clear installation progress indication
  • Error Handling: Better error reporting and recovery

4. Technical Benefits

  • Distribution-Agnostic: Not tied to specific Debian internals
  • Extensible: Easy to add new features and modules
  • Well-Documented: Comprehensive documentation and examples

Technical Challenges

1. Module Development Complexity

Challenge: Creating a custom bootc module requires significant development

  • Learning Curve: Understanding Calamares module architecture
  • Integration Points: Coordinating with existing modules
  • Error Handling: Robust error handling and recovery

Mitigation:

  • Start Simple: Begin with basic module and iterate
  • Leverage Examples: Use existing modules as templates
  • Community Support: Calamares has active community

2. Container Download and Storage

Challenge: Managing container downloads during installation

  • Network Access: Ensuring network connectivity
  • Storage Space: Temporary storage for container images
  • Authentication: Registry authentication handling

Solutions:

  • Pre-download: Download container before installation starts
  • Streaming: Stream container directly to installation target
  • Caching: Cache containers for offline installations

3. Bootloader Configuration

Challenge: Configuring GRUB for OSTree-based bootc systems

  • OSTree Integration: GRUB must understand OSTree deployments
  • Kernel Parameters: Special parameters for bootc systems
  • UEFI/BIOS Support: Different bootloader requirements

Approach:

  • Custom Bootloader Module: Extend existing bootloader module
  • OSTree Support: Add OSTree-specific GRUB configuration
  • Testing: Comprehensive testing across different hardware

4. Package Management Integration

Challenge: Integrating with existing package management

  • Dependency Resolution: Ensuring bootc dependencies are met
  • Package Installation: Installing bootc and related packages
  • Repository Management: Managing package repositories

Solution:

  • Hybrid Approach: Use Calamares for base system, bootc for container
  • Package Module: Leverage existing package installation module
  • Custom Packages: Create bootc-specific packages if needed

Implementation Strategy

Based on the analysis of Fedora's kickstart and Ignition approaches, here's a comprehensive implementation roadmap:

Phase 1: Foundation and Research

  1. Study Fedora Patterns: Analyze ostreecontainer directive and Ignition configs
  2. Calamares Architecture: Understand module system and configuration
  3. Container Runtime: Ensure podman/containerd integration
  4. Registry Authentication: Implement Fedora-style auth patterns

Phase 2: Core Module Development

  1. Basic Bootc Module: Create simple Python module for bootc installation
  2. Registry Integration: Implement /etc/ostree/auth.json and registry config
  3. Systemd Service: Create bootc installation service (Ignition pattern)
  4. Configuration System: Integrate with existing debian-bootc-image-builder config

Phase 3: Advanced Features

  1. Hybrid Approach: Support kickstart, Ignition, and systemd patterns
  2. Partitioning Integration: Coordinate with Calamares partition module
  3. Bootloader Configuration: Configure GRUB for OSTree deployments
  4. Error Handling: Robust error handling and user feedback

Phase 4: Production Ready

  1. User Interface: Polish Calamares UI for bootc configuration
  2. Testing: Comprehensive testing across all patterns
  3. Documentation: User and developer documentation
  4. Integration: Full integration with debian-bootc-image-builder

Implementation Details

Module Development Steps

# 1. Basic module structure
class BootcModule:
    def __init__(self):
        self.config = None
        self.container_url = None
        self.registry_auth = None
    
    def run(self):
        # Main installation logic
        pass

# 2. Registry authentication (from Fedora kickstart)
def setup_registry_auth(self):
    # Create /etc/ostree/auth.json
    # Create /etc/containers/registries.conf.d/bootc.conf
    pass

# 3. Container installation (from Fedora Ignition)
def install_container(self):
    # Create systemd service
    # Execute bootc install
    pass

# 4. Integration with Calamares
def integrate_with_calamares(self):
    # Coordinate with partition module
    # Configure bootloader module
    # Handle user creation
    pass

Testing Strategy

  1. Unit Tests: Test individual module functions
  2. Integration Tests: Test with Calamares framework
  3. End-to-End Tests: Test complete installation process
  4. Pattern Tests: Test kickstart, Ignition, and systemd approaches

Configuration Integration

# Integration with existing debian-bootc-image-builder config
# .config/registry.yaml
calamares:
  enabled: true
  installation_approach: "systemd"  # "kickstart", "ignition", "systemd"
  container_config:
    stateroot: "default"
    remote: "default"
    transport: "registry"
  registry_auth:
    # Same as existing registry config

Key Implementation Insights

From Fedora Kickstart Analysis:

  • ostreecontainer directive provides complete parameter set
  • Registry authentication via /etc/ostree/auth.json
  • No %packages section - container-first approach
  • Dracut hooks for kickstart processing

From Fedora Ignition Analysis:

  • Systemd services for container installation
  • JSON-based configuration - easier to generate
  • Modular approach - can combine different config sources
  • Immutable design - configuration applied once

Hybrid Benefits:

  • Flexibility: Support multiple installation patterns
  • Compatibility: Work with existing Fedora tooling
  • Modern approach: Leverage best of both worlds
  • Future-proof: Easy to extend and modify

Comparison: Calamares vs Debian-Installer

Aspect Calamares Debian-Installer
Interface Graphical (Qt) Text-based
Architecture Modular Monolithic
Customization High (modules) Low (preseed)
Development Python/C++ C/Shell scripts
Documentation Comprehensive Limited
Community Active Established
Bootc Integration Custom module Preseed hooks
User Experience Modern Traditional
Complexity Medium High

Recommendation

Use Calamares with Custom Bootc Module:

Advantages

  • Modern Architecture: Modular, extensible design
  • Better UX: Graphical interface and better error handling
  • Easier Development: Python modules and good documentation
  • Active Community: Ongoing development and support
  • Distribution-Agnostic: Not tied to Debian internals

Implementation Approach

  1. Create Custom Module: Develop bootc installation module
  2. Integrate with Existing: Work with partition and bootloader modules
  3. Configuration System: Extend existing config system
  4. User Experience: Provide modern, intuitive installation

Risk Mitigation

  • Start Simple: Begin with basic functionality
  • Leverage Community: Use existing modules and documentation
  • Iterative Development: Build and test incrementally
  • Fallback Option: Keep debian-installer as backup

Next Steps

  1. Research Calamares Module Development: Study existing modules and architecture
  2. Create Bootc Module Prototype: Develop basic bootc installation module
  3. Test Calamares Integration: Verify module integration and functionality
  4. Design Configuration System: Plan integration with existing config system
  5. Evaluate Complexity: Assess development effort vs. benefits
  6. Compare with Debian-Installer: Make final decision on approach