Files
zosbuilder/IMPLEMENTATION_PLAN.md
Jan De Landtsheer 860b9aa161 feat: Implement complete Zero OS Alpine Initramfs Builder
- Complete bash framework with strict error handling
- Modular library system (docker, alpine, components, initramfs, kernel, testing)
- Rust component integration (zinit, rfs, mycelium) with musl targeting
- Rootless Docker/Podman support for GitHub Actions
- Centralized configuration in config/build.conf
- 2-stage module loading system
- Strip + UPX optimization for minimal size
- Complete zinit integration replacing OpenRC
- GitHub Actions CI/CD pipeline
- Comprehensive documentation and usage guides

Components:
- Latest stable kernel 6.12.44
- Alpine Linux 3.22 base
- ThreeFold components: zinit, mycelium, rfs, corex
- Target: ~8-12MB final initramfs.cpio.xz
2025-08-31 12:31:49 +02:00

17 KiB

Zero OS Alpine Initramfs Builder - Complete Implementation Plan

Current Analysis

Based on the existing project structure and your requirements, I've analyzed:

  • Existing configs: Excellent foundation with Alpine init, kernel config, minimal packages, and zinit services
  • New requirements: Rust builds (zinit, rfs, mycelium) with musl, strip+UPX optimization, rootless containers
  • sources.conf: Already defines ThreeFold components with proper build functions

Directory Structure to Create

project-root/
├── config/
│   ├── zinit/
│   │   ├── services/          # zinit service definitions
│   │   └── zinit.conf         # main zinit configuration
│   ├── packages.list          # apk packages to install in initramfs
│   ├── sources.conf           # components to download/build (EXISTING)
│   ├── kernel.config          # kernel config with initramfs path
│   └── modules.conf           # 2-stage module loading specification
├── scripts/
│   ├── lib/
│   │   ├── docker.sh          # container lifecycle, rootless setup
│   │   ├── alpine.sh          # miniroot extraction, apk operations
│   │   ├── components.sh      # download/build from sources.conf
│   │   ├── initramfs.sh       # assembly, aggressive cleanup, compression
│   │   ├── kernel.sh          # kernel build with embedded initramfs
│   │   └── testing.sh         # qemu/cloud-hypervisor test commands
│   ├── build.sh               # main orchestrator script
│   └── clean.sh               # cleanup all generated artifacts
├── initramfs/                 # final initramfs tree (generated)
├── components/                # component build staging (generated)
├── kernel/                    # kernel source tree (generated)
└── dist/                      # final build artifacts (generated)

Implementation Framework

1. Bash Scripting Standards

All scripts must follow these patterns:

#!/bin/bash
set -euo pipefail

# Source common functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib/common.sh"

# Command execution pattern
function safe_execute() {
    local cmd="$*"
    log_info "Executing: ${cmd}"
    if ! ${cmd}; then
        log_error "Command failed: ${cmd}"
        exit 1
    fi
}

# Section separation
function section_header() {
    echo "=================================================="
    echo "SECTION: $1"
    echo "=================================================="
}

2. Container Support (scripts/lib/docker.sh)

#!/bin/bash
# Container management for rootless builds

function docker_build_container() {
    local dockerfile_path="$1"
    local tag="$2"
    
    section_header "Building Container"
    safe_execute docker build -t "${tag}" "${dockerfile_path}"
}

function docker_start_rootless() {
    local image="$1"
    local workdir="$2"
    local volumes="$3"
    
    section_header "Starting Rootless Container"
    local user_args="--user $(id -u):$(id -g)"
    local volume_args=""
    
    for vol in ${volumes}; do
        volume_args="${volume_args} -v ${vol}"
    done
    
    safe_execute docker run ${user_args} ${volume_args} -w "${workdir}" "${image}"
}

function docker_commit_builder() {
    local container_id="$1"
    local new_tag="$2"
    
    section_header "Committing Builder Container"
    safe_execute docker commit "${container_id}" "${new_tag}"
}

3. Alpine Operations (scripts/lib/alpine.sh)

#!/bin/bash
# Alpine miniroot and package operations

function alpine_extract_miniroot() {
    local version="3.22"
    local arch="x86_64"
    local target_dir="$1"
    
    section_header "Extracting Alpine Miniroot"
    local url="https://dl-cdn.alpinelinux.org/alpine/v${version}/releases/${arch}/alpine-minirootfs-${version}.0-${arch}.tar.gz"
    
    safe_execute mkdir -p "${target_dir}"
    safe_execute wget -O "/tmp/alpine-miniroot.tar.gz" "${url}"
    safe_execute tar -xzf "/tmp/alpine-miniroot.tar.gz" -C "${target_dir}"
    safe_execute rm "/tmp/alpine-miniroot.tar.gz"
}

