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
This commit is contained in:
2025-08-31 12:31:49 +02:00
commit 860b9aa161
81 changed files with 30118 additions and 0 deletions

276
scripts/lib/docker.sh Normal file
View File

@@ -0,0 +1,276 @@
#!/bin/bash
# Container management for rootless Docker/Podman builds
# Source common functions
LIB_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${LIB_SCRIPT_DIR}/common.sh"
# Container configuration
CONTAINER_RUNTIME=""
BUILDER_IMAGE="zero-os-builder:latest"
ALPINE_VERSION="${ALPINE_VERSION:-3.22}"
# Detect available container runtime
function docker_detect_runtime() {
section_header "Detecting Container Runtime"
if command_exists "podman"; then
CONTAINER_RUNTIME="podman"
log_info "Using Podman as container runtime"
elif command_exists "docker"; then
CONTAINER_RUNTIME="docker"
log_info "Using Docker as container runtime"
else
log_error "No container runtime found (podman or docker required)"
return 1
fi
# Check if rootless setup is working
docker_verify_rootless
}
# Verify rootless container setup
function docker_verify_rootless() {
section_header "Verifying Rootless Container Setup"
log_info "Checking ${CONTAINER_RUNTIME} rootless configuration"
safe_execute ${CONTAINER_RUNTIME} system info
# Test basic rootless functionality
log_info "Testing rootless container execution"
safe_execute ${CONTAINER_RUNTIME} run --rm alpine:${ALPINE_VERSION} echo "Rootless container test successful"
log_info "Rootless container setup verified"
}
# Build container image with build tools
function docker_build_container() {
local dockerfile_path="${1:-${PROJECT_ROOT}/Dockerfile}"
local tag="${2:-${BUILDER_IMAGE}}"
section_header "Building Container Image"
# Create Dockerfile if it doesn't exist
if [[ ! -f "$dockerfile_path" ]]; then
docker_create_dockerfile "$dockerfile_path"
fi
log_info "Building container image: ${tag}"
safe_execute ${CONTAINER_RUNTIME} build -t "${tag}" -f "${dockerfile_path}" "${PROJECT_ROOT}"
log_info "Container image built successfully: ${tag}"
}
# Create optimized Dockerfile for build environment
function docker_create_dockerfile() {
local dockerfile_path="$1"
section_header "Creating Dockerfile"
cat > "$dockerfile_path" << 'EOF'
FROM alpine:3.22
# Install build dependencies
RUN apk add --no-cache \
build-base \
rust \
cargo \
upx \
git \
wget \
tar \
gzip \
xz \
cpio \
binutils \
linux-headers \
musl-dev \
pkgconfig \
openssl-dev
# Add Rust musl target
RUN rustup target add x86_64-unknown-linux-musl
# Create non-root user for builds
RUN adduser -D -s /bin/sh builder && \
chown -R builder:builder /home/builder
# Set working directory
WORKDIR /workspace
# Switch to non-root user
USER builder
# Set environment variables for static linking
ENV RUSTFLAGS="-C target-feature=+crt-static"
ENV CC_x86_64_unknown_linux_musl="musl-gcc"
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER="musl-gcc"
CMD ["/bin/sh"]
EOF
log_info "Created Dockerfile: ${dockerfile_path}"
}
# Start rootless container for building
function docker_start_rootless() {
local image="${1:-${BUILDER_IMAGE}}"
local workdir="${2:-/workspace}"
local command="${3:-/bin/sh}"
section_header "Starting Rootless Container"
# Setup volume mounts
local user_args="--user $(id -u):$(id -g)"
local volume_args="-v ${PROJECT_ROOT}:${workdir}"
local env_args=""
# Pass through environment variables
local env_vars=(
"DEBUG"
"ALPINE_VERSION"
"KERNEL_VERSION"
"RUST_TARGET"
"OPTIMIZATION_LEVEL"
)
for var in "${env_vars[@]}"; do
if [[ -n "${!var:-}" ]]; then
env_args="${env_args} -e ${var}=${!var}"
fi
done
log_info "Starting container with rootless privileges"
safe_execute ${CONTAINER_RUNTIME} run --rm -it \
${user_args} \
${volume_args} \
${env_args} \
-w "${workdir}" \
"${image}" \
${command}
}
# Run build command in container
function docker_run_build() {
local build_script="${1:-./scripts/build.sh}"
local image="${2:-${BUILDER_IMAGE}}"
section_header "Running Build in Container"
# Ensure build script is executable
safe_execute chmod +x "${PROJECT_ROOT}/${build_script}"
# Setup container arguments
local user_args="--user $(id -u):$(id -g)"
local volume_args="-v ${PROJECT_ROOT}:/workspace"
local work_args="-w /workspace"
log_info "Executing build script in container: ${build_script}"
safe_execute ${CONTAINER_RUNTIME} run --rm \
${user_args} \
${volume_args} \
${work_args} \
"${image}" \
${build_script}
}
# Commit container state for reuse
function docker_commit_builder() {
local container_id="$1"
local new_tag="${2:-${BUILDER_IMAGE}-cached}"
section_header "Committing Builder Container"
log_info "Committing container ${container_id} as ${new_tag}"
safe_execute ${CONTAINER_RUNTIME} commit "${container_id}" "${new_tag}"
log_info "Container committed successfully: ${new_tag}"
}
# Clean up container images
function docker_cleanup() {
local keep_builder="${1:-false}"
section_header "Cleaning Up Container Images"
if [[ "$keep_builder" != "true" ]]; then
log_info "Removing builder images"
safe_execute ${CONTAINER_RUNTIME} rmi "${BUILDER_IMAGE}" || true
safe_execute ${CONTAINER_RUNTIME} rmi "${BUILDER_IMAGE}-cached" || true
fi
log_info "Pruning unused containers and images"
safe_execute ${CONTAINER_RUNTIME} system prune -f
log_info "Container cleanup complete"
}
# Check container runtime capabilities
function docker_check_capabilities() {
section_header "Checking Container Capabilities"
# Check user namespace support
if [[ -f /proc/sys/user/max_user_namespaces ]]; then
local max_namespaces=$(cat /proc/sys/user/max_user_namespaces)
log_info "User namespaces available: ${max_namespaces}"
if [[ "$max_namespaces" -eq 0 ]]; then
log_warn "User namespaces are disabled, rootless containers may not work"
fi
fi
# Check subuid/subgid configuration
local current_user=$(whoami)
if [[ -f /etc/subuid ]] && grep -q "^${current_user}:" /etc/subuid; then
log_info "subuid configured for user: ${current_user}"
else
log_warn "subuid not configured for user: ${current_user}"
log_warn "Run: echo '${current_user}:100000:65536' | sudo tee -a /etc/subuid"
fi
if [[ -f /etc/subgid ]] && grep -q "^${current_user}:" /etc/subgid; then
log_info "subgid configured for user: ${current_user}"
else
log_warn "subgid not configured for user: ${current_user}"
log_warn "Run: echo '${current_user}:100000:65536' | sudo tee -a /etc/subgid"
fi
}
# Setup rootless environment
function docker_setup_rootless() {
section_header "Setting Up Rootless Environment"
local current_user=$(whoami)
# Check if running as root
if [[ "$EUID" -eq 0 ]]; then
log_error "Do not run as root. Rootless containers require non-root user."
return 1
fi
# Check and setup subuid/subgid if needed
if ! grep -q "^${current_user}:" /etc/subuid 2>/dev/null; then
log_info "Setting up subuid for ${current_user}"
echo "${current_user}:100000:65536" | sudo tee -a /etc/subuid
fi
if ! grep -q "^${current_user}:" /etc/subgid 2>/dev/null; then
log_info "Setting up subgid for ${current_user}"
echo "${current_user}:100000:65536" | sudo tee -a /etc/subgid
fi
# Initialize container runtime if needed
if [[ "$CONTAINER_RUNTIME" == "podman" ]]; then
log_info "Initializing Podman for rootless use"
safe_execute podman system migrate || true
fi
log_info "Rootless environment setup complete"
}
# Export functions
export -f docker_detect_runtime docker_verify_rootless
export -f docker_build_container docker_create_dockerfile
export -f docker_start_rootless docker_run_build
export -f docker_commit_builder docker_cleanup
export -f docker_check_capabilities docker_setup_rootless