feat: initial Phase 1 PoC scaffolding for KubeSolo OS

Complete Phase 1 implementation of KubeSolo OS — an immutable, bootable
Linux distribution built on Tiny Core Linux for running KubeSolo
single-node Kubernetes.

Build system:
- Makefile with fetch, rootfs, initramfs, iso, disk-image targets
- Dockerfile.builder for reproducible builds
- Scripts to download Tiny Core, extract rootfs, inject KubeSolo,
  pack initramfs, and create bootable ISO/disk images

Init system (10 POSIX sh stages):
- Early mount (proc/sys/dev/cgroup2), cmdline parsing, persistent
  mount with bind-mounts, kernel module loading, sysctl, DHCP
  networking, hostname, clock sync, containerd prep, KubeSolo exec

Shared libraries:
- functions.sh (device wait, IP lookup, config helpers)
- network.sh (static IP, config persistence, interface detection)
- health.sh (containerd, API server, node readiness checks)
- Emergency shell for boot failure debugging

Testing:
- QEMU boot test with serial log marker detection
- K8s readiness test with kubectl verification
- Persistence test (reboot + verify state survives)
- Workload deployment test (nginx pod)
- Local storage test (PVC + local-path provisioner)
- Network policy test
- Reusable run-vm.sh launcher

Developer tools:
- dev-vm.sh (interactive QEMU with port forwarding)
- rebuild-initramfs.sh (fast iteration)
- inject-ssh.sh (dropbear SSH for debugging)
- extract-kernel-config.sh + kernel-audit.sh

Documentation:
- Full design document with architecture research
- Boot flow documentation covering all 10 init stages
- Cloud-init examples (DHCP, static IP, Portainer Edge, air-gapped)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 10:18:42 -06:00
commit e372df578b
50 changed files with 4392 additions and 0 deletions

84
hack/dev-vm.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/bin/bash
# dev-vm.sh — Launch a QEMU VM for development and testing
# Usage: ./hack/dev-vm.sh [path-to-iso-or-img] [--shell] [--debug]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
VERSION="$(cat "$PROJECT_ROOT/VERSION")"
DEFAULT_ISO="$PROJECT_ROOT/output/kubesolo-os-${VERSION}.iso"
DEFAULT_IMG="$PROJECT_ROOT/output/kubesolo-os-${VERSION}.img"
IMAGE="${1:-}"
EXTRA_APPEND=""
SERIAL_OPTS="-serial stdio"
# Parse flags
shift || true
for arg in "$@"; do
case "$arg" in
--shell) EXTRA_APPEND="$EXTRA_APPEND kubesolo.shell" ;;
--debug) EXTRA_APPEND="$EXTRA_APPEND kubesolo.debug" ;;
esac
done
# Auto-detect image
if [ -z "$IMAGE" ]; then
if [ -f "$DEFAULT_ISO" ]; then
IMAGE="$DEFAULT_ISO"
elif [ -f "$DEFAULT_IMG" ]; then
IMAGE="$DEFAULT_IMG"
else
echo "ERROR: No image found. Run 'make iso' or 'make disk-image' first."
echo " Or specify path: $0 <path-to-iso-or-img>"
exit 1
fi
fi
echo "==> Launching QEMU with: $IMAGE"
echo " Press Ctrl+A, X to exit"
echo ""
# Create a temporary data disk for persistence testing
DATA_DISK=$(mktemp /tmp/kubesolo-data-XXXXXX.img)
dd if=/dev/zero of="$DATA_DISK" bs=1M count=1024 2>/dev/null
mkfs.ext4 -q -L KSOLODATA "$DATA_DISK" 2>/dev/null
cleanup() { rm -f "$DATA_DISK"; }
trap cleanup EXIT
COMMON_OPTS=(
-m 2048
-smp 2
-nographic
-net nic,model=virtio
-net user,hostfwd=tcp::6443-:6443,hostfwd=tcp::2222-:22
-drive "file=$DATA_DISK,format=raw,if=virtio"
)
# Enable KVM if available
if [ -w /dev/kvm ] 2>/dev/null; then
COMMON_OPTS+=(-enable-kvm)
echo " KVM acceleration: enabled"
else
echo " KVM acceleration: not available (using TCG)"
fi
case "$IMAGE" in
*.iso)
qemu-system-x86_64 \
"${COMMON_OPTS[@]}" \
-cdrom "$IMAGE" \
-boot d \
-append "console=ttyS0,115200n8 kubesolo.data=/dev/vda $EXTRA_APPEND"
;;
*.img)
qemu-system-x86_64 \
"${COMMON_OPTS[@]}" \
-drive "file=$IMAGE,format=raw,if=virtio"
;;
*)
echo "ERROR: Unrecognized image format: $IMAGE"
exit 1
;;
esac

