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
- Create Live System: Build a live CD/USB with your desired OS (e.g., using
live-buildfor Debian) - Install Calamares: Add Calamares installer to the live system
- Configure Calamares: Set up modules and configuration files
- Create ISO: Package the live system with Calamares into an installer ISO
- 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:
- Use OSBuild to create a live system with Calamares
- Configure Calamares with a custom bootc module
- Generate installer ISO that boots to Calamares GUI
- User installs bootc container via Calamares interface
Integration Architecture Options
Option 1: Single Container (Recommended)
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
Recommended Approach: Single Container
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
- Add Calamares dependencies to existing Containerfile
- Add ISO generation tools (live-build, etc.)
- Extend CLI to support installer image types
- Add Calamares configuration to existing config system
Phase 2: Custom Bootc Module
- Develop Calamares bootc module in Python
- Integrate with existing APT and container systems
- Test end-to-end ISO generation and installation
Phase 3: Production Ready
- Optimize container size (multi-stage builds, cleanup)
- Comprehensive testing across all image types
- 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
- Simplified Development: One codebase, one container, one deployment
- Consistent UX: Same CLI, config, and error handling for all image types
- Shared Infrastructure: Leverage existing APT, OSBuild, and config systems
- Easier Maintenance: Single container to update and maintain
- Better Testing: Can test all image types together
- User-Friendly: One tool to learn and use
Container Size Optimization
To address the "larger container" concern:
- Multi-stage builds: Separate build and runtime stages
- Dependency cleanup: Remove build tools in final stage
- Shared base images: Use common base for related containers
- 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
Option 1: Custom Bootc Module (Recommended)
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:
- Create bootc module: Python or C++ module for bootc installation
- Integrate with partitioning: Work with existing partition module
- Container download: Handle container registry access
- Installation process: Call
bootc installat 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
- Study Fedora Patterns: Analyze
ostreecontainerdirective and Ignition configs - Calamares Architecture: Understand module system and configuration
- Container Runtime: Ensure podman/containerd integration
- Registry Authentication: Implement Fedora-style auth patterns
Phase 2: Core Module Development
- Basic Bootc Module: Create simple Python module for bootc installation
- Registry Integration: Implement
/etc/ostree/auth.jsonand registry config - Systemd Service: Create bootc installation service (Ignition pattern)
- Configuration System: Integrate with existing debian-bootc-image-builder config
Phase 3: Advanced Features
- Hybrid Approach: Support kickstart, Ignition, and systemd patterns
- Partitioning Integration: Coordinate with Calamares partition module
- Bootloader Configuration: Configure GRUB for OSTree deployments
- Error Handling: Robust error handling and user feedback
Phase 4: Production Ready
- User Interface: Polish Calamares UI for bootc configuration
- Testing: Comprehensive testing across all patterns
- Documentation: User and developer documentation
- 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
- Unit Tests: Test individual module functions
- Integration Tests: Test with Calamares framework
- End-to-End Tests: Test complete installation process
- 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:
ostreecontainerdirective provides complete parameter set- Registry authentication via
/etc/ostree/auth.json - No
%packagessection - 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
- Create Custom Module: Develop bootc installation module
- Integrate with Existing: Work with partition and bootloader modules
- Configuration System: Extend existing config system
- 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
- Research Calamares Module Development: Study existing modules and architecture
- Create Bootc Module Prototype: Develop basic bootc installation module
- Test Calamares Integration: Verify module integration and functionality
- Design Configuration System: Plan integration with existing config system
- Evaluate Complexity: Assess development effort vs. benefits
- Compare with Debian-Installer: Make final decision on approach