# CLAUDE.md — KubeSolo OS ## Project Overview **KubeSolo OS** is an immutable, bootable Linux distribution purpose-built to run [KubeSolo](https://github.com/portainer/kubesolo) — Portainer's ultra-lightweight single-node Kubernetes distribution. It combines Tiny Core Linux's minimal footprint (~11 MB) with KubeSolo's single-binary K8s packaging to create an appliance-like Kubernetes node with atomic A/B updates. **Design document:** See `docs/design/kubesolo-os-design.md` for full architecture research, competitive analysis, and technical specifications. **Target:** Edge/IoT devices, single-node K8s appliances, air-gapped deployments, resource-constrained hardware. --- ## Repository Structure ``` kubesolo-os/ ├── CLAUDE.md # This file ├── README.md # Project README ├── Makefile # Top-level build orchestration ├── VERSION # Semver version (e.g., 0.1.0) │ ├── docs/ │ ├── design/ │ │ └── kubesolo-os-design.md # Full architecture document │ ├── boot-flow.md # Boot sequence documentation │ ├── update-flow.md # Atomic update documentation │ └── cloud-init.md # Configuration reference │ ├── build/ # Build system │ ├── Dockerfile.builder # Containerized build environment │ ├── build.sh # Main build script (orchestrator) │ ├── config/ │ │ ├── kernel-audit.sh # Verify kernel config requirements │ │ ├── kernel-config.fragment # Custom kernel config overrides (if needed) │ │ └── modules.list # Required kernel modules list │ ├── rootfs/ # Files injected into initramfs │ │ ├── sbin/ │ │ │ └── init # Custom init script │ │ ├── etc/ │ │ │ ├── os-release # OS identification │ │ │ ├── sysctl.d/ │ │ │ │ └── k8s.conf # Kernel parameters for K8s │ │ │ └── kubesolo/ │ │ │ └── defaults.yaml # Default KubeSolo config │ │ └── usr/ │ │ └── lib/ │ │ └── kubesolo-os/ │ │ ├── functions.sh # Shared shell functions │ │ ├── network.sh # Network configuration helpers │ │ └── health.sh # Health check functions │ ├── grub/ │ │ ├── grub.cfg # A/B boot GRUB config │ │ └── grub-env-defaults # Default GRUB environment vars │ └── scripts/ │ ├── fetch-components.sh # Download Tiny Core, KubeSolo, deps │ ├── extract-core.sh # Extract and prepare Tiny Core rootfs │ ├── inject-kubesolo.sh # Add KubeSolo + deps to rootfs │ ├── pack-initramfs.sh # Repack initramfs (core.gz → kubesolo-os.gz) │ ├── create-iso.sh # Build bootable ISO │ ├── create-disk-image.sh # Build raw disk image with A/B partitions │ └── create-oci-image.sh # Build OCI container image (future) │ ├── init/ # Init system source │ ├── init.sh # Main init script (becomes /sbin/init) │ ├── lib/ │ │ ├── 00-early-mount.sh # Mount proc, sys, dev, tmpfs │ │ ├── 10-parse-cmdline.sh # Parse kernel boot parameters │ │ ├── 20-persistent-mount.sh # Mount + bind persistent data partition │ │ ├── 30-kernel-modules.sh # Load required kernel modules │ │ ├── 40-sysctl.sh # Apply sysctl settings │ │ ├── 50-network.sh # Network configuration (cloud-init/DHCP) │ │ ├── 60-hostname.sh # Set hostname │ │ ├── 70-clock.sh # NTP / system clock │ │ ├── 80-containerd.sh # Start containerd │ │ └── 90-kubesolo.sh # Start KubeSolo (final stage) │ └── emergency-shell.sh # Drop to shell on boot failure │ ├── update/ # Atomic update agent │ ├── go.mod │ ├── go.sum │ ├── main.go # Update agent entrypoint │ ├── cmd/ │ │ ├── check.go # Check for available updates │ │ ├── apply.go # Download + write to passive partition │ │ ├── activate.go # Update GRUB, set boot counter │ │ ├── rollback.go # Force rollback to previous partition │ │ └── healthcheck.go # Post-boot health verification │ ├── pkg/ │ │ ├── grubenv/ # GRUB environment manipulation │ │ │ └── grubenv.go │ │ ├── partition/ # Partition detection and management │ │ │ └── partition.go │ │ ├── image/ # Image download, verify, write │ │ │ └── image.go │ │ └── health/ # K8s + containerd health checks │ │ └── health.go │ └── deploy/ │ └── update-cronjob.yaml # K8s CronJob manifest for auto-updates │ ├── cloud-init/ # Cloud-init implementation │ ├── cloud-init.go # Lightweight cloud-init parser │ ├── network.go # Network config from cloud-init │ ├── kubesolo.go # KubeSolo config from cloud-init │ └── examples/ │ ├── dhcp.yaml # DHCP example │ ├── static-ip.yaml # Static IP example │ ├── portainer-edge.yaml # Portainer Edge integration │ └── airgapped.yaml # Air-gapped deployment │ ├── test/ # Testing │ ├── Makefile # Test orchestration │ ├── qemu/ │ │ ├── run-vm.sh # Launch QEMU VM with built image │ │ ├── test-boot.sh # Automated boot test │ │ ├── test-persistence.sh # Reboot + verify state survives │ │ ├── test-update.sh # A/B update cycle test │ │ └── test-rollback.sh # Forced rollback test │ ├── integration/ │ │ ├── test-k8s-ready.sh # Verify K8s node reaches Ready │ │ ├── test-deploy-workload.sh # Deploy nginx, verify pod running │ │ ├── test-local-storage.sh # PVC with local-path provisioner │ │ └── test-network-policy.sh # Basic network policy enforcement │ └── kernel/ │ └── check-config.sh # Validate kernel config requirements │ └── hack/ # Developer utilities ├── dev-vm.sh # Quick-launch dev VM (QEMU) ├── rebuild-initramfs.sh # Fast rebuild for dev iteration ├── inject-ssh.sh # Add SSH extension for debugging └── extract-kernel-config.sh # Pull /proc/config.gz from running TC ``` --- ## Architecture Summary ### Core Concept KubeSolo OS is a **remastered Tiny Core Linux** where the initramfs (`core.gz`) is rebuilt to include KubeSolo and all its dependencies. The result is a single bootable image that: 1. Boots kernel + initramfs into RAM (read-only SquashFS root) 2. Mounts a persistent ext4 partition for K8s state 3. Bind-mounts writable paths (`/var/lib/kubesolo`, `/var/lib/containerd`, etc.) 4. Loads kernel modules (br_netfilter, overlay, veth, etc.) 5. Configures networking (cloud-init → persistent config → DHCP fallback) 6. Starts containerd, then KubeSolo 7. Kubernetes API becomes available; node reaches Ready ### Partition Layout ``` Disk (minimum 8 GB): Part 1: EFI/Boot (256 MB, FAT32) — GRUB + A/B boot logic Part 2: System A (512 MB, ext4) — vmlinuz + kubesolo-os.gz (active) Part 3: System B (512 MB, ext4) — vmlinuz + kubesolo-os.gz (passive) Part 4: Data (remaining, ext4) — persistent K8s state ``` ### Persistent Paths (survive updates) | Mount Point | Content | On Data Partition | |---|---|---| | `/var/lib/kubesolo` | K8s state, certs, SQLite DB | `/mnt/data/kubesolo` | | `/var/lib/containerd` | Container images + layers | `/mnt/data/containerd` | | `/etc/kubesolo` | Node configuration | `/mnt/data/etc-kubesolo` | | `/var/log` | System + K8s logs | `/mnt/data/log` | | `/usr/local` | User data, extra binaries | `/mnt/data/usr-local` | ### Atomic Updates A/B partition scheme with GRUB fallback counter: - Update writes new image to passive partition - GRUB boots new partition with `boot_counter=3` - Health check sets `boot_success=1` on success - On 3 consecutive failures (counter reaches 0), GRUB auto-rolls back --- ## Technology Stack | Component | Technology | Rationale | |---|---|---| | Base OS | Tiny Core Linux 17.0 (Micro Core, x86_64) | 11 MB, RAM-resident, SquashFS root | | Kernel | Tiny Core stock (6.x) or custom build | Must have cgroup v2, namespaces, netfilter | | Kubernetes | KubeSolo (single binary) | Single-node K8s, SQLite backend, bundled runtime | | Container runtime | containerd + runc (bundled in KubeSolo) | Industry standard, KubeSolo dependency | | Init | Custom shell script (POSIX sh) | Minimal, no systemd dependency | | Bootloader | GRUB 2 (EFI + BIOS) | A/B partition support, env variables | | Update agent | Go binary | Single static binary, K8s client-go | | Cloud-init parser | Go binary or shell script | First-boot configuration | | Build system | Bash + Make + Docker (builder container) | Reproducible builds | | Testing | QEMU/KVM + shell scripts | Automated boot + integration tests | --- ## Development Guidelines ### Shell Scripts (init system, build scripts) - **POSIX sh** — no bashisms in init scripts (BusyBox ash compatibility) - **Shellcheck** all scripts: `shellcheck -s sh