Happy Dussehra! May good always win. Merry Christmas! Warm wishes from Vizag. Happy New Year! Here’s to a great year ahead.

DevOps · CNCF daily

k0s: A Zero-Friction Kubernetes Distribution in a Single Binary

CNCF Sandbox. A certified, upstream Kubernetes distribution shipped as one self-contained binary, with a controller that runs the control plane as supervised processes, an install tool for multi-node clusters, and built-in backup, upgrades and high availability.

23 min read

CNCF Sandbox

  • k0s
  • k0sctl
  • containerd
  • etcd
  • Konnectivity
  • Kubernetes
CNCF project page

k0s is an open-source Kubernetes distribution that arrives as one self-contained executable. The same binary embeds the Kubernetes components, installs itself as a system service, runs a controller or a worker, and ships tools for tokens, backup, restore and diagnostics. It needs nothing from the host beyond the kernel, which makes it easy to put on a small VM, a rack server, a gateway or a laptop, and to keep upgraded. It is certified and tracks upstream Kubernetes, so manifests, Helm charts and operators behave as they do on any other conformant cluster. Mirantis created k0s and is its main commercial sponsor, and the project joined the CNCF Sandbox on January 19, 2025. This brief explains k0s from the problem it solves to installing, configuring, operating and securing it, so one read is enough to decide whether it belongs in your platform.

CNCF daily · Sprint 5, post 1 of 14 · Certified Kubernetes - Distribution

At a glance

Category Platform › Certified Kubernetes - Distribution (as listed in the CNCF Landscape for comparable distributions; confirm on the project page)
CNCF status Sandbox. Accepted January 19, 2025. An incubation application has been submitted
Written in Go
License Open source; see the LICENSE file in the repository for the exact terms
Versioning Follows Kubernetes: 1.<minor>.<patch>+k0s.<n>. A new minor release roughly every four months, each maintained for about 14 months
Datastore k0s-managed etcd by default, or kine in front of SQLite, MySQL or PostgreSQL
Container runtime and network containerd with runc; kube-router by default, Calico or a custom CNI as options
Architectures x86_64, aarch64 and armv7l with CI coverage; riscv64 has no pre-built binaries
Minimum size (approx.) Controller 1 GB RAM and 1 vCPU; worker 0.5 GB RAM and 1 vCPU; controller and worker together 1 GB and 1 vCPU
Install curl -sSf https://get.k0s.sh | sudo sh for the binary; k0sctl for multi-node clusters

The problem k0s solves

A Kubernetes cluster is more than the API server. Someone has to choose and install a container runtime, a datastore, a network plugin and a certificate scheme, wire them together, and then upgrade all of them as the host operating system moves on a different schedule. On a cloud that is mostly handled for you. On bare metal, in a branch office, at an edge site, in a lab or inside an appliance, it is the real work, and a distribution that expects a package manager, a particular OS version or a pile of dependencies makes it worse.

k0s attacks that gap from the packaging side. Everything the cluster needs is in one binary that has no host dependencies apart from the kernel, so the same file runs on a wide range of Linux distributions (and, as an early option, Windows workers). Installing is a handful of commands, and tearing a node down with k0s reset removes what k0s put there. The project’s stated aim is to make a conformant cluster something you bootstrap in minutes rather than assemble. It deliberately bundles only a small set of add-ons, so you add the ones you want instead of removing the ones you do not.

Key concepts

Term Meaning
Controller A node that runs the control plane: API server, scheduler, controller manager, the datastore and the Konnectivity server.
Worker A node that runs pods: kubelet, containerd with runc, kube-proxy and the CNI.
Controller + worker One node with both roles, started with --enable-worker. --single is the shortcut for a one-node cluster.
Naked process How k0s runs control-plane components: as plain host processes that the k0s binary supervises, not as pods.
Konnectivity A reverse tunnel. Workers dial the controller and the controller uses that connection to reach kubelets (for logs, exec and webhooks), so workers do not need to be reachable from the control plane.
Join token A short-lived credential created on a controller that lets a new worker (or controller) join the cluster.
k0s.yaml The cluster configuration file (kind: ClusterConfig). Partial files are fine; missing values take defaults.
k0sctl A separate command-line tool that connects over SSH, installs k0s on a list of hosts and brings them into one cluster.
Kine A shim that lets the API server use SQL databases instead of etcd.
Autopilot k0s’s built-in controller for coordinated, in-cluster upgrades of controllers and workers.

