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>
141 lines
3.8 KiB
Bash
Executable File
141 lines
3.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# create-iso.sh — Create a bootable ISO from kernel + initramfs
|
|
# Uses isolinux (syslinux) for Phase 1 simplicity (GRUB in Phase 3)
|
|
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}"
|
|
OUTPUT_DIR="${OUTPUT_DIR:-$PROJECT_ROOT/output}"
|
|
VERSION="$(cat "$PROJECT_ROOT/VERSION")"
|
|
OS_NAME="kubesolo-os"
|
|
|
|
ISO_STAGING="$ROOTFS_DIR/iso-staging"
|
|
ISO_OUTPUT="$OUTPUT_DIR/${OS_NAME}-${VERSION}.iso"
|
|
|
|
VMLINUZ="$ROOTFS_DIR/vmlinuz"
|
|
INITRAMFS="$ROOTFS_DIR/kubesolo-os.gz"
|
|
|
|
# Validate inputs
|
|
for f in "$VMLINUZ" "$INITRAMFS"; do
|
|
if [ ! -f "$f" ]; then
|
|
echo "ERROR: Missing required file: $f"
|
|
echo "Run 'make initramfs' first."
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# Check for required tools
|
|
for cmd in mkisofs xorriso genisoimage; do
|
|
if command -v "$cmd" >/dev/null 2>&1; then
|
|
MKISO_CMD="$cmd"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -z "${MKISO_CMD:-}" ]; then
|
|
echo "ERROR: Need mkisofs, genisoimage, or xorriso to create ISO"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Stage ISO contents ---
|
|
rm -rf "$ISO_STAGING"
|
|
mkdir -p "$ISO_STAGING/boot/isolinux"
|
|
|
|
cp "$VMLINUZ" "$ISO_STAGING/boot/vmlinuz"
|
|
cp "$INITRAMFS" "$ISO_STAGING/boot/kubesolo-os.gz"
|
|
|
|
# Find isolinux.bin
|
|
ISOLINUX_BIN=""
|
|
for path in /usr/lib/ISOLINUX/isolinux.bin /usr/lib/syslinux/isolinux.bin \
|
|
/usr/share/syslinux/isolinux.bin /usr/lib/syslinux/bios/isolinux.bin; do
|
|
[ -f "$path" ] && ISOLINUX_BIN="$path" && break
|
|
done
|
|
|
|
if [ -z "$ISOLINUX_BIN" ]; then
|
|
echo "ERROR: Cannot find isolinux.bin. Install syslinux/isolinux package."
|
|
exit 1
|
|
fi
|
|
|
|
cp "$ISOLINUX_BIN" "$ISO_STAGING/boot/isolinux/"
|
|
|
|
# Copy ldlinux.c32 if it exists (needed by syslinux 6+)
|
|
LDLINUX_DIR="$(dirname "$ISOLINUX_BIN")"
|
|
for mod in ldlinux.c32 libcom32.c32 libutil.c32 mboot.c32; do
|
|
[ -f "$LDLINUX_DIR/$mod" ] && cp "$LDLINUX_DIR/$mod" "$ISO_STAGING/boot/isolinux/"
|
|
done
|
|
|
|
# Isolinux config
|
|
cat > "$ISO_STAGING/boot/isolinux/isolinux.cfg" << 'EOF'
|
|
DEFAULT kubesolo
|
|
TIMEOUT 30
|
|
PROMPT 0
|
|
|
|
LABEL kubesolo
|
|
MENU LABEL KubeSolo OS
|
|
KERNEL /boot/vmlinuz
|
|
INITRD /boot/kubesolo-os.gz
|
|
APPEND quiet kubesolo.data=LABEL=KSOLODATA
|
|
|
|
LABEL kubesolo-debug
|
|
MENU LABEL KubeSolo OS (debug)
|
|
KERNEL /boot/vmlinuz
|
|
INITRD /boot/kubesolo-os.gz
|
|
APPEND kubesolo.data=LABEL=KSOLODATA kubesolo.debug console=ttyS0,115200n8
|
|
|
|
LABEL kubesolo-shell
|
|
MENU LABEL KubeSolo OS (emergency shell)
|
|
KERNEL /boot/vmlinuz
|
|
INITRD /boot/kubesolo-os.gz
|
|
APPEND kubesolo.shell console=ttyS0,115200n8
|
|
|
|
LABEL kubesolo-nopersist
|
|
MENU LABEL KubeSolo OS (RAM only, no persistence)
|
|
KERNEL /boot/vmlinuz
|
|
INITRD /boot/kubesolo-os.gz
|
|
APPEND kubesolo.nopersist
|
|
EOF
|
|
|
|
# --- Create ISO ---
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
case "$MKISO_CMD" in
|
|
xorriso)
|
|
xorriso -as mkisofs \
|
|
-o "$ISO_OUTPUT" \
|
|
-isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin 2>/dev/null || true \
|
|
-c boot/isolinux/boot.cat \
|
|
-b boot/isolinux/isolinux.bin \
|
|
-no-emul-boot \
|
|
-boot-load-size 4 \
|
|
-boot-info-table \
|
|
"$ISO_STAGING"
|
|
;;
|
|
*)
|
|
"$MKISO_CMD" \
|
|
-o "$ISO_OUTPUT" \
|
|
-b boot/isolinux/isolinux.bin \
|
|
-c boot/isolinux/boot.cat \
|
|
-no-emul-boot \
|
|
-boot-load-size 4 \
|
|
-boot-info-table \
|
|
-J -R -V "KUBESOLOOS" \
|
|
"$ISO_STAGING"
|
|
;;
|
|
esac
|
|
|
|
# Make ISO hybrid-bootable (USB stick)
|
|
if command -v isohybrid >/dev/null 2>&1; then
|
|
isohybrid "$ISO_OUTPUT" 2>/dev/null || true
|
|
fi
|
|
|
|
# Clean staging
|
|
rm -rf "$ISO_STAGING"
|
|
|
|
echo ""
|
|
echo "==> ISO created: $ISO_OUTPUT"
|
|
echo " Size: $(du -h "$ISO_OUTPUT" | cut -f1)"
|
|
echo ""
|
|
echo " Boot in QEMU: make dev-vm"
|
|
echo " Write to USB: dd if=$ISO_OUTPUT of=/dev/sdX bs=4M status=progress"
|