48
hack/extract-kernel-config.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
# extract-kernel-config.sh — Pull kernel config from Tiny Core rootfs
# Usage: ./hack/extract-kernel-config.sh [path-to-core.gz]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
ROOTFS_DIR="${ROOTFS_DIR:-$PROJECT_ROOT/build/rootfs-work}"
COREGZ="${1:-$ROOTFS_DIR/rootfs}"
OUTPUT="$PROJECT_ROOT/build/cache/kernel-config"
if [ -d "$COREGZ" ]; then
# Rootfs already extracted
ROOTFS="$COREGZ"
elif [ -f "$COREGZ" ]; then
# Extract core.gz
TMPDIR=$(mktemp -d)
cd "$TMPDIR"
zcat "$COREGZ" | cpio -idm 2>/dev/null
ROOTFS="$TMPDIR"
fi
# Try /proc/config.gz in rootfs
if [ -f "$ROOTFS/proc/config.gz" ]; then
zcat "$ROOTFS/proc/config.gz" > "$OUTPUT"
echo "==> Extracted kernel config to: $OUTPUT"
"$PROJECT_ROOT/build/config/kernel-audit.sh" "$OUTPUT"
else
echo "Kernel config not found in rootfs /proc/config.gz"
echo ""
echo "Alternative: Boot the Tiny Core ISO in QEMU and run:"
echo " zcat /proc/config.gz > /tmp/kernel-config"
echo " # Then copy it out"
echo ""
echo "Or check if /boot/config-* exists in the ISO"
# Try looking in /boot
for f in "$ROOTFS"/boot/config-*; do
[ -f "$f" ] || continue
cp "$f" "$OUTPUT"
echo "==> Found boot config: $f$OUTPUT"
"$PROJECT_ROOT/build/config/kernel-audit.sh" "$OUTPUT"
exit 0
done
fi
[ -d "${TMPDIR:-}" ] && rm -rf "$TMPDIR"

82
hack/inject-ssh.sh Executable file
View File

@@ -0,0 +1,82 @@
#!/bin/bash
# inject-ssh.sh — Add SSH (dropbear) to initramfs for debugging
# Usage: ./hack/inject-ssh.sh [path-to-kubesolo-os.gz]
#
# This adds a minimal SSH server to the initramfs so you can SSH into the
# running KubeSolo OS for debugging. NOT for production use.
#
# Prerequisites: dropbear binaries (statically compiled) or tcz packages
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
ROOTFS_DIR="${ROOTFS_DIR:-$PROJECT_ROOT/build/rootfs-work}"
ROOTFS="$ROOTFS_DIR/rootfs"
INITRAMFS="${1:-$ROOTFS_DIR/kubesolo-os.gz}"
if [ ! -d "$ROOTFS" ]; then
echo "ERROR: Rootfs not found: $ROOTFS"
echo "Run 'make rootfs' first."
exit 1
fi
SSH_PUBKEY="${SSH_PUBKEY:-$HOME/.ssh/id_rsa.pub}"
if [ ! -f "$SSH_PUBKEY" ]; then
SSH_PUBKEY="$HOME/.ssh/id_ed25519.pub"
fi
if [ ! -f "$SSH_PUBKEY" ]; then
echo "ERROR: No SSH public key found."
echo "Set SSH_PUBKEY=/path/to/key.pub or generate one with: ssh-keygen"
exit 1
fi
echo "==> Injecting SSH support into rootfs..."
echo " Public key: $SSH_PUBKEY"
# Create SSH directories
mkdir -p "$ROOTFS/root/.ssh"
mkdir -p "$ROOTFS/etc/dropbear"
# Install authorized key
cp "$SSH_PUBKEY" "$ROOTFS/root/.ssh/authorized_keys"
chmod 700 "$ROOTFS/root/.ssh"
chmod 600 "$ROOTFS/root/.ssh/authorized_keys"
# Create a startup script for dropbear
cat > "$ROOTFS/usr/lib/kubesolo-os/init.d/85-ssh.sh" << 'EOF'
#!/bin/sh
# 85-ssh.sh — Start SSH server for debugging (dev only)
if command -v dropbear >/dev/null 2>&1; then
# Generate host keys if missing
if [ ! -f /etc/dropbear/dropbear_rsa_host_key ]; then
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key >/dev/null 2>&1
fi
if [ ! -f /etc/dropbear/dropbear_ed25519_host_key ]; then
dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key >/dev/null 2>&1
fi
dropbear -R -p 22 2>/dev/null
log_ok "SSH server (dropbear) started on port 22"
else
log_warn "dropbear not found — SSH not available"
log_warn "To add SSH, install dropbear statically compiled binary to /usr/sbin/dropbear"
fi
EOF
chmod +x "$ROOTFS/usr/lib/kubesolo-os/init.d/85-ssh.sh"
echo "==> SSH stage added (85-ssh.sh)"
echo ""
echo "==> NOTE: You still need the dropbear binary in the rootfs."
echo " Option 1: Download a static dropbear build:"
echo " wget -O $ROOTFS/usr/sbin/dropbear <url-to-static-dropbear>"
echo " chmod +x $ROOTFS/usr/sbin/dropbear"
echo ""
echo " Option 2: Build from source with CGO_ENABLED=0 equivalent"
echo ""
echo "==> After adding dropbear, rebuild:"
echo " make initramfs iso"
echo ""
echo "==> Then connect with:"
echo " ssh -p 2222 root@localhost (when using hack/dev-vm.sh)"

18
hack/rebuild-initramfs.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
# rebuild-initramfs.sh — Fast rebuild: re-inject init scripts + repack
# Skips fetch/extract — only updates init system and configs
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
echo "==> Quick rebuild: re-injecting init system..."
"$PROJECT_ROOT/build/scripts/inject-kubesolo.sh"
echo "==> Repacking initramfs..."
"$PROJECT_ROOT/build/scripts/pack-initramfs.sh"
echo "==> Rebuilding ISO..."
"$PROJECT_ROOT/build/scripts/create-iso.sh"
echo "==> Done. Run 'make dev-vm' to test."