function alpine_install_packages() {
    local initramfs_dir="$1"
    local packages_file="$2"
    
    section_header "Installing Alpine Packages"
    
    # Setup chroot environment
    safe_execute mount --bind /proc "${initramfs_dir}/proc"
    safe_execute mount --bind /sys "${initramfs_dir}/sys"
    safe_execute mount --bind /dev "${initramfs_dir}/dev"
    
    # Install packages (NO OpenRC)
    local packages=$(grep -v '^#' "${packages_file}" | grep -v '^$' | tr '\n' ' ')
    safe_execute chroot "${initramfs_dir}" apk add --no-cache ${packages}
    
    # Cleanup
    safe_execute umount "${initramfs_dir}/proc" || true
    safe_execute umount "${initramfs_dir}/sys" || true
    safe_execute umount "${initramfs_dir}/dev" || true
}

function alpine_aggressive_cleanup() {
    local initramfs_dir="$1"
    
    section_header "Aggressive Alpine Cleanup"
    
    # Remove documentation
    safe_execute rm -rf "${initramfs_dir}/usr/share/doc"
    safe_execute rm -rf "${initramfs_dir}/usr/share/man"
    safe_execute rm -rf "${initramfs_dir}/usr/share/info"
    
    # Remove locales except C
    safe_execute find "${initramfs_dir}/usr/share/locale" -mindepth 1 -maxdepth 1 -type d ! -name 'C' -exec rm -rf {} + 2>/dev/null || true
    
    # Remove headers and development files
    safe_execute rm -rf "${initramfs_dir}/usr/include"
    safe_execute rm -rf "${initramfs_dir}/usr/lib/pkgconfig"
    
    # Remove APK cache
    safe_execute rm -rf "${initramfs_dir}/var/cache/apk"
    safe_execute rm -rf "${initramfs_dir}/lib/apk"
}

4. Component Building (scripts/lib/components.sh)

#!/bin/bash
# Component download and build system

function components_parse_sources_conf() {
    local sources_file="$1"
    local components_dir="$2"
    
    section_header "Parsing Sources Configuration"
    
    while IFS=: read -r type name url version build_func extra; do
        [[ $type =~ ^#.*$ ]] && continue  # Skip comments
        [[ -z "$type" ]] && continue      # Skip empty lines
        
        log_info "Component: ${name} (${type})"
        
        case "$type" in
            "git")
                components_download_git "$name" "$url" "$version" "$components_dir"
                ;;
            "release")
                components_download_release "$name" "$url" "$version" "$components_dir" "$extra"
                ;;
            *)
                log_error "Unknown component type: $type"
                exit 1
                ;;
        esac
        
        # Build component
        components_build_component "$name" "$build_func" "$components_dir"
        
    done < <(grep -v '^#' "$sources_file" | grep -v '^$')
}

function components_download_git() {
    local name="$1"
    local url="$2"
    local version="$3"
    local components_dir="$4"
    
    local target_dir="${components_dir}/${name}"
    
    section_header "Downloading Git Component: ${name}"
    
    if [[ -d "$target_dir" ]]; then
        log_info "Component ${name} already exists, updating..."
        safe_execute cd "$target_dir"
        safe_execute git fetch
        safe_execute git checkout "$version"
        safe_execute git pull origin "$version" || true
    else
        log_info "Cloning ${name} from ${url}"
        safe_execute git clone "$url" "$target_dir"
        safe_execute cd "$target_dir"
        safe_execute git checkout "$version"
    fi
}

function components_download_release() {
    local name="$1"
    local url="$2"
    local version="$3"
    local components_dir="$4"
    local extra="$5"
    
    local target_dir="${components_dir}/${name}"
    local filename=$(basename "$url")
    
    section_header "Downloading Release Component: ${name}"
    
    safe_execute mkdir -p "$target_dir"
    safe_execute wget -O "${target_dir}/${filename}" "$url"
    
    # Handle rename option
    if [[ "$extra" =~ rename=(.+) ]]; then
        local new_name="${BASH_REMATCH[1]}"
        safe_execute mv "${target_dir}/${filename}" "${target_dir}/${new_name}"
    fi
}

function components_build_component() {
    local name="$1"
    local build_func="$2"
    local components_dir="$3"
    
    section_header "Building Component: ${name}"
    
    local component_dir="${components_dir}/${name}"
    safe_execute cd "$component_dir"
    
    # Call the specific build function
    "$build_func" "$name" "$component_dir"
}