Architecture

k0s architecture: an operator reaches a load balancer on port 6443; it forwards to a controller running kube-apiserver with etcd or kine and a Konnectivity server, all supervised by the k0s process; on each worker a node-local load balancer lets the kubelet reach the API server, a Konnectivity agent holds a reverse tunnel to the controller, containerd and runc run the pods, and kube-router provides the pod network.

The diagram shows one controller and one worker; a production cluster has three or five controllers and many workers. Purple is a k0s component, grey is an upstream component, green is your workload and blue is the operator. Open the zoomable diagram, or download it as SVG or PNG.

Component Responsibility
k0s controller process Installed as a system service. Starts and supervises kube-apiserver, kube-scheduler, kube-controller-manager, the datastore and the Konnectivity server as plain processes.
Datastore etcd managed by k0s, co-located on the controllers, or an external SQL database through kine. k0s cannot shrink an etcd cluster, so plan the controller count before you grow it.
Load balancer (HA) A TCP load balancer in front of the controllers on 6443 (Kubernetes API), 8132 (Konnectivity) and 9443 (controller join API).
Konnectivity server and agent The server runs on controllers, the agent on workers. Agents dial in, so workers can sit behind NAT. Defaults: agent port 8132, admin port 8133.
Node-local load balancing (optional) An Envoy proxy on each worker’s loopback (ports 7443 for the API and 7132 for Konnectivity) that spreads a worker’s calls across controllers without an external load balancer. Disabled by default.
Control plane load balancing (optional) A k0s-run virtual IP (IPVS) across controllers, for networks where you cannot provide a load balancer. Disabled by default.
Worker kubelet, containerd with runc, kube-proxy (iptables by default) and the CNI. kube-router is the default CNI.
Extensions Helm repositories and charts listed in k0s.yaml that k0s installs during bootstrap and keeps reconciled.

Design principle. Make the Kubernetes distribution a single, self-contained artifact and keep it neutral. k0s supervises the control plane itself instead of relying on the host or a runtime, bundles only what a cluster needs to start, and leaves ingress, storage, monitoring and policy to you.

From k0sctl apply to a Ready node

The second diagram follows a two-node cluster, one controller and one worker, from the first command to a node showing Ready.

k0s install flow in eight steps: the operator runs k0sctl apply; k0sctl connects over SSH to the controller host, installs and starts k0s as a controller, creates a join token, passes it over SSH to the worker host, installs the worker, which joins the controller on port 9443 and registers its kubelet as a node; the operator then uses the kubeconfig to see the node Ready.

  1. SSH. The operator runs k0sctl apply with a k0sctl.yaml; k0sctl connects to each host over SSH, checks the OS and prepares it.
  2. Install and start. k0sctl downloads k0s onto the controller host, writes the configuration and starts the k0s controller service.
  3. Create a token. Once the controller is initialised, k0sctl creates a worker join token on it.
  4. Token over SSH. k0sctl carries the token to the worker host.
  5. Install the worker. It installs k0s there as a worker using the token.
  6. Join. The worker contacts the controller (join API on 9443) and receives its cluster credentials.
  7. Register. The worker’s kubelet registers the node and the Konnectivity agent opens its tunnel.
  8. Check. The operator runs k0sctl kubeconfig, then kubectl get nodes shows the node Ready.

The phases k0sctl actually reports are: connect to hosts, detect the OS, prepare hosts, gather facts, download k0s, configure k0s, initialise the controller, install workers and disconnect. Open the zoomable flow diagram, or download it as SVG or PNG.

Install k0s

Check the host

Run k0s sysinfo after downloading the binary to test the host against k0s’s requirements. The system requirements page lists the approximate minimums above, recommends an SSD, asks that workers keep at least 15% disk space free, and says k0s uses roughly 0.5 GB on a controller, 1.3 GB on a worker and 1.7 GB on a combined node, before the OS and your applications. CI covers a long list of distributions, among them Ubuntu 20.04, 22.04 and 24.04, Debian 11 and 12, RHEL 8 and 9, Rocky Linux 8 and 9, Amazon Linux 2023, SUSE Linux Enterprise Server 15, Alpine, Flatcar and Fedora CoreOS. The page does not list kernel requirements itself; it points to the external runtime dependencies page, so check that page for your kernel.

