Ways to install
KubeSolo is a single Linux binary. There are three ways to put it on a machine:
| Method | Runs on | Use when |
|---|---|---|
| Install script | Linux | The quickest path for a Linux host. One curl command detects the architecture, libc and init system, then installs and starts KubeSolo as a service. |
| kubesoloctl | Linux, macOS, Windows (WSL2) | You want install, upgrade, reset and uninstall from one CLI, or you want to run KubeSolo in a container for development and CI on macOS or WSL2. |
| Release archive | Linux | Custom images (Yocto, Buildroot) or init systems the script does not know. Download kubesolo-<version>-linux-<arch>.tar.gz from GitHub releases and run the binary yourself. |
Supported architectures are x86_64 (amd64), aarch64 (arm64), armv7l (arm) and riscv64. Every architecture is published for both glibc and musl, as an online and an offline build. Check the host first with the requirements in the quick start.
Install channels
Two URLs serve the install script. Flags work the same way on both.
| URL | Serves | Intended use |
|---|---|---|
| https://get.kubesolo.io | The script from the latest stable release | Production installs |
| https://get-dev.kubesolo.io | The script from the develop branch | Testing unreleased changes |
get-dev.kubesolo.io can install pre-release behaviour or defaults that differ from the stable release.Running the install script
The script must run as root. Pipe it to sh through sudo:
To pass flags through a pipe, use sh -s --. -s makes the shell read the script from stdin, and everything after -- goes to the script instead of to sh:
Every option also has an environment variable. sudo drops the caller's environment, so use sudo -E when you set them in front of the command:
With a downloaded copy of the script, pass flags as usual: sudo sh install.sh --version=v1.2.1.
What the script does
- Detects the architecture, glibc or musl, the init system and whether it is running in a container.
- Runs pre-flight checks. It stops if Docker is installed or running, if the hostname is not lowercase RFC 1123, if
iptablesor itsxt_commentmodule is missing, if thecpuset,cpu,io,memoryorpidscgroup controllers are missing, or (on Alpine) ifnftis missing. - Stops any running KubeSolo and frees its ports (2379, 6443, 10443, 6060), killing only processes whose executable is
/usr/local/bin/kubesolo. - Downloads
kubesolo-<version>-linux-<arch>[-musl][-offline].tar.gzfrom GitHub releases and installs the binary to/usr/local/bin/kubesolo. - Writes your settings to
/etc/kubesolo/config.yaml(mode0600). The installed binary produces the file itself with--print-config, so the service command line is justkubesolo --config=/etc/kubesolo/config.yaml. - Creates and starts a service for the detected init system.
- If
kubectlis on the node, waits for the admin kubeconfig and merges it into~/.kube/configfor the user who ransudo, backing up the existing file first.
Online and offline builds
Every release ships two variants of the binary:
| Variant | Archive suffix | Internet at runtime | Use when |
|---|---|---|---|
| Online (default) | none | Yes. CoreDNS and the pause image are embedded; the local-path provisioner, Portainer agent and d2k images are pulled from registries when KubeSolo deploys them. | The device has reliable internet access and a smaller download matters more. |
| Offline | -offline | No. Those images are embedded in the binary as well, alongside the runtime and CNI plugins. The exception is a custom Portainer agent image, which is always pulled from its registry. | Air-gapped sites, factory floors, devices with intermittent or no connectivity. |
To install the offline build on a connected machine, add --offline (or set KUBESOLO_OFFLINE=true):
Your own workload images still come from a registry. For air-gapped workloads, point containerd at an internal registry. See registry mirrors.
Pinning a version
The script installs the release it was published with unless you pass --version. Pin the version in automation so every device gets the same build:
Versions are release tags such as v1.2.1, as listed on the releases page. Running the script again with a newer --version upgrades in place. See Upgrading.
Installer flags
The script accepts these options. Boolean options take an explicit value (--debug=true), except --offline and --install-prereqs, which take none.
| Flag | Env var | Default | Description |
|---|---|---|---|
| --version=VERSION | KUBESOLO_VERSION | v1.2.1 | Release to install. |
| --path=PATH | KUBESOLO_PATH | /var/lib/kubesolo | Data directory for certificates, the database and container state. Cannot be changed after install. |
| --apiserver-extra-sans=LIST | KUBESOLO_APISERVER_EXTRA_SANS | (none) | Comma-separated extra IPs or DNS names for the API server certificate. |
| --portainer-edge-id=ID | KUBESOLO_PORTAINER_EDGE_ID | (none) | Portainer Edge ID. See Portainer. |
| --portainer-edge-key=KEY | KUBESOLO_PORTAINER_EDGE_KEY | (none) | Portainer Edge key. Prefer the environment variable; the key contains special characters. |
| --portainer-edge-async=true|false | KUBESOLO_PORTAINER_EDGE_ASYNC | false | Edge async mode. |
| --portainer-edge-image=IMAGE | KUBESOLO_PORTAINER_EDGE_IMAGE | docker.io/portainer/agent:lts | Edge Agent image, including the tag. |
| --local-storage=true|false | KUBESOLO_LOCAL_STORAGE | true | local-path storage provisioner. |
| --d2k=true|false | KUBESOLO_D2K | false | Docker-compatible API on port 2376. See d2k. |
| --d2k-namespace=NS | KUBESOLO_D2K_NAMESPACE | d2k | Namespace d2k deploys into and translates against. |
| --debug=true|false | KUBESOLO_DEBUG | false | Debug logging. |
| --pprof-server=true|false | KUBESOLO_PPROF_SERVER | false | Go pprof server on port 6060. |
| --cpu-manager-policy=POLICY | KUBESOLO_CPU_MANAGER_POLICY | none | none or static. See CPU pinning. |
| --cpu-manager-policy-options=OPTS | KUBESOLO_CPU_MANAGER_POLICY_OPTIONS | (none) | Comma-separated key=value options for the static policy. |
| --reserved-cpus=CPUSET | KUBESOLO_RESERVED_CPUS | 0 under static | CPUs held back for the host, such as 0 or 0-1. |
| --system-reserved=LIST | KUBESOLO_SYSTEM_RESERVED | (none) | Resources withheld from allocatable, such as cpu=1,memory=500Mi. |
| --run-mode=MODE | KUBESOLO_RUN_MODE | service | service, daemon or foreground. See init systems. |
| --proxy=URL | KUBESOLO_PROXY | (none) | HTTP/HTTPS proxy for the service. See proxy. |
| --offline | KUBESOLO_OFFLINE | false | Download the offline build. |
| --offline-install=PATH | KUBESOLO_OFFLINE_INSTALL | (none) | Install from a local .tar.gz, .tgz, .zip or raw binary instead of downloading. |
| --download-only[=DIR] | KUBESOLO_DOWNLOAD_DIR | . | Download the archive and the install script, then exit. Needs no root. |
| --install-prereqs | KUBESOLO_INSTALL_PREREQS | false | On Alpine, install nftables and enable the cgroups service when they are missing. |
| --help | Print the options and the detected defaults. | ||
| — | KUBESOLO_LOAD_BALANCER | true | Built-in LoadBalancer EXTERNAL-IP. Environment variable only. |
| — | KUBESOLO_LOCAL_STORAGE_SHARED_PATH | (none) | Shared filesystem for local-path volumes. Environment variable only. |
| — | KUBESOLO_DB_WAL_REPAIR | false | Repair the SQLite WAL after power loss. Environment variable only. |
| — | KUBESOLO_DISABLE_IPV6 | false | Disable IPv6. Environment variable only. |
| — | KUBESOLO_STARTUP_TIMEOUT | 600 | Seconds each component may take to become healthy. Environment variable only. |
--mtu=1400 does nothing. Set those as KUBESOLO_* environment variables with sudo -E, or change them after install. See Changing settings after install.This works because the installer generates /etc/kubesolo/config.yaml by running the installed binary with --print-config, and the binary reads every recognised KUBESOLO_* variable. The variable names are listed in the settings table.
Changing settings after install
From v1.2.1 the installer records every setting in /etc/kubesolo/config.yaml, and the service reads that file at startup. To change a setting later, edit the file instead of reinstalling, then restart KubeSolo:
Running the script again starts from the existing file and applies only the flags you pass, so settings you changed in the file survive a re-run. The configuration reference lists every setting, its flag and its environment variable.
--path, defaulting to /var/lib/kubesolo, and that overrides the path recorded in config.yaml. If the node uses another directory, pass --path again on every reinstall or upgrade, or KubeSolo starts against an empty /var/lib/kubesolo.Air-gapped installation
An air-gapped node needs the offline build, because the online build pulls system images at startup.
With the install script
On a connected Linux machine with the same architecture and libc as the target, download the offline archive and a copy of the script. --download-only needs no root and runs no pre-flight checks, so the machine can have Docker installed:
Copy the directory to the target, then install from the archive:
Pass the archive the download saved. Its name follows the detected platform: kubesolo-<version>-linux-<arch>[-musl]-offline.tar.gz, for example kubesolo-v1.2.1-linux-amd64-offline.tar.gz. The bundle is built for the OS, architecture and libc of the downloading machine, so a bundle fetched on macOS or on a glibc host for an Alpine target won't work. If the target has a different architecture or libc than the machine you download on, fetch the matching archive directly from the release instead, for example:
With kubesoloctl
kubesoloctl download builds a bundle for another architecture with --arch (amd64, arm64, arm, riscv64, each with an optional -musl suffix):
kubesoloctl download fetches the online archive. For a node with no registry access at all, download the -offline archive from the release and pass that to --offline-install.Workload images are separate from the system images. Mirror them to an internal registry and use a catch-all _default mirror so that every pull goes there.
Init systems and run modes
With the default --run-mode=service, the script detects the init system in this order and writes the matching service definition:
| Init system | Service definition | Status and logs |
|---|---|---|
| systemd | /etc/systemd/system/kubesolo.service | systemctl status kubesolo, journalctl -u kubesolo -f |
| upstart | /etc/init/kubesolo.conf | initctl status kubesolo |
| OpenRC | /etc/init.d/kubesolo | rc-service kubesolo status, /var/log/messages |
| s6 | /etc/s6/sv/kubesolo/run | s6-svstat /etc/s6/sv/kubesolo |
| runit | /etc/runit/sv/kubesolo/run | sv status kubesolo |
| SysV init | /etc/init.d/kubesolo | service kubesolo status, /var/log/syslog |
| none detected | Falls back to daemon mode | /var/log/kubesolo.log |
Two other run modes skip the init system entirely:
--run-mode=daemonstarts KubeSolo in the background withnohup, writing its PID to/var/run/kubesolo.pidand logs to/var/log/kubesolo.log.--run-mode=foregroundruns KubeSolo in the current terminal, for debugging.
For an image you build yourself, such as Yocto or Buildroot, install the binary from the release archive and start it from your own init script with /usr/local/bin/kubesolo --config=/etc/kubesolo/config.yaml.
Alpine Linux and musl
The script detects musl from /lib/ld-musl-*.so.1 and downloads the static -musl build, so Alpine and other musl distributions need no extra libraries. Alpine needs three things that other distributions usually already have:
iptables, for the installer's pre-flight check;nftables, because kube-proxy runs in nftables mode on Alpine;- the OpenRC
cgroupsservice, so the cgroup v2 controllers are available.
Run it as root, since Alpine does not ship sudo by default. --install-prereqs installs nftables if it is missing and runs rc-update add cgroups boot and rc-service cgroups start. KubeSolo itself is registered as an OpenRC service.
Behind a proxy
--proxy writes HTTP_PROXY and HTTPS_PROXY into the service environment for every init system and run mode, and sets NO_PROXY=localhost,127.0.0.1. The installer's own downloads follow your shell's proxy settings as usual.
Upgrading
Run the installer again with the new version. It stops KubeSolo, replaces the binary and restarts the service. The data directory and /etc/kubesolo/config.yaml are kept.
Or use kubesoloctl, which also moves a flag-based service definition from an older release into the configuration file:
Uninstalling
The hosted uninstall script stops KubeSolo, removes the service definition, binary, CNI configuration and /etc/kubesolo/config.yaml, and leaves the data directory in place:
For the options, download the script from the release and run it locally. --remove-data asks for confirmation, so it needs a terminal rather than a pipe:
| Option | Effect |
|---|---|
| --path=PATH | Data directory to act on. Defaults to /var/lib/kubesolo. |
| --remove-data | Also delete the data directory, after a confirmation prompt. Deletes all cluster state. |
| --remove-kubeconfig | Remove the KubeSolo context from ~/.kube/config. |
| --keep-config | Leave /etc/kubesolo/config.yaml in place so a reinstall reuses it. |
With kubesoloctl, which works for both host installs and container mode: