# K3s: a distribution rather than a fork, with sqlite3 by default and a privileged compose file

> K3s is a conformant Kubernetes distribution packaged as a single binary under 100 MB, with sqlite3 as the default datastore and eleven components bundled in. The README argues at length that it is not a fork, the go.mod pins a dozen upstream projects to k3s forks, and the compose file it ships runs privileged and drops a mode 666 kubeconfig next to you.

**k3s-io/k3s** — Lightweight Kubernetes

- Repository: https://github.com/k3s-io/k3s
- Website: https://k3s.io
- Stars: 34,093 · Forks: 2,745
- Language: Go
- License: Apache-2.0
- Published: 2026-08-17 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/k3s-io-k3s

## The name is half of k8s, and there is no long form to search for

The project explains its own name. The goal was an installation of Kubernetes that was half the size in terms of memory footprint. Kubernetes is a 10 letter word stylised as k8s, so something half as big would be a 5 letter word stylised as K3s. A 3 is also an 8 cut in half vertically.

Then the sentence that saves people a search: there is neither a long-form of K3s nor an official pronunciation.

That is a small thing with a practical edge. Nothing expands to Kubernetes Lightweight or anything similar, so documentation, error messages and configuration keys are all just k3s, and the documentation lives at docs.k3s.io with quick start, architecture and FAQ pages linked from the README. If you are scanning a log for the word, you will be looking for the lowercase name, not a product name that spells itself out.

The one thing the name does not tell you is the scope. Lightweight here means one binary and a smaller memory footprint, both of which the README is specific about.

## It says it is a distribution, and go.mod is where the divergence sits

The README spends a section on the fork question, and the answer is no. A fork implies continued divergence from the original, which is described as neither the goal nor the practice. The stated intent is not to change any core Kubernetes functionality, to stay as close to upstream as possible, and to keep a small set of patches, well under 1000 lines, for the K3s use case and deployment model, contributing them back upstream where possible, with SELinux support in containerd given as the example.

Read the module file next to that claim. go.mod declares go 1.26.8 and then a long replace block pointing a dozen projects at k3s forks: cri-dockerd, kube-router, containerd and its API and imgcrypt, cadvisor, etcd's API and client, spegel, hcsshim, cilium's ebpf, selinux, plus pinned versions of runc, cobra, viper and the Docker libraries.

So the small patch set is real for the k3s repository itself, while the wider dependency graph is deliberately held on forks. That is a normal distribution practice, and it is also the thing to plan for: an upgrade depends on those forks being rebuilt and published, so read the release notes for the components you depend on rather than assuming an upstream version arrived.

## Exactly two things are removed, and both have out-of-tree replacements

The section on removals opens by acknowledging it is a common point of confusion because it has changed over time, since early versions of K3s removed much more. Two things are removed now: in-tree storage drivers, and the in-tree cloud provider.

Both have out-of-tree alternatives in the form of CSI for storage and a cloud controller manager for the provider, and both work in K3s, with upstream moving towards them. The justification is given twice: removing them shrinks the binary, and it is possible to remove them while remaining conformant because neither affects core Kubernetes functionality. The third reason is the one that bites in practice: they depend on third-party cloud or data centre technologies and services, which may not be available in many K3s use cases.

So the trade is explicit. On a bare metal or edge cluster with no cloud provider in the picture, removing the in-tree provider costs nothing. On a cloud where the control plane expects it, or where your volumes depend on a specific in-tree driver, you now owe a CSI driver and a cloud controller manager, and you have to supply them yourself.

## Eleven components come pre-selected, and each one can be swapped out

The distribution argument rests on bundling opinionated choices, and the README names all of them. Containerd and runc for the runtime, Flannel for CNI, CoreDNS, Metrics Server, Traefik for ingress, Klipper-lb as an embedded service load balancer provider, Kube-router as the netpol controller for network policy, Helm-controller so Helm manifests can be deployed through CRDs, Kine as a datastore shim that lets etcd be replaced with another database, Local-path-provisioner for local storage volumes, and host utilities from a separate k3s-root project covering iptables or nftables, ebtables, ethtool and socat.

One sentence covers what you are allowed to do about all of that: these technologies can be disabled or swapped out for technologies of your choice.

That is the single most useful line in the file for an adopter, and it cuts both ways. It means you are not locked into Traefik or Local-path-provisioner, so an existing ingress controller or a CSI driver with a real storage backend can take their place. It also means the defaults you get are not neutral, and a cluster that already has opinions about DNS, ingress or storage has work to do before the first workload lands.

## sqlite3 is the default datastore, with Kine as the shim behind it

The storage decision is made for you unless you change it. K3s adds support for sqlite3 as the default storage backend, and etcd3, MariaDB, MySQL and Postgres are also supported. Kine is the datastore shim that allows etcd to be replaced with other databases, which is the mechanism behind sqlite3 as well as the external engines. Separately, K3s maintains the management of an embedded etcd cluster.

The README does not publish a decision rule for choosing between them, so the choice is yours to reason about rather than something the project settles for you. The same section also lists what K3s maintains for you: the TLS certificates of Kubernetes components, the connection between worker and server nodes, and the auto-deployment of Kubernetes resources from local manifests in real time as they are changed.

That last one is worth a second look in a GitOps setup. If something else is already reconciling your manifests, having the cluster do it as well is not a free feature, and the README does not document a flag for turning that behaviour off.