One node, in four commands

This is the Quick Start path: one machine that is both controller and worker.

curl --proto '=https' --tlsv1.2 -sSf https://get.k0s.sh | sudo sh
sudo k0s install controller --single
sudo k0s start
sudo k0s kubectl get nodes

sudo k0s install controller --single --start combines the install and start. If you may want to add workers later, install with --enable-worker --no-taints instead of --single. Give the node a minute or two before expecting it to be ready for applications, and check the service with sudo k0s status. In an air-gapped environment, download the binary from the releases page instead of the script and follow the air-gap guide for images.

Add a worker by hand

On a controller, create a token. Then, on the new machine with the same binary installed, install the worker with it:

sudo k0s token create --role=worker --expiry=24h > worker.token
sudo k0s install worker --token-file worker.token
sudo k0s start

Move the token file to the worker securely and delete it afterwards. The manual multi-node guide covers the controller case and the ports to open.

A multi-node cluster with k0sctl

k0sctl is the recommended path for production, because it makes multi-node installs repeatable. It is a single binary, runs wherever Go does, and needs only SSH access to the hosts. k0sctl init > k0sctl.yaml writes a starter file. A small high-availability layout, with a load balancer you provide in front of three controllers, looks like this:

apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: demo
spec:
  hosts:
  - role: controller
    ssh: { address: 10.0.0.11, user: ubuntu, keyPath: ~/.ssh/id_ed25519 }
  - role: controller
    ssh: { address: 10.0.0.12, user: ubuntu, keyPath: ~/.ssh/id_ed25519 }
  - role: controller
    ssh: { address: 10.0.0.13, user: ubuntu, keyPath: ~/.ssh/id_ed25519 }
  - role: worker
    ssh: { address: 10.0.0.21, user: ubuntu, keyPath: ~/.ssh/id_ed25519 }
  - role: worker
    ssh: { address: 10.0.0.22, user: ubuntu, keyPath: ~/.ssh/id_ed25519 }
  k0s:
    version: <k0s version, for example the current 1.36.x+k0s.0 release>
    config:
      spec:
        api:
          externalAddress: k8s.example.internal
          sans:
          - k8s.example.internal
k0sctl apply --config k0sctl.yaml
k0sctl kubeconfig --config k0sctl.yaml > kubeconfig
kubectl --kubeconfig kubeconfig get nodes

The example addresses and host names are placeholders. Each entry in hosts has a role and an ssh block, and k0sctl manages only the hosts listed. The docs note two limits: k0sctl does not discover hosts, and it can add nodes to a cluster but cannot remove them. k0sctl also generates and shares the controllers’ certificates for you, which is the main reason to use it for HA.

Configuration reference

k0s.yaml uses apiVersion: k0s.k0sproject.io/v1beta1 and kind: ClusterConfig, with everything under spec. k0s config create writes a file full of defaults to start from; partial files are accepted. Pass it with --config at install time on each controller, or put it under spec.k0s.config in k0sctl.yaml.

Section What it sets Defaults worth knowing
api How components reach the API server port 6443, k0sApiPort 9443, CA lifetime 87600h (10 years), server certificates 8760h (1 year); externalAddress and sans for a load balancer
storage type: etcd or kine etcd with peerAddress; kine.dataSource takes the database URL; etcd.externalCluster for etcd you run yourself
network CNI and address ranges provider kuberouter (or calico, custom); podCIDR 10.244.0.0/16; serviceCIDR 10.96.0.0/12; clusterDomain cluster.local; kube-proxy mode iptables
network.nodeLocalLoadBalancing Envoy on each worker disabled; API on 7443, Konnectivity on 7132
network.controlPlaneLoadBalancing Virtual IP across controllers disabled
konnectivity Tunnel ports agent 8132, admin 8133
extensions.helm Charts installed at bootstrap concurrencyLevel 5 in the sample
images Per-component image overrides repository redirects every pull to one registry (air-gapped use); overriding an image does not disable its component
telemetry Anonymous usage reports enabled by default; set enabled: false to turn off