# Rust build functions for ThreeFold components
function build_zinit() {
    local name="$1"
    local component_dir="$2"
    
    log_info "Building zinit with musl target"
    export RUSTFLAGS="-C target-feature=+crt-static"
    safe_execute cargo build --release --target x86_64-unknown-linux-musl
    
    # Copy binary to install location
    local binary_path="target/x86_64-unknown-linux-musl/release/zinit"
    safe_execute cp "$binary_path" "${INSTALL_DIR}/sbin/zinit"
}

function build_rfs() {
    local name="$1"
    local component_dir="$2"
    
    log_info "Building rfs with musl target"
    export RUSTFLAGS="-C target-feature=+crt-static"
    safe_execute cargo build --release --target x86_64-unknown-linux-musl
    
    # Copy binary to install location
    local binary_path="target/x86_64-unknown-linux-musl/release/rfs"
    safe_execute cp "$binary_path" "${INSTALL_DIR}/usr/bin/rfs"
}

function build_mycelium() {
    local name="$1"
    local component_dir="$2"
    
    log_info "Building mycelium with musl target (special directory)"
    safe_execute cd myceliumd
    export RUSTFLAGS="-C target-feature=+crt-static"
    safe_execute cargo build --release --target x86_64-unknown-linux-musl
    
    # Copy binary from special path
    local binary_path="target/x86_64-unknown-linux-musl/release/mycelium"
    safe_execute cp "$binary_path" "${INSTALL_DIR}/usr/bin/mycelium"
}

function install_corex() {
    local name="$1"
    local component_dir="$2"
    
    log_info "Installing corex binary"
    safe_execute chmod +x "${component_dir}/corex"
    safe_execute cp "${component_dir}/corex" "${INSTALL_DIR}/usr/bin/corex"
}

5. Initramfs Assembly (scripts/lib/initramfs.sh)

#!/bin/bash
# Initramfs assembly and optimization