## Workers need no kubelet port, because the API arrives over a websocket

One of the six stated changes is about attack surface rather than convenience. K3s eliminates the need to expose a port on Kubernetes worker nodes for the kubelet API, by exposing that API to the control plane nodes over a websocket tunnel instead.

The effect is that a worker node has one fewer listening port, and the port it would have exposed, a kubelet port reachable from anywhere that can route to the node, is gone. For a cluster spread across sites or a home connection, that is a meaningful difference in what you have to firewall.

The remaining two changes in the list are about defaults and dependencies. K3s describes itself as secure by default with reasonable defaults for lightweight environments, and as having minimal to no OS dependencies, needing just a sane kernel and cgroup mounts. Both are claims about the packaged experience rather than about the configuration surface: a cluster still has whatever hardening you did not add, and a single binary does not mean a single decision.

## The shipped compose file is privileged, publishes 6443, and writes a 666 kubeconfig

The compose file in the repository is the quickest way to see the intended shape, and it is a development shape. The server service is privileged, restarts always, and publishes three ports:

```yaml
    ports:
    - 6443:6443  # Kubernetes API Server
    - 80:80      # Ingress controller port 80
    - 443:443    # Ingress controller port 443
```

The kubeconfig handling deserves a closer look. K3S_KUBECONFIG_OUTPUT points at /output/kubeconfig.yaml, and the host directory is mounted into the container, with a comment saying it is just so that the kubeconfig file gets out. The mode is set to 666, which means anyone on the host can read and rewrite the credentials that grant full access to the cluster. Add the published API port and a required K3S_TOKEN, and this file is fine for a laptop and wrong for a shared machine.

The agent service is simpler and points at the server with K3S_URL over https, sharing the token. Both services mount tmpfs on /run and /var/run, raise the nproc and nofile ulimits to 65535, and keep their data in named volumes at /var/lib/rancher/k3s. The run command in the file's own comment sets a token and starts it.

## Building a Go project still goes through docker buildx, and a script polices the size

The Makefile is worth a look even if you never build it, because it states the supported platforms. The multiarch-binary target builds for linux/amd64, linux/arm64, linux/arm/v7, linux/riscv64 and windows/amd64. That list is the answer to what a K3s binary can be.

The build itself is a docker buildx invocation against the Dockerfile with a target of result, and the source of the version is a git_version.sh script. The default goal is ci, deps runs go mod tidy, format runs gofmt -s and goimports over the found Go files, and validate builds the Dockerfile's validate target.

Two targets enforce the project's own claims. binary-size-check runs a script named binary_size_check.sh, which is how the under 100 MB statement stays true across releases, and image-scan runs an image scan script. So even though this is a Go module with a normal go.mod, a source build wants Docker and buildx present, and the size promise is a gate rather than an aspiration.

Around the Makefile the repository carries the administrative files a project of this size accumulates: GOVERNANCE.md, MAINTAINERS, CODEOWNERS, a DCO, a ROADMAP.md, ADOPTERS.md, BUILDING.md, channel.yaml for release channels, install.sh with its sha256sum file, and systemd units for both a normal and a rootless service.

## Conclusion

K3s fits edge, IoT, CI, ARM and development clusters, where one binary and half the memory of upstream Kubernetes are worth more than the components you would have to assemble. It does not fit a cluster that depends on an in-tree storage driver or the in-tree cloud provider, since both are removed, and it is not a place to assume upstream component versions, since go.mod replaces a dozen projects with k3s forks. Before you deploy: read docker-compose.yml before running it, because privileged plus a 6443 host port plus K3S_KUBECONFIG_MODE 666 is a development shape; pick a datastore deliberately rather than accepting sqlite3 because it is the default; and check the release channel you are on, since v1.37.1+k3s1 was published 2026-09-30 alongside an rc2 of the same version.

## FAQ

### What does K3s stand for?

The project explains the name as a derivation rather than an abbreviation. The aim was half the memory footprint of Kubernetes, and since Kubernetes is a 10 letter word written as k8s, something half as big would be a 5 letter word written as K3s, with a 3 being an 8 cut in half vertically. There is no long form of K3s and no official pronunciation.

### Is K3s the same as Kubernetes?

It is a fully conformant, production-ready Kubernetes distribution rather than a fork, and the README says so explicitly: the intent is not to change core Kubernetes functionality and to stay as close to upstream as possible. What it adds is packaging, since eleven components including Traefik, Flannel, Kine and Local-path-provisioner are bundled, and what it removes is limited to in-tree storage drivers and the in-tree cloud provider.

### What is the current version of K3s?

The most recent release listed is v1.37.1+k3s1, published on 2026-09-30, alongside v1.37.1-rc2+k3s1 and v1.36.5-rc2+k3s1 from 2026-09-24. The repository carries a channel.yaml file, which is where release channels are described.

### Should I install K3s as root?

The repository ships two systemd units, k3s.service and k3s-rootless.service, so both shapes are accounted for. The published compose file takes a different route: the server and agent services are marked privileged: true, and the file writes the cluster credentials to a kubeconfig with mode 666 so anyone on the host can read them. The README does not document a non-root installation path beyond those files.

## Sources

- [Official documentation](https://k3s.io)
- [Official README](https://github.com/k3s-io/k3s#readme)
- [Project repository](https://github.com/k3s-io/k3s)
- [Release notes](https://github.com/k3s-io/k3s/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/k3s-io-k3s