The pod and service ranges cannot be changed casually on a live cluster, so choose them before the first install and keep them clear of your node and site networks. If a site will use a different network plugin, set network.provider: custom and install your own CNI.

Helm charts from the configuration

k0s can install and reconcile Helm charts for you, which is useful for the first add-ons a cluster always needs (ingress, a metrics stack, a CNI addon). Add them under extensions.helm:

spec:
  extensions:
    helm:
      repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      charts:
      - name: cert-manager
        chartname: jetstack/cert-manager
        version: "<chart version>"
        namespace: cert-manager
        values: |
          crds:
            enabled: true

The chart, version and values here are an example of the shape; take the exact values from the chart’s own documentation. Charts can also come from OCI registries. Because the list lives in the cluster configuration, it fits the same Git workflow as the rest of k0s.yaml.

Features

  • Single binary, no host dependencies. One file, plus the kernel. Install, token, backup, restore, reset and a bundled kubectl are subcommands.
  • Certified upstream Kubernetes. Unmodified Kubernetes, with k0s version numbers that start with the Kubernetes minor.
  • Flexible control plane. Controller-only, worker-only, controller-and-worker and single-node roles. Controllers run as supervised processes, so they do not appear as pods and by default there is no kubelet on a controller.
  • Datastore choice. etcd, or kine with SQLite, MySQL or PostgreSQL. Single-node edge clusters can use SQLite and avoid running etcd.
  • Konnectivity tunnels. Workers behind NAT or a firewall only need outbound access to the controllers.
  • Built-in HA options. Node-local load balancing, a control-plane load balancer, or your own TCP load balancer.
  • Backup and restore. k0s backup captures the PKI, the datastore snapshot (etcd or kine), k0s.yaml, manifests, images and Helm configuration. It does not include PersistentVolumes, which you protect separately.
  • Upgrades. k0sctl can upgrade a cluster by applying a new version, and Autopilot gives a plan-driven, in-cluster alternative with update channels.
  • Windows workers. Available as an alpha capability since 1.34.
  • Other ways to run. Air-gapped installs, k0s in Docker, and the k0smotron companion project for running control planes as pods and managing hosted k0s clusters through Cluster API.
  • Runtime and network flexibility. Custom CNI, CRI and CSI are supported; k0s does not choose storage for you.

Production reference design

This design is a small production cluster of three controllers and three workers on VMs or servers in one site, using k0sctl from a bastion or CI runner.

  1. Plan the network. Reserve a stable DNS name and a TCP load balancer for the API. It must route 6443, 8132 and 9443 to every controller. HAProxy, nginx and cloud load balancers all work. Pick pod and service CIDRs that do not overlap anything routed to the site.
  2. Prepare the hosts. Install the OS, set time sync, open SSH for the k0sctl user, run k0s sysinfo once on each model of machine, and keep SSD storage for the controllers.
  3. Write k0sctl.yaml as in the example above, with three controllers, three workers, externalAddress set to the load balancer name and the k0s version pinned. Add extensions.helm for the first add-ons.
  4. Apply and verify. k0sctl apply, then fetch the kubeconfig and check nodes, system pods and k0s status on each controller. Take the first backup immediately and store it off the cluster.
  5. Rehearse failure. Stop one controller and confirm the API still answers through the load balancer; drain and rejoin a worker; restore a backup onto a spare machine to prove the procedure.
  6. Operate through Git. Keep k0sctl.yaml in Git, apply it from CI with the SSH key held as a secret, and roll upgrades one minor version at a time.

For high availability the docs recommend three or five controllers for etcd (an odd number), and note that a two-controller control plane is considered highly available even though it is not HA from etcd’s perspective. All controllers must share the same CA certificates and service-account key pair; k0sctl handles that automatically.