function initramfs_setup_zinit() {
    local initramfs_dir="$1"
    local zinit_config_dir="$2"
    
    section_header "Setting up zinit as init"
    
    # Replace /sbin/init with zinit
    safe_execute rm -f "${initramfs_dir}/sbin/init"
    safe_execute ln -sf zinit "${initramfs_dir}/sbin/init"
    
    # Copy zinit configuration
    safe_execute mkdir -p "${initramfs_dir}/etc/zinit"
    safe_execute cp -r "${zinit_config_dir}"/* "${initramfs_dir}/etc/zinit/"
}

function initramfs_setup_modules() {
    local initramfs_dir="$1"
    local modules_conf="$2"
    local kernel_version="$3"
    
    section_header "Setting up 2-stage module loading"
    
    local modules_dir="${initramfs_dir}/lib/modules/${kernel_version}"
    safe_execute mkdir -p "$modules_dir"
    
    # Create stage1 and stage2 module lists
    grep "^stage1:" "$modules_conf" | cut -d: -f2 > "${modules_dir}/stage1.list"
    grep "^stage2:" "$modules_conf" | cut -d: -f2 > "${modules_dir}/stage2.list"
}

function initramfs_strip_and_upx() {
    local initramfs_dir="$1"
    
    section_header "Stripping and UPX compressing binaries"
    
    # Find all executables and strip them
    find "$initramfs_dir" -type f -executable -print0 | while IFS= read -r -d '' file; do
        if file "$file" | grep -q "ELF.*executable"; then
            log_info "Stripping: $file"
            safe_execute strip "$file" || log_warn "Failed to strip $file"
            
            log_info "UPX compressing: $file"
            safe_execute upx --best "$file" || log_warn "Failed to UPX $file"
        fi
    done
    
    # Strip libraries too
    find "$initramfs_dir" -name "*.so*" -type f -print0 | while IFS= read -r -d '' file; do
        if file "$file" | grep -q "ELF.*shared object"; then
            log_info "Stripping library: $file"
            safe_execute strip "$file" || log_warn "Failed to strip $file"
        fi
    done
}

function initramfs_create_cpio() {
    local initramfs_dir="$1"
    local output_file="$2"
    
    section_header "Creating initramfs.cpio.xz"
    
    safe_execute cd "$initramfs_dir"
    safe_execute find . | cpio -o -H newc | xz -9 --check=crc32 > "$output_file"
    
    local size=$(du -h "$output_file" | cut -f1)
    log_info "Created initramfs: $output_file ($size)"
}

6. Configuration Files

config/packages.list (migrate from existing)

# Based on existing configs/packages-minimal.txt
# Core system (essential only)
alpine-baselayout
busybox
musl

# Module loading & hardware detection  
eudev
eudev-hwids
eudev-libs
eudev-netifnames
kmod

# Console/terminal management
util-linux

# Essential networking
iproute2
ethtool

# Filesystem support
btrfs-progs
dosfstools

# Essential libraries
zlib

# Network utilities
dhcpcd
tcpdump
bmon

# Random number generation
haveged

# SSH access and terminal multiplexer
openssh-server
zellij

config/modules.conf

# 2-stage module loading based on existing configs/modules-essential.list

# Stage 1: Critical boot modules
stage1:virtio_net
stage1:virtio_scsi
stage1:virtio_blk
stage1:virtio_pci
stage1:e1000
stage1:e1000e
stage1:scsi_mod
stage1:sd_mod

# Stage 2: Extended hardware support
stage2:igb
stage2:ixgbe
stage2:i40e
stage2:ice
stage2:r8169
stage2:bnx2
stage2:bnx2x
stage2:tg3
stage2:overlay
stage2:tun

config/zinit/zinit.conf

# Main zinit configuration
log_level: debug
init:
  - stage1-modules
  - stage2-modules
  - networking
  - services

7. Main Build Script (scripts/build.sh)

#!/bin/bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"

# Source all libraries
source "${SCRIPT_DIR}/lib/docker.sh"
source "${SCRIPT_DIR}/lib/alpine.sh"
source "${SCRIPT_DIR}/lib/components.sh"
source "${SCRIPT_DIR}/lib/initramfs.sh"
source "${SCRIPT_DIR}/lib/kernel.sh"
source "${SCRIPT_DIR}/lib/testing.sh"

# Configuration
ALPINE_VERSION="3.22"
KERNEL_VERSION="6.8.8"
export INSTALL_DIR="${PROJECT_ROOT}/initramfs"
export COMPONENTS_DIR="${PROJECT_ROOT}/components"
export KERNEL_DIR="${PROJECT_ROOT}/kernel"
export DIST_DIR="${PROJECT_ROOT}/dist"

function main() {
    section_header "Zero OS Alpine Initramfs Builder"
    
    # Setup build environment
    setup_build_environment
    
    # Extract Alpine miniroot
    alpine_extract_miniroot "$INSTALL_DIR"
    
    # Install packages
    alpine_install_packages "$INSTALL_DIR" "${PROJECT_ROOT}/config/packages.list"
    
    # Build and install components
    export INSTALL_DIR  # Make available to component build functions
    components_parse_sources_conf "${PROJECT_ROOT}/config/sources.conf" "$COMPONENTS_DIR"
    
    # Setup zinit
    initramfs_setup_zinit "$INSTALL_DIR" "${PROJECT_ROOT}/config/zinit"
    
    # Setup modules
    initramfs_setup_modules "$INSTALL_DIR" "${PROJECT_ROOT}/config/modules.conf" "$KERNEL_VERSION"
    
    # Aggressive cleanup
    alpine_aggressive_cleanup "$INSTALL_DIR"
    
    # Strip and UPX all binaries
    initramfs_strip_and_upx "$INSTALL_DIR"
    
    # Create initramfs
    initramfs_create_cpio "$INSTALL_DIR" "${DIST_DIR}/initramfs.cpio.xz"
    
    # Build kernel with embedded initramfs
    kernel_build_with_initramfs "${PROJECT_ROOT}/config/kernel.config" "${DIST_DIR}/initramfs.cpio.xz" "${DIST_DIR}/vmlinuz.efi"
    
    section_header "Build Complete"
    log_info "Artifacts created in: $DIST_DIR"
}

function setup_build_environment() {
    section_header "Setting up build environment"
    
    safe_execute mkdir -p "$INSTALL_DIR"
    safe_execute mkdir -p "$COMPONENTS_DIR"
    safe_execute mkdir -p "$KERNEL_DIR"
    safe_execute mkdir -p "$DIST_DIR"
    
    # Install build dependencies
    if command -v apk >/dev/null 2>&1; then
        safe_execute apk add --no-cache build-base rust cargo upx strip git wget
    elif command -v apt-get >/dev/null 2>&1; then
        safe_execute apt-get update
        safe_execute apt-get install -y build-essential rustc cargo upx-ucl binutils git wget
    fi
}

main "$@"

Next Steps

  1. Switch to Code Mode: Request mode switch to implement all files
  2. Migrate Configs: Move existing configurations to new structure
  3. Test Build: Run complete build process
  4. Optimize: Fine-tune strip/UPX and size optimization
  5. Documentation: Create README and GitHub Actions integration

This plan provides a complete, production-ready build system with:

  • Rootless container support
  • Rust builds with musl targeting
  • Strip + UPX optimization
  • Strict error handling
  • Modular architecture
  • GitHub Actions compatibility
  • 2-stage module loading
  • Complete zinit integration