# KubeSolo OS — Cloud-Init Configuration KubeSolo OS uses a lightweight cloud-init system to configure the node on first boot. The configuration is a YAML file placed on the data partition before the first boot. ## Configuration File Location The cloud-init config is loaded from (in priority order): 1. Path specified by `kubesolo.cloudinit=` boot parameter 2. `/mnt/data/etc-kubesolo/cloud-init.yaml` (default) ## Boot Sequence Integration Cloud-init runs as **init stage 45**, before network (stage 50) and hostname (stage 60). When cloud-init applies successfully, stages 50 and 60 detect this and skip their default behavior. ``` Stage 20: Mount persistent storage Stage 30: Load kernel modules Stage 40: Apply sysctl Stage 45: Cloud-init (parse YAML, apply hostname + network + KubeSolo config) <-- Stage 50: Network fallback (skipped if cloud-init handled it) Stage 60: Hostname fallback (skipped if cloud-init handled it) Stage 70: Clock sync Stage 80: Containerd prerequisites Stage 90: Start KubeSolo ``` ## YAML Schema ```yaml # Hostname for the node hostname: kubesolo-node # Network configuration network: mode: dhcp | static # Default: dhcp interface: eth0 # Optional: auto-detected if omitted address: 192.168.1.100/24 # Required for static mode (CIDR notation) gateway: 192.168.1.1 # Required for static mode dns: # Optional: DNS nameservers - 8.8.8.8 - 1.1.1.1 # KubeSolo settings kubesolo: extra-flags: "--disable traefik" # Extra CLI flags for KubeSolo binary local-storage: true # Enable local-path provisioner (default: true) local-storage-shared-path: "/mnt/shared" # Shared path for local-path-provisioner apiserver-extra-sans: # Extra SANs for API server certificate - node.example.com - 10.0.0.50 debug: false # Enable verbose debug logging pprof-server: false # Enable Go pprof profiling server portainer-edge-id: "" # Portainer Edge Agent ID portainer-edge-key: "" # Portainer Edge Agent key portainer-edge-async: false # Enable async Portainer Edge communication # NTP servers (optional) ntp: servers: - pool.ntp.org # Air-gapped deployment (optional) airgap: import-images: true # Import container images from data partition images-dir: /mnt/data/images # Directory containing .tar image files # Portainer Edge Agent (optional) portainer: edge-agent: enabled: true edge-id: "your-edge-id" edge-key: "your-edge-key" portainer-url: "https://portainer.example.com" ``` ## Network Modes ### DHCP (Default) ```yaml network: mode: dhcp ``` Uses BusyBox `udhcpc` on the first non-virtual interface. Optionally override DNS: ```yaml network: mode: dhcp dns: - 10.0.0.1 ``` ### Static IP ```yaml network: mode: static interface: eth0 address: 192.168.1.100/24 gateway: 192.168.1.1 dns: - 8.8.8.8 - 8.8.4.4 ``` Both `address` (CIDR) and `gateway` are required for static mode. ## Persistence After applying, cloud-init saves its configuration to the data partition: | File | Purpose | |------|---------| | `/mnt/data/network/interfaces.sh` | Shell script to restore network config on next boot | | `/mnt/data/etc-kubesolo/hostname` | Saved hostname | | `/etc/kubesolo/extra-flags` | KubeSolo CLI flags | | `/etc/kubesolo/config.yaml` | KubeSolo configuration | On subsequent boots, stage 50 (network) sources the saved `interfaces.sh` directly, skipping cloud-init parsing entirely. This is faster and doesn't require the cloud-init binary. ## CLI Usage The cloud-init binary supports three commands: ```bash # Apply configuration (run during boot by stage 45) kubesolo-cloudinit apply /path/to/cloud-init.yaml # Validate a config file kubesolo-cloudinit validate /path/to/cloud-init.yaml # Dump parsed config as JSON (for debugging) kubesolo-cloudinit dump /path/to/cloud-init.yaml ``` ## KubeSolo Configuration Reference All fields under the `kubesolo:` section and their corresponding CLI flags: | YAML Field | CLI Flag | Type | Default | Description | |---|---|---|---|---| | `extra-flags` | (raw flags) | string | `""` | Arbitrary extra flags passed to KubeSolo binary | | `local-storage` | `--local-storage` | bool | `true` | Enable local-path-provisioner for PVCs | | `local-storage-shared-path` | `--local-storage-shared-path` | string | `""` | Shared path for local-path-provisioner storage | | `apiserver-extra-sans` | `--apiserver-extra-sans` | list | `[]` | Extra SANs for API server TLS certificate | | `debug` | `--debug` | bool | `false` | Enable verbose debug logging | | `pprof-server` | `--pprof-server` | bool | `false` | Enable Go pprof profiling server | | `portainer-edge-id` | `--portainer-edge-id` | string | `""` | Portainer Edge Agent ID (from Portainer UI) | | `portainer-edge-key` | `--portainer-edge-key` | string | `""` | Portainer Edge Agent key (from Portainer UI) | | `portainer-edge-async` | `--portainer-edge-async` | bool | `false` | Enable async Portainer Edge communication | **Note:** The `portainer-edge-*` fields generate CLI flags for KubeSolo's built-in Edge Agent support. This is an alternative to the `portainer.edge-agent` section, which creates a standalone Kubernetes manifest. Use one approach or the other, not both. ## Examples See `cloud-init/examples/` for complete configuration examples: - `dhcp.yaml` — DHCP with defaults - `static-ip.yaml` — Static IP configuration - `portainer-edge.yaml` — Portainer Edge Agent integration - `airgapped.yaml` — Air-gapped deployment with pre-loaded images - `full-config.yaml` — All supported KubeSolo parameters ## Building The cloud-init binary is built as part of the normal build process: ```bash # Build just the cloud-init binary make build-cloudinit # Run cloud-init unit tests make test-cloudinit # Full build (includes cloud-init) make iso ``` The binary is compiled as a static Linux/amd64 binary (`CGO_ENABLED=0`) and is approximately 2.7 MB.