Security

  • Certificates and keys. The cluster CA and service-account keys live under /var/lib/k0s/pki on each controller. The CA lasts 10 years and server certificates 1 year by default, so plan certificate rotation and protect those files like any other root of trust. Controllers in an HA cluster must share them.
  • Join tokens. Create them with short expiries (--expiry=24h or less), transfer them over SSH, and never commit them to Git.
  • Fewer exposed components. Control-plane processes are supervised by k0s on the host rather than being pods, so there is no kubelet or container runtime on a controller by default to compromise.
  • Network exposure. Expose only 6443 to clients and 8132 and 9443 to the nodes. Workers connect outward to the controllers, so worker networks need no inbound path from the control plane for kubelet traffic.
  • Telemetry. Anonymous telemetry is on by default and reports every ten minutes; turn it off with spec.telemetry.enabled: false where policy requires it.
  • Images and supply chain. Use spec.images.repository to pull everything from your own registry and pin versions. The binary is downloaded from the project’s releases, so verify what you fetch in automated installs.
  • Host hardening. k0s does not harden the OS, apply Pod Security Standards or ship network policy by default; add those as you would on any cluster. kube-router handles NetworkPolicy in the default setup.

Monitoring and day-2 operations

Task How
Is a node healthy? sudo k0s status on the host; k0s kubectl get nodes on a controller.
Logs The services are k0scontroller and k0sworker; use journalctl -u k0scontroller (or k0sworker). Control-plane component logs are in the same journal because k0s supervises them.
Metrics Not bundled. Deploy a metrics stack through extensions.helm or any GitOps flow, as you would on any Kubernetes cluster.
Backup k0s backup on a controller; copy the archive off the node. PersistentVolumes need their own backup.
Restore k0s restore on a fresh controller before starting it. Rehearse this.
Upgrade Change the version in k0sctl.yaml and k0sctl apply, or use Autopilot plans. Upgrade controllers first, then workers, one minor at a time.
Add a worker Add a host to k0sctl.yaml and apply, or create a token and join by hand.
Remove a node Drain and delete it in Kubernetes, then run k0s reset on the host. k0sctl does not remove nodes for you.
Clean a host k0s reset stops k0s processes and containers, unmounts under the data directory and removes the service registration.
Symptom Check
Worker will not join Token expired or already used; port 9443 not reachable through the load balancer; externalAddress missing from the API certificate SANs
logs or exec fail on a worker The Konnectivity agent is not connected; check port 8132 on the controllers and the agent’s logs on the worker
API unavailable after a controller fails Load balancer health checks; etcd quorum (with three controllers, two must be up)
Pods cannot reach each other CNI mode and kube-proxy mode; pod CIDR overlaps with the host network

Usage cases

  • Edge and branch sites. Small clusters on a few mini-PCs or one server, where installation must be a few commands and upgrades must not need an expert on site.
  • Single-node developer and CI clusters. k0s install controller --single gives a throwaway conformant cluster; the k0s maintainers use k0s to host their own CI runners.
  • Bare-metal and on-premises clusters. Multi-node clusters from k0sctl on servers with no managed Kubernetes available.
  • Embedded clusters in products. Vendors ship k0s inside their installers so that customers get a Kubernetes cluster as part of an appliance or software package.
  • Hosted control planes. With the k0smotron companion project, run k0s control planes as pods in a management cluster and attach workers from anywhere.
  • In the Sprint 5 project. The final project of this sprint, a cold-chain logistics monitoring platform on AWS, uses k0s as lightweight Kubernetes for depot and vehicle gateways.

Operational considerations

  • Two components, two releases. k0s and k0sctl are separate projects with separate versions. Pin both and upgrade them deliberately.
  • Controller count is hard to undo. The docs say k0s cannot shrink an etcd cluster, so start with one, three or five controllers on purpose.
  • No kubelet on controllers. Control-plane processes are not pods, so you will not see them in kubectl get pods. Monitor them through the host service and the API server’s own metrics. Add --enable-worker only when you want workloads on a controller.
  • Version follow-through. The project follows Kubernetes’ cadence, with a new minor roughly every four months and about 14 months of maintenance each. Older minors reach end of life quickly, as the project noted for 1.30 and 1.31, so budget for regular upgrades.
  • Docs versions. The documentation has head, main and stable trees. Use the one that matches your installed version, because defaults and features change.
  • Windows is early. Windows workers are alpha, and riscv64 has no pre-built binaries.
  • Backups are not volumes. Backup covers cluster state, not PersistentVolume data.
  • Telemetry default. It is on until you turn it off.

Adoption

