# Create bootc base images without bootc โš ๏ธ **EXPERIMENTAL WARNING** โš ๏ธ **bootc on Debian is HIGHLY EXPERIMENTAL and NOT production-ready!** - **No reproducible bootc images exist yet** - Everything is experimental - **Use only for testing** on virtual machines or test hardware - **Expect failures** - bootc is not stable on Debian - **DO NOT use in production** - Data loss and system instability possible The bootc binary is unreliable under Debian as it's mainly developed for Fedora despite it aiming to be a distro agnostic tool. In this doc we'll go over all the little things a base bootc needs to be considered a true bootc image. ## Why Avoid bootc Binary on Debian ### Common Issues - **Missing Dependencies**: bootc may have Fedora-specific dependencies not available in Debian - **Compilation Issues**: Rust dependencies may not compile cleanly on Debian - **Runtime Errors**: Even if compiled, bootc may fail at runtime on Debian systems - **Feature Gaps**: Some bootc features may not work properly on Debian ### Alternative Validation Instead of relying on `bootc container lint`, we'll manually validate our images against the bootc specification. ## Essential Requirements for bootc Images ### 1. Required Labels Every bootc image must have these labels: ```dockerfile LABEL containers.bootc 1 LABEL ostree.bootable 1 ``` ### 2. Systemd as Init System bootc requires systemd as the init system: ```dockerfile # Install systemd RUN apt update && apt install -y systemd # Set systemd as init RUN ln -sf /lib/systemd/systemd /sbin/init # Set default target RUN systemctl set-default multi-user.target ``` ### 3. Essential Systemd Services Enable these core systemd services: ```dockerfile # Enable essential services RUN systemctl enable systemd-resolved.service RUN systemctl enable systemd-networkd.service RUN systemctl enable systemd-timesyncd.service RUN systemctl enable systemd-journald.service ``` ### 4. Proper Directory Structure Create essential systemd directories: ```dockerfile # Create systemd directories RUN mkdir -p /usr/lib/systemd/system \ /usr/lib/systemd/user \ /etc/systemd/system \ /etc/systemd/user \ /var/lib/systemd \ /run/systemd \ /etc/systemd/network ``` ### 5. Kernel and Initramfs Install kernel and initramfs tools: ```dockerfile # Install kernel and initramfs RUN apt install -y \ linux-image-amd64 \ initramfs-tools \ linux-base ``` ### 6. Bootloader Support Install bootloader tools: ```dockerfile # Install GRUB2 RUN apt install -y \ grub2 \ grub2-common \ grub-pc-bin \ grub-efi-amd64-bin \ efibootmgr ``` ### 7. OSTree Support Install OSTree for transactional updates: ```dockerfile # Install OSTree RUN apt install -y \ ostree \ libostree-1-1 ``` ## Manual Validation Checklist ### Filesystem Structure Validation ```bash #!/bin/bash # validate-filesystem.sh - Manual filesystem validation set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" echo "๐Ÿ” Validating filesystem structure for ${IMAGE_NAME}" # Use podman image mount for robust image inspection echo "๐Ÿ“ฆ Mounting image for inspection..." MOUNTPOINT=$(podman image mount "${IMAGE_NAME}") if [ -z "${MOUNTPOINT}" ]; then echo "โŒ Failed to mount image. Trying alternative method..." # Fallback: extract using podman save (less robust) TEMP_DIR=$(mktemp -d) podman save "${IMAGE_NAME}" | tar -xf - -C "${TEMP_DIR}" LAYER_DIR=$(find "${TEMP_DIR}" -name "layer.tar" | head -1 | xargs dirname) tar -xf "${LAYER_DIR}/layer.tar" -C "${TEMP_DIR}/extracted" ROOTFS="${TEMP_DIR}/extracted" CLEANUP_TEMP=1 else ROOTFS="${MOUNTPOINT}" CLEANUP_TEMP=0 fi echo "โœ… Checking systemd as init..." if [ -L "${ROOTFS}/sbin/init" ] && [ "$(readlink "${ROOTFS}/sbin/init")" = "/lib/systemd/systemd" ]; then echo "โœ… systemd is properly set as init" else echo "โŒ systemd is not set as init" exit 1 fi echo "โœ… Checking systemd directories..." for dir in /usr/lib/systemd/system /usr/lib/systemd/user /etc/systemd/system /etc/systemd/user; do if [ -d "${ROOTFS}${dir}" ]; then echo "โœ… ${dir} exists" else echo "โŒ ${dir} missing" exit 1 fi done echo "โœ… Checking essential binaries..." for binary in /lib/systemd/systemd /usr/bin/systemctl /sbin/init; do if [ -f "${ROOTFS}${binary}" ]; then echo "โœ… ${binary} exists" else echo "โŒ ${binary} missing" exit 1 fi done echo "โœ… Checking kernel..." if [ -d "${ROOTFS}/boot" ] && [ -f "${ROOTFS}/boot/vmlinuz-"* ]; then echo "โœ… Kernel found" else echo "โŒ Kernel missing" exit 1 fi echo "โœ… Checking initramfs..." if [ -f "${ROOTFS}/boot/initrd.img-"* ]; then echo "โœ… Initramfs found" else echo "โŒ Initramfs missing" exit 1 fi echo "โœ… Checking GRUB..." if [ -f "${ROOTFS}/usr/bin/grub-install" ] && [ -f "${ROOTFS}/usr/bin/grub-mkconfig" ]; then echo "โœ… GRUB2 found" else echo "โŒ GRUB2 missing" exit 1 fi echo "โœ… Checking OSTree..." if [ -f "${ROOTFS}/usr/bin/ostree" ]; then echo "โœ… OSTree found" else echo "โŒ OSTree missing" exit 1 fi # Clean up if [ "${CLEANUP_TEMP}" = "1" ]; then rm -rf "${TEMP_DIR}" else podman image umount "${IMAGE_NAME}" fi echo "๐ŸŽ‰ All filesystem validations passed!" ``` ### Label Validation ```bash #!/bin/bash # validate-labels.sh - Validate OCI labels set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" echo "๐Ÿ” Validating OCI labels for ${IMAGE_NAME}" # Check for required labels if podman inspect "${IMAGE_NAME}" | grep -q '"containers.bootc": "1"'; then echo "โœ… containers.bootc label found" else echo "โŒ containers.bootc label missing" exit 1 fi if podman inspect "${IMAGE_NAME}" | grep -q '"ostree.bootable": "1"'; then echo "โœ… ostree.bootable label found" else echo "โŒ ostree.bootable label missing" exit 1 fi echo "๐ŸŽ‰ All label validations passed!" ``` ### Systemd Service Validation ```bash #!/bin/bash # validate-systemd.sh - Validate systemd configuration set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" TEMP_DIR=$(mktemp -d) echo "๐Ÿ” Validating systemd configuration for ${IMAGE_NAME}" # Extract and run systemd validation podman run --rm -v "${TEMP_DIR}:/tmp" "${IMAGE_NAME}" /bin/bash -c " echo 'Checking systemd version...' systemctl --version echo 'Checking enabled services...' systemctl list-unit-files --state=enabled | grep -E '(systemd-resolved|systemd-networkd|systemd-timesyncd)' echo 'Checking systemd directories...' ls -la /usr/lib/systemd/system/ | head -5 ls -la /etc/systemd/system/ | head -5 echo 'Checking network configuration...' ls -la /etc/systemd/network/ echo 'Checking journal configuration...' ls -la /var/log/journal/ || echo 'No journal directory (normal for base image)' " rm -rf "${TEMP_DIR}" echo "๐ŸŽ‰ Systemd validation completed!" ``` ## Complete Build Script Without bootc ```bash #!/bin/bash # build-bootc-base-wo-bootc.sh - Build bootc base without bootc binary set -euo pipefail IMAGE_NAME="debian-bootc-base" TAG="${1:-latest}" echo "๐Ÿ—๏ธ Building Debian bootc Base Image (without bootc binary)" echo "Image: ${IMAGE_NAME}:${TAG}" # Build the image echo "๐Ÿ“ฆ Building container image..." podman build -f Containerfile.wo-bootc -t "${IMAGE_NAME}:${TAG}" . echo "โœ… Base image built successfully!" # Run validations echo "๐Ÿ” Running validations..." ./validate-labels.sh "${IMAGE_NAME}:${TAG}" ./validate-filesystem.sh "${IMAGE_NAME}:${TAG}" ./validate-systemd.sh "${IMAGE_NAME}:${TAG}" echo "๐Ÿ“Š Image Information:" podman images "${IMAGE_NAME}:${TAG}" echo "" echo "๐Ÿš€ Ready to build application layers!" echo "Example: podman build -f examples/nginx/Containerfile -t ${IMAGE_NAME}:nginx" ``` ## Containerfile Without bootc Dependency ```dockerfile # Containerfile.wo-bootc - Build bootc base without bootc binary FROM debian:sid-slim # Install essential packages for bootc RUN apt update && apt install -y \ systemd \ systemd-sysusers \ systemd-tmpfiles \ systemd-resolved \ systemd-networkd \ systemd-timesyncd \ kernel \ initramfs-tools \ linux-base \ grub2 \ grub2-common \ grub-pc-bin \ grub-efi-amd64-bin \ efibootmgr \ ostree \ libostree-1-1 \ && apt clean # Create essential directories RUN mkdir -p /usr/lib/systemd/system \ /usr/lib/systemd/user \ /etc/systemd/system \ /etc/systemd/user \ /var/lib/systemd \ /run/systemd \ /etc/systemd/network # Configure systemd as init RUN ln -sf /lib/systemd/systemd /sbin/init # Set up basic systemd configuration (using symlinks instead of systemctl) RUN ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target # Create essential systemd services (using symlinks instead of systemctl) RUN mkdir -p /etc/systemd/system/multi-user.target.wants \ && ln -sf /usr/lib/systemd/system/systemd-resolved.service /etc/systemd/system/multi-user.target.wants/systemd-resolved.service \ && ln -sf /usr/lib/systemd/system/systemd-networkd.service /etc/systemd/system/multi-user.target.wants/systemd-networkd.service \ && ln -sf /usr/lib/systemd/system/systemd-timesyncd.service /etc/systemd/system/multi-user.target.wants/systemd-timesyncd.service # Configure basic networking RUN echo -e "[Match]\nName=*\n\n[Network]\nDHCP=yes" > /etc/systemd/network/80-dhcp.network # Set up basic users and groups RUN systemd-sysusers --create # Configure tmpfiles RUN systemd-tmpfiles --create # Create essential systemd unit files RUN echo -e "[Unit]\nDescription=Bootc Base Image\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/bin/true\n\n[Install]\nWantedBy=multi-user.target" > /etc/systemd/system/bootc-base.service # Enable the bootc base service (using symlink instead of systemctl) RUN ln -sf /etc/systemd/system/bootc-base.service /etc/systemd/system/multi-user.target.wants/bootc-base.service # Required bootc labels LABEL containers.bootc 1 LABEL ostree.bootable 1 # Set default command CMD ["/lib/systemd/systemd"] ``` ## Advanced Validation Scripts ### Network Configuration Validation ```bash #!/bin/bash # validate-network.sh - Validate network configuration set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" echo "๐Ÿ” Validating network configuration for ${IMAGE_NAME}" podman run --rm "${IMAGE_NAME}" /bin/bash -c " echo 'Checking systemd-networkd configuration...' if [ -f /etc/systemd/network/80-dhcp.network ]; then echo 'โœ… DHCP network configuration found' cat /etc/systemd/network/80-dhcp.network else echo 'โŒ DHCP network configuration missing' exit 1 fi echo 'Checking systemd-resolved configuration...' if [ -f /etc/systemd/resolved.conf ]; then echo 'โœ… systemd-resolved configuration found' else echo 'โŒ systemd-resolved configuration missing' exit 1 fi " echo "๐ŸŽ‰ Network validation completed!" ``` ### Bootloader Validation ```bash #!/bin/bash # validate-bootloader.sh - Validate bootloader configuration set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" echo "๐Ÿ” Validating bootloader configuration for ${IMAGE_NAME}" podman run --rm "${IMAGE_NAME}" /bin/bash -c " echo 'Checking GRUB2 installation...' if command -v grub-install >/dev/null 2>&1; then echo 'โœ… grub-install found' grub-install --version else echo 'โŒ grub-install missing' exit 1 fi if command -v grub-mkconfig >/dev/null 2>&1; then echo 'โœ… grub-mkconfig found' grub-mkconfig --version else echo 'โŒ grub-mkconfig missing' exit 1 fi echo 'Checking EFI support...' if command -v efibootmgr >/dev/null 2>&1; then echo 'โœ… efibootmgr found' efibootmgr --version else echo 'โŒ efibootmgr missing' exit 1 fi " echo "๐ŸŽ‰ Bootloader validation completed!" ``` ## Complete Validation Suite ```bash #!/bin/bash # validate-all.sh - Complete validation suite set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" echo "๐Ÿ” Running complete validation suite for ${IMAGE_NAME}" echo "==================================================" # Run all validations ./validate-labels.sh "${IMAGE_NAME}" echo "" ./validate-filesystem.sh "${IMAGE_NAME}" echo "" ./validate-systemd.sh "${IMAGE_NAME}" echo "" ./validate-network.sh "${IMAGE_NAME}" echo "" ./validate-bootloader.sh "${IMAGE_NAME}" echo "" echo "๐ŸŽ‰ All validations passed! Image is bootc-compatible." echo "Image: ${IMAGE_NAME}" echo "Ready for deployment with bootc!" ``` ## Troubleshooting Common Issues ### Missing systemd Services ```bash # Check if services are properly enabled podman run --rm debian-bootc-base:latest systemctl list-unit-files --state=enabled ``` ### Kernel Issues ```bash # Check kernel installation podman run --rm debian-bootc-base:latest ls -la /boot/ ``` ### GRUB Issues ```bash # Check GRUB installation podman run --rm debian-bootc-base:latest which grub-install ``` ### OSTree Issues ```bash # Check OSTree installation podman run --rm debian-bootc-base:latest ostree --version ``` ## Installing bootc for Management Operations While bootc may be unreliable for installation on Debian, you can still install it for management operations like upgrades, rollbacks, and status checking. ### Installing bootc from Source ```bash #!/bin/bash # install-bootc-for-management.sh - Install bootc for management only set -euo pipefail echo "๐Ÿ—๏ธ Installing bootc for management operations on Debian" # Install build dependencies echo "๐Ÿ“ฆ Installing build dependencies..." sudo apt update && sudo apt install -y \ build-essential \ git \ pkg-config \ libostree-dev \ libglib2.0-dev \ libgpgme-dev \ libseccomp-dev \ cargo \ rustc # Install runtime dependencies echo "๐Ÿ“ฆ Installing runtime dependencies..." sudo apt install -y \ ostree \ podman \ systemd # Clone and build bootc echo "๐Ÿ”จ Building bootc from source..." if [ ! -d "bootc" ]; then git clone https://github.com/containers/bootc.git fi cd bootc git fetch origin git checkout origin/main # Build bootc echo "๐Ÿ”จ Compiling bootc..." make # Install bootc echo "๐Ÿ“ฆ Installing bootc..." sudo make install # Verify installation echo "โœ… Verifying installation..." bootc --version echo "๐ŸŽ‰ bootc installed for management operations!" echo "Note: Use manual installation for deploying images" ``` ### Installing bootc with Composefs Support ```bash #!/bin/bash # install-bootc-composefs.sh - Install bootc with composefs support set -euo pipefail echo "๐Ÿ—๏ธ Installing bootc with composefs support for management" # Install additional dependencies for composefs echo "๐Ÿ“ฆ Installing composefs dependencies..." sudo apt update && sudo apt install -y \ build-essential \ git \ pkg-config \ libostree-dev \ libglib2.0-dev \ libgpgme-dev \ libseccomp-dev \ cargo \ rustc \ libfuse3-dev \ libfuse3-3 # Clone and build bootc with composefs echo "๐Ÿ”จ Building bootc with composefs support..." if [ ! -d "bootc" ]; then git clone https://github.com/containers/bootc.git fi cd bootc git fetch origin git checkout origin/composefs-backend # Build with composefs feature echo "๐Ÿ”จ Compiling bootc with composefs..." cargo build --release --features composefs-backend # Install bootc echo "๐Ÿ“ฆ Installing bootc..." sudo cp target/release/bootc /usr/local/bin/ sudo chmod +x /usr/local/bin/bootc # Verify installation echo "โœ… Verifying installation..." bootc --version echo "๐ŸŽ‰ bootc with composefs support installed!" ``` ### Management Operations with bootc Once bootc is installed, you can use it for management operations: ```bash #!/bin/bash # bootc-management-examples.sh - Examples of bootc management operations set -euo pipefail echo "๐Ÿ”ง bootc Management Operations Examples" # Check system status echo "๐Ÿ“Š Checking system status..." bootc status # Check for upgrades echo "๐Ÿ”„ Checking for upgrades..." bootc upgrade --check # Apply upgrades (if available) echo "โฌ†๏ธ Applying upgrades..." bootc upgrade --apply # Switch to different image echo "๐Ÿ”„ Switching image..." # bootc switch quay.io/myorg/myapp:latest --apply # Rollback if needed echo "โช Rolling back..." # bootc rollback --apply # Check usr-overlay status echo "๐Ÿ“ Checking usr-overlay..." bootc usr-overlay echo "โœ… Management operations completed!" ``` ### Hybrid Approach: Manual Install + bootc Management ```bash #!/bin/bash # hybrid-bootc-workflow.sh - Manual install + bootc management set -euo pipefail IMAGE_NAME="${1:-debian-bootc-nginx:latest}" TARGET_ROOT="${2:-/mnt/sysroot}" echo "๐Ÿ”„ Hybrid bootc workflow: Manual install + bootc management" echo "Image: ${IMAGE_NAME}" echo "Target: ${TARGET_ROOT}" # Step 1: Manual installation (reliable) echo "๐Ÿ“ฆ Step 1: Manual installation..." ./install-bootc-manual.sh "${IMAGE_NAME}" "${TARGET_ROOT}" # Step 2: Install bootc for management echo "๐Ÿ”ง Step 2: Installing bootc for management..." ./install-bootc-for-management.sh # Step 3: Initialize bootc management echo "โš™๏ธ Step 3: Initializing bootc management..." sudo chroot "${TARGET_ROOT}" bootc status || echo "bootc status not available yet" # Step 4: Set up bootc configuration echo "๐Ÿ“ Step 4: Setting up bootc configuration..." sudo chroot "${TARGET_ROOT}" /bin/bash -c " # Create bootc configuration mkdir -p /etc/bootc echo 'image: ${IMAGE_NAME}' > /etc/bootc/config.yaml echo 'boot_order: [\"current\", \"rollback\"]' >> /etc/bootc/config.yaml " echo "โœ… Hybrid workflow completed!" echo "Manual installation: โœ…" echo "bootc management: โœ…" echo "Ready for upgrades and management!" ``` ### bootc Management Service ```bash #!/bin/bash # setup-bootc-management-service.sh - Set up bootc management service set -euo pipefail echo "๐Ÿ”ง Setting up bootc management service" # Create systemd service for bootc management sudo tee /etc/systemd/system/bootc-management.service > /dev/null << 'EOF' [Unit] Description=bootc Management Service Documentation=man:bootc(1) After=network.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/bin/bootc status ExecReload=/usr/local/bin/bootc upgrade --check StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF # Create bootc upgrade timer sudo tee /etc/systemd/system/bootc-upgrade.timer > /dev/null << 'EOF' [Unit] Description=Run bootc upgrade check daily Requires=bootc-management.service [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target EOF # Create bootc upgrade service sudo tee /etc/systemd/system/bootc-upgrade.service > /dev/null << 'EOF' [Unit] Description=bootc Upgrade Service Documentation=man:bootc(1) After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/bootc upgrade --check StandardOutput=journal StandardError=journal EOF # Enable services sudo systemctl daemon-reload sudo systemctl enable bootc-management.service sudo systemctl enable bootc-upgrade.timer echo "โœ… bootc management services configured!" echo "Status: systemctl status bootc-management" echo "Upgrades: systemctl status bootc-upgrade.timer" ``` ### Management Scripts ```bash #!/bin/bash # bootc-manage.sh - Comprehensive bootc management script set -euo pipefail ACTION="${1:-status}" IMAGE_NAME="${2:-}" case "${ACTION}" in "status") echo "๐Ÿ“Š bootc System Status" bootc status ;; "check-upgrades") echo "๐Ÿ”„ Checking for upgrades..." bootc upgrade --check ;; "upgrade") echo "โฌ†๏ธ Applying upgrades..." bootc upgrade --apply ;; "switch") if [ -z "${IMAGE_NAME}" ]; then echo "โŒ Error: Image name required for switch" echo "Usage: $0 switch " exit 1 fi echo "๐Ÿ”„ Switching to ${IMAGE_NAME}..." bootc switch "${IMAGE_NAME}" --apply ;; "rollback") echo "โช Rolling back..." bootc rollback --apply ;; "usr-overlay") echo "๐Ÿ“ Managing usr-overlay..." bootc usr-overlay ;; "help") echo "๐Ÿ”ง bootc Management Script" echo "Usage: $0 [image-name]" echo "" echo "Actions:" echo " status - Show system status" echo " check-upgrades - Check for available upgrades" echo " upgrade - Apply upgrades" echo " switch - Switch to different image" echo " rollback - Rollback to previous version" echo " usr-overlay - Manage usr-overlay" echo " help - Show this help" ;; *) echo "โŒ Unknown action: ${ACTION}" echo "Run '$0 help' for usage information" exit 1 ;; esac ``` ## Bypassing bootc for Installation Since bootc may be unreliable on Debian, you can manually install your bootc-compatible images to the filesystem without using the `bootc install` command. ### Manual Installation Process ```bash #!/bin/bash # install-bootc-manual.sh - Manually install bootc image without bootc binary set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" TARGET_ROOT="${2:-/mnt/sysroot}" # Safety check for destructive operations if [ "${TARGET_ROOT}" != "/mnt/sysroot" ] && [ -z "${BOOTC_CONFIRM_DISK_WIPE:-}" ]; then echo "๐Ÿšจ CRITICAL SAFETY WARNING ๐Ÿšจ" echo "This script will perform DESTRUCTIVE operations!" echo "Target: ${TARGET_ROOT}" echo "This may WIPE existing data and partitions!" echo "" echo "THIS IS EXPERIMENTAL SOFTWARE - Expect failures and data loss!" echo "" echo "MANDATORY: Set BOOTC_CONFIRM_DISK_WIPE=1 to proceed" echo "Example: BOOTC_CONFIRM_DISK_WIPE=1 $0 ${IMAGE_NAME} ${TARGET_ROOT}" echo "" echo "Sleeping 10 seconds before exit..." sleep 10 exit 1 fi echo "๐Ÿ—๏ธ Manually installing bootc image without bootc binary" echo "Image: ${IMAGE_NAME}" echo "Target: ${TARGET_ROOT}" # Create target directory sudo mkdir -p "${TARGET_ROOT}" # Extract image to temporary directory TEMP_DIR=$(mktemp -d) echo "๐Ÿ“ฆ Extracting image to ${TEMP_DIR}..." # Save and extract image podman save "${IMAGE_NAME}" | tar -xf - -C "${TEMP_DIR}" # Find the layer directory LAYER_DIR=$(find "${TEMP_DIR}" -name "layer.tar" | head -1 | xargs dirname) # Extract the layer to target echo "๐Ÿ“‚ Extracting filesystem to ${TARGET_ROOT}..." sudo tar -xf "${LAYER_DIR}/layer.tar" -C "${TARGET_ROOT}" # Set up essential directories echo "โš™๏ธ Setting up essential directories..." sudo mkdir -p "${TARGET_ROOT}/boot" sudo mkdir -p "${TARGET_ROOT}/sysroot" sudo mkdir -p "${TARGET_ROOT}/var/lib/ostree" # Set up bind mounts for chroot echo "๐Ÿ”— Setting up bind mounts..." sudo mount --bind /proc "${TARGET_ROOT}/proc" sudo mount --bind /sys "${TARGET_ROOT}/sys" sudo mount --bind /dev "${TARGET_ROOT}/dev" # Configure systemd in chroot echo "๐Ÿ”ง Configuring systemd..." sudo chroot "${TARGET_ROOT}" systemctl set-default multi-user.target # Generate initramfs echo "๐Ÿš€ Generating initramfs..." sudo chroot "${TARGET_ROOT}" update-initramfs -u # Install GRUB (if installing to disk) if [ "${TARGET_ROOT}" != "/mnt/sysroot" ]; then echo "๐Ÿ’พ Installing GRUB..." sudo chroot "${TARGET_ROOT}" grub-install /dev/sda sudo chroot "${TARGET_ROOT}" grub-mkconfig -o /boot/grub/grub.cfg fi # Clean up sudo umount "${TARGET_ROOT}/proc" || true sudo umount "${TARGET_ROOT}/sys" || true sudo umount "${TARGET_ROOT}/dev" || true rm -rf "${TEMP_DIR}" echo "โœ… Manual installation completed!" echo "Target: ${TARGET_ROOT}" ``` ### Alternative: Using systemd-nspawn ```bash #!/bin/bash # install-bootc-nspawn.sh - Install using systemd-nspawn set -euo pipefail IMAGE_NAME="${1:-debian-bootc-base:latest}" TARGET_ROOT="${2:-/mnt/sysroot}" echo "๐Ÿ—๏ธ Installing bootc image using systemd-nspawn" echo "Image: ${IMAGE_NAME}" echo "Target: ${TARGET_ROOT}" # Extract image first TEMP_DIR=$(mktemp -d) podman save "${IMAGE_NAME}" | tar -xf - -C "${TEMP_DIR}" LAYER_DIR=$(find "${TEMP_DIR}" -name "layer.tar" | head -1 | xargs dirname) sudo tar -xf "${LAYER_DIR}/layer.tar" -C "${TARGET_ROOT}" # Use systemd-nspawn for configuration echo "๐Ÿ”ง Configuring with systemd-nspawn..." sudo systemd-nspawn -D "${TARGET_ROOT}" /bin/bash -c " systemctl set-default multi-user.target update-initramfs -u systemctl enable systemd-resolved.service systemctl enable systemd-networkd.service " rm -rf "${TEMP_DIR}" echo "โœ… Installation completed with systemd-nspawn!" ``` ## Essential Initramfs Integration For proper composefs support and boot functionality, you need to include initramfs integration files in your base image. These files are essential for Debian bootc images: ### Required Files **1. `bootc-initramfs-setup.service`** - Systemd service for initramfs: ```ini # Copyright (C) 2013 Colin Walters # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. [Unit] DefaultDependencies=no ConditionKernelCommandLine=composefs ConditionPathExists=/etc/initrd-release After=sysroot.mount Requires=sysroot.mount Before=initrd-root-fs.target Before=initrd-switch-root.target OnFailure=emergency.target OnFailureJobMode=isolate [Service] Type=oneshot ExecStart=/usr/bin/bootc-initramfs-setup StandardInput=null StandardOutput=journal StandardError=journal+console RemainAfterExit=yes ``` **2. `module-setup.sh`** - Dracut module for initramfs: ```bash #!/usr/bin/bash check() { return 0 } depends() { return 0 } install() { inst \ "${moddir}/bootc-initramfs-setup" /bin/bootc-initramfs-setup inst \ "${moddir}/bootc-initramfs-setup.service" \ "${systemdsystemunitdir}/bootc-initramfs-setup.service" $SYSTEMCTL -q --root "${initdir}" add-wants \ 'initrd-root-fs.target' 'bootc-initramfs-setup.service' } ``` **3. `prepare-root.conf`** - Composefs configuration: ```ini [composefs] enabled = yes [sysroot] readonly = true ``` ### Integration in Containerfile Add these files to your base image: ```dockerfile # Copy initramfs integration files COPY files/37composefs/bootc-initramfs-setup.service /usr/lib/systemd/system/ COPY files/37composefs/module-setup.sh /usr/lib/dracut/modules.d/37composefs/ COPY files/ostree/prepare-root.conf /usr/lib/ostree-boot/prepare-root.conf # Enable the service RUN ln -sf /usr/lib/systemd/system/bootc-initramfs-setup.service \ /etc/systemd/system/multi-user.target.wants/bootc-initramfs-setup.service ``` ## Adding Application Layers (Example: nginx) ### Method 1: Building on Base Image ```dockerfile # examples/nginx/Containerfile FROM debian-bootc-base:latest # Install nginx RUN apt update && apt install -y nginx && apt clean # Configure nginx RUN echo 'server { \ listen 80; \ server_name _; \ location / { \ return 200 "Hello from bootc nginx!"; \ add_header Content-Type text/plain; \ } \ }' > /etc/nginx/sites-available/default RUN ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/ RUN rm -f /etc/nginx/sites-enabled/default.bak # Enable nginx service RUN systemctl enable nginx.service # Create nginx user and group RUN systemd-sysusers --create # Required bootc labels LABEL containers.bootc 1 LABEL ostree.bootable 1 # Set default command CMD ["/lib/systemd/systemd"] ``` ### Method 2: Multi-stage Build ```dockerfile # examples/nginx/Containerfile.multistage FROM debian:sid-slim as base # Install base packages RUN apt update && apt install -y \ systemd \ systemd-sysusers \ systemd-tmpfiles \ systemd-resolved \ systemd-networkd \ systemd-timesyncd \ kernel \ initramfs-tools \ grub2 \ grub2-common \ efibootmgr \ ostree \ nginx \ && apt clean # Configure systemd RUN ln -sf /lib/systemd/systemd /sbin/init RUN systemctl set-default multi-user.target RUN systemctl enable systemd-resolved.service \ systemd-networkd.service \ systemd-timesyncd.service \ nginx.service # Configure nginx RUN echo 'server { \ listen 80; \ server_name _; \ location / { \ return 200 "Hello from bootc nginx!"; \ add_header Content-Type text/plain; \ } \ }' > /etc/nginx/sites-available/default RUN ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/ RUN rm -f /etc/nginx/sites-enabled/default.bak # Create essential directories RUN mkdir -p /usr/lib/systemd/system \ /usr/lib/systemd/user \ /etc/systemd/system \ /etc/systemd/user \ /var/lib/systemd \ /run/systemd \ /etc/systemd/network # Configure networking RUN echo -e "[Match]\nName=*\n\n[Network]\nDHCP=yes" > /etc/systemd/network/80-dhcp.network # Set up users and groups RUN systemd-sysusers --create RUN systemd-tmpfiles --create # Required bootc labels LABEL containers.bootc 1 LABEL ostree.bootable 1 # Set default command CMD ["/lib/systemd/systemd"] ``` ### Build and Install Script ```bash #!/bin/bash # build-and-install-nginx.sh - Build nginx layer and install manually set -euo pipefail BASE_IMAGE="debian-bootc-base:latest" NGINX_IMAGE="debian-bootc-nginx:latest" TARGET_ROOT="${1:-/mnt/sysroot}" echo "๐Ÿ—๏ธ Building nginx layer on bootc base" echo "Base: ${BASE_IMAGE}" echo "Nginx: ${NGINX_IMAGE}" echo "Target: ${TARGET_ROOT}" # Build nginx image echo "๐Ÿ“ฆ Building nginx image..." podman build -f examples/nginx/Containerfile -t "${NGINX_IMAGE}" . # Validate the image echo "๐Ÿ” Validating nginx image..." ./validate-all.sh "${NGINX_IMAGE}" # Install manually echo "๐Ÿ’พ Installing nginx image..." ./install-bootc-manual.sh "${NGINX_IMAGE}" "${TARGET_ROOT}" echo "โœ… nginx bootc image built and installed!" echo "Image: ${NGINX_IMAGE}" echo "Target: ${TARGET_ROOT}" ``` ### Testing the nginx Layer ```bash #!/bin/bash # test-nginx-layer.sh - Test nginx layer set -euo pipefail NGINX_IMAGE="${1:-debian-bootc-nginx:latest}" echo "๐Ÿงช Testing nginx layer: ${NGINX_IMAGE}" # Test nginx configuration echo "๐Ÿ” Testing nginx configuration..." podman run --rm "${NGINX_IMAGE}" nginx -t # Test systemd services echo "๐Ÿ” Testing systemd services..." podman run --rm "${NGINX_IMAGE}" systemctl list-unit-files --state=enabled | grep nginx # Test nginx startup echo "๐Ÿ” Testing nginx startup..." podman run --rm "${NGINX_IMAGE}" systemctl is-enabled nginx.service # Test HTTP response (if possible) echo "๐Ÿ” Testing HTTP response..." podman run --rm -d --name nginx-test -p 8080:80 "${NGINX_IMAGE}" sleep 5 if curl -s http://localhost:8080 | grep -q "Hello from bootc nginx"; then echo "โœ… nginx HTTP response test passed" else echo "โŒ nginx HTTP response test failed" fi podman stop nginx-test podman rm nginx-test echo "๐ŸŽ‰ nginx layer testing completed!" ``` ### Complete Project Structure with nginx ``` debian-bootc-project/ โ”œโ”€โ”€ build-bootc-base-wo-bootc.sh # Build base image โ”œโ”€โ”€ build-and-install-nginx.sh # Build and install nginx โ”œโ”€โ”€ install-bootc-manual.sh # Manual installation โ”œโ”€โ”€ install-bootc-nspawn.sh # nspawn installation โ”œโ”€โ”€ validate-all.sh # Complete validation โ”œโ”€โ”€ test-nginx-layer.sh # Test nginx layer โ”œโ”€โ”€ Containerfile.wo-bootc # Base image containerfile โ”œโ”€โ”€ examples/ โ”‚ โ””โ”€โ”€ nginx/ โ”‚ โ”œโ”€โ”€ Containerfile # nginx layer โ”‚ โ””โ”€โ”€ Containerfile.multistage # Multi-stage nginx โ””โ”€โ”€ scripts/ โ”œโ”€โ”€ validate-filesystem.sh โ”œโ”€โ”€ validate-labels.sh โ”œโ”€โ”€ validate-systemd.sh โ”œโ”€โ”€ validate-network.sh โ””โ”€โ”€ validate-bootloader.sh ``` ### Usage Workflow ```bash # 1. Build base image ./build-bootc-base-wo-bootc.sh # 2. Build and install nginx layer ./build-and-install-nginx.sh /mnt/sysroot # 3. Test the installation ./test-nginx-layer.sh debian-bootc-nginx:latest # 4. Boot the system (if installed to disk) # Reboot and select the new boot entry ``` ## Summary This approach allows you to create fully bootc-compatible base images on Debian without relying on the potentially unreliable bootc binary. The manual validation scripts ensure your images meet all bootc requirements, making them ready for deployment and management with bootc once it's properly working on your system. The key is understanding what bootc expects and manually validating those requirements rather than depending on the bootc binary for validation. You can also manually install these images without using `bootc install`, and easily add application layers like nginx on top of your base images.