The project keeps an official Adopters list, and these are the entries on it that describe production use:

  • Mirantis provides commercial support for k0s, and k0s is included in a number of Mirantis products such as MKE.
  • Replicated builds its Embedded Cluster project on top of k0s, and Progress Chef 360 uses it for embedded Kubernetes clusters.
  • k0smotron manages hosted k0s clusters and offers a full Cluster API provider for k0s.
  • AudioCodes uses it for its VoIP and voice-AI products, and DeepSquare for high-performance computing as a service.
  • Defense Unicorns uses it as a lightweight Kubernetes for mission-critical environments, and KubeArmor lists support for it in its security product.
  • The k0s maintainers run their build and CI infrastructure on it, mainly dynamic GitHub runners.
  • The list also includes a research use for NVIDIA GPU data analysis at the National Astronomical Observatory of Japan, and community write-ups such as a New England Research Cloud option and a Tokyo smart-cities project.

Treat the list as self-reported. It tells you that k0s runs in many settings, from embedded products to HPC, not how large any given deployment is.

Alternatives

Solution Model Best suited to
K3s Lightweight Kubernetes distribution with bundled add-ons such as an ingress controller and a service load balancer; see the K3s brief Teams who want a batteries-included small cluster and a large community
kubeadm Upstream bootstrap tool; you provide runtime, network and OS packaging Teams who want to assemble and manage every part themselves
MicroK8s Snap-packaged Kubernetes with add-ons you enable Ubuntu-centric developer and edge use
Talos Linux An immutable, API-managed OS built around Kubernetes Teams ready to adopt a Kubernetes-specific OS
KubeEdge Cloud-managed edge nodes and device management; see the KubeEdge brief Edge fleets controlled from a central cluster rather than independent clusters
Managed Kubernetes (EKS, AKS, GKE) The provider runs the control plane Cloud workloads where nobody should operate a control plane

Strengths and limitations

Strengths Limitations
One binary with no host dependencies, so installs and upgrades are simple Sandbox-stage project with Mirantis as the dominant maintainer; check the contributor mix before betting on it
Certified, upstream Kubernetes, so workloads are portable Few add-ons are bundled; ingress, storage and monitoring are yours to choose
Konnectivity tunnels and optional node-local load balancing suit awkward networks etcd clusters cannot be shrunk, and k0sctl cannot remove nodes
k0sctl makes multi-node and HA installs repeatable; backup and restore are built in Backup excludes PersistentVolumes; k0sctl is a separate tool to version
Small footprint, from 1 GB RAM for a controller Fast release cadence needs regular upgrades; Windows workers are alpha
Flexible datastore, CNI and runtime choices The documentation is split across several version trees

Project status and roadmap

k0s was accepted into the CNCF Sandbox on January 19, 2025 and has submitted an incubation application. CNCF’s 2025 review reports 39 stable releases in that year and a roadmap that targeted v1.35 for February 2026. Patch releases on the 1.34, 1.35 and 1.36 lines and a 1.37 alpha were visible on the project’s releases when this brief was written, so check the releases page for the latest version before you pin one. The project holds community calls and office hours, and is promoting a governance and contributor expansion as part of its CNCF journey. Mirantis sells commercial support for k0s, including prioritised support and verified extensions, and a LabCare to ProdCare range of subscriptions.

Recommendation

Trial. k0s earns a place on the shortlist when you need many small or awkwardly networked clusters, or a Kubernetes you can embed in a product or install on bare metal with very little ceremony. Start with a single-node install on a spare VM, then build a three-controller, two-worker cluster with k0sctl behind a TCP load balancer, and rehearse a controller failure, an upgrade and a backup restore before relying on it. Compare it with K3s on the points that matter to you, which are bundled add-ons, the datastore options and how you want to upgrade. If your workloads run in a cloud account that already has a managed Kubernetes service, that service is usually the simpler choice.

References: CNCF project page · k0s documentation · Quick Start · System requirements · Configuration · Install with k0sctl · High availability · Architecture · Release and support model · Adopters · k0s repository · k0s in 2025 (CNCF blog) · k0s joins the CNCF Sandbox (Mirantis) · CNCF Landscape

Spotted something wrong or out of date?Suggest a correction. I review every suggestion before changing the page.