Skip to content
Go back

K3s vs K0s vs MicroK8s: Lightweight Kubernetes for Home Labs

By SumGuy 10 min read
K3s vs K0s vs MicroK8s: Lightweight Kubernetes for Home Labs

Full Upstream Kubernetes Is a Terrible Idea for Your Home Lab

Let me paint you a picture. It’s Saturday morning. You’ve got coffee, a freshly wiped NUC, and big dreams of “learning Kubernetes properly.” Six hours later you’re deep in etcd documentation, your cluster won’t form, and you’ve learned exactly one thing: kubeadm has opinions and those opinions are hostile.

Here’s the thing — full upstream Kubernetes was designed for people with dedicated ops teams and a budget line item for pain tolerance. If you’re running a home lab, a few Raspberry Pis, or an edge cluster at a remote site, you don’t need that. You need something that boots in under a minute, survives a VM reboot, and doesn’t require three control plane nodes just to avoid feeling guilty.

Enter the lightweight Kubernetes crew: K3s, K0s, and MicroK8s. All three are CNCF-conformant, production-capable, and designed to run on hardware that full Kubernetes would laugh at. But they make wildly different tradeoffs, and picking the wrong one wastes your weekend in a different way.

Let’s settle this.


The Contenders at a Glance

Before we get into the weeds, here’s the honest summary:

K3sK0sMicroK8s
MaintainerRancher/SUSEMirantisCanonical
InstallSingle binarySingle binarySnap package
Default CNIFlannelNone (bring your own)Calico
Default IngressTraefikNoneNone (addon)
Default LBServiceLB (klipper)NoneNone (addon)
Default storageLocal pathNoneHostpath provisioner
SQLite supportYes (single node)No (etcd/kine)No
ARM/Pi supportExcellentGoodGood
HA storyBuilt-in embedded DBetcd or kineBuilt-in HA addon

That table tells the story faster than a thousand words could. K3s comes with batteries. K0s comes with nothing but a very clean engine. MicroK8s comes with a snap and an addon system that’s either convenient or annoying depending on your Ubuntu feelings.


K3s: The One That Just Works

K3s is the Rancher/SUSE project that started as “Kubernetes but without the stuff we don’t need.” It strips out alpha features, cloud-provider plugins, and anything that exists purely for managed cloud environments. What you’re left with is a single binary under 70MB that ships with Flannel (CNI), Traefik (ingress), ServiceLB (layer 4 load balancer), local-path-provisioner (storage), and CoreDNS. You get a working cluster out of the box.

The killer feature is the install story:

Terminal window
curl -sfL https://get.k3s.io | sh -

That’s it. Thirty seconds later you have a single-node cluster. kubectl is already there. The kubeconfig is at /etc/rancher/k3s/k3s.yaml. You can do:

Terminal window
sudo kubectl get nodes

And you’ll see your node, Ready, no additional configuration. This is aggressively good UX for a Kubernetes distribution.

For HA, K3s uses an embedded distributed DB (etcd or SQLite in single-node mode) or an external DB via kine. To add a second server node, you grab a token from your first node and pass it to the install script:

Terminal window
# On your first server — grab the token
sudo cat /var/lib/rancher/k3s/server/node-token
# On each additional server node
curl -sfL https://get.k3s.io | K3S_URL=https://10.0.0.1:6443 \
K3S_TOKEN=<your-token> \
INSTALL_K3S_EXEC="server" sh -

Agent (worker) nodes follow the same pattern but without INSTALL_K3S_EXEC="server".

ARM support is first-class. K3s runs beautifully on Raspberry Pi 4 and newer. The only gotcha is enabling cgroups v2 on Raspberry Pi OS — add cgroup_memory=1 cgroup_enable=memory to /boot/cmdline.txt and reboot first. After that, the install script handles everything.

Upgrades are handled by the system-upgrade-controller — you apply a Plan CRD pointing at a target version and it drains, upgrades, and uncordons nodes for you. Honestly well thought out.

Who it’s for: Everyone who wants Kubernetes working in under five minutes and doesn’t want to make fifty decisions first.


K0s: The Puritan’s Choice

K0s from Mirantis takes a different philosophy. Zero dependencies, zero friction, zero compromises — hence the name. It’s also a single binary, but it ships with nothing pre-installed on the cluster side. No CNI. No ingress. No storage. Just the control plane and a worker, waiting for you to bring your own opinions.

The install is similarly clean:

Terminal window
# Download the binary
curl -sSLf https://get.k0s.sh | sudo sh
# Generate a default config
sudo k0s config create > k0s.yaml
# Install and start as a service
sudo k0s install controller -c k0s.yaml --single
sudo k0s start
# Check status
sudo k0s status

The --single flag creates a combined controller+worker node — useful for home lab single-node setups. For HA you’d run separate controller and worker nodes.

The config file is where K0s shines architecturally. It’s a single YAML that controls everything about your cluster:

k0s.yaml
apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
metadata:
name: k0s
spec:
network:
provider: kuberouter # or calico, custom
podCIDR: "10.244.0.0/16"
serviceCIDR: "10.96.0.0/12"
storage:
type: etcd # or kine (SQLite, MySQL, Postgres)
telemetry:
enabled: false

That provider: kuberouter is K0s’s built-in CNI option — kube-router, which is lightweight and does BGP if you’re into that. You can also set it to calico or custom (bring your own manifests).

No ingress means you install your own — Nginx, Traefik, whatever. No service LB means MetalLB or similar. No storage means OpenEBS, Longhorn, or whatever you fancy. This sounds painful but it’s actually kind of liberating if you already know what you want and don’t want K3s’s defaults getting in your way.

K0s generates and manages kubeconfigs directly:

Terminal window
sudo k0s kubeconfig admin > ~/.kube/config
kubectl get nodes

The upgrade story is clean — k0s stop, replace the binary, k0s start. Automated upgrades via the k0sctl tool work for multi-node clusters. ARM support exists and works, though the ecosystem around K0s is smaller than K3s so you’ll Google your way through more edge cases.

Who it’s for: Infrastructure folks who know exactly what components they want, don’t want surprises, and like building things themselves. Also good for embedding in products or appliances where you’re shipping K0s as an internal component.


MicroK8s: The Snap Skeptic Test

MicroK8s is Canonical’s entry. It’s been around the longest of the three, and it shows — both in terms of polish and in terms of some rough edges that feel like they predate modern expectations.

The defining characteristic is that it installs as a snap:

Terminal window
sudo snap install microk8s --classic
sudo usermod -aG microk8s $USER
sudo chown -R $USER ~/.kube
newgrp microk8s

If you have strong feelings about snap packages, this is where you either nod along or quietly close the tab. The snap isolation means MicroK8s has its own kubectl (invoked as microk8s kubectl or microk8s.kubectl), its own container runtime, its own everything — sandboxed away from the rest of your system. You can export a standard kubeconfig with microk8s config > ~/.kube/config.

The party trick is the addons system:

Terminal window
# Enable what you need
microk8s enable dns
microk8s enable ingress
microk8s enable storage
microk8s enable metallb:10.0.0.200-10.0.0.220
microk8s enable dashboard
# Check what's available
microk8s status

This is genuinely nice for newcomers. Want a dashboard? One command. Want MetalLB with a specific IP range? One command with an argument. The addons are curated and tested together, which reduces the “why won’t my CNI and ingress controller stop fighting” debugging sessions.

Under the hood, the default CNI is Calico (as of recent versions). DNS is CoreDNS. Ingress is the nginx ingress controller. HA is available via microk8s add-node — same token-passing pattern as K3s.

ARM support works — MicroK8s is probably the most commonly used Kubernetes on Ubuntu ARM due to the snap store making it trivially installable. The snap model does mean updates are automatic unless you pin a channel, which can surprise you with a minor version bump if you’re not paying attention.

Terminal window
# Pin to a specific channel to avoid surprise upgrades
sudo snap refresh microk8s --channel=1.30/stable

Upgrades otherwise just work through snap refresh, though major version jumps should be done deliberately.

Who it’s for: Ubuntu users who want the addon system, Canonical-supported environments, or folks who genuinely like the snap model. Also a solid choice if you’re training or demoing Kubernetes to people on Ubuntu machines.


Working Example: K3s Hello World

Since K3s is the recommendation for most home labs, let’s actually deploy something. Assuming you’ve run the one-liner install above:

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-hello
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx-hello
template:
metadata:
labels:
app: nginx-hello
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-hello
namespace: default
spec:
selector:
app: nginx-hello
ports:
- port: 80
targetPort: 80
type: LoadBalancer

Apply it:

Terminal window
sudo kubectl apply -f deployment.yaml
# Watch the pods come up
sudo kubectl get pods -w
# Once Running, check the service for an external IP
sudo kubectl get svc nginx-hello

ServiceLB (klipper) will assign the node’s IP as the external IP. Hit that in a browser and you’ll see the Nginx welcome page. This works on a bare VM with no cloud provider, no MetalLB config, nothing extra. That’s what K3s’s batteries-included approach buys you.


The Upgrade Stories, Honestly

K3s: Best-in-class for automation. The system-upgrade-controller is a proper Kubernetes operator that handles rolling upgrades across your cluster. You can set it and forget it, or trigger upgrades manually. Downgrades are not supported — but that’s true of all three.

K0s: Straightforward but more manual. k0sctl upgrade handles multi-node clusters. Single binary replacement works for single nodes. No magic — but also no surprises.

MicroK8s: Snap auto-updates are convenient until they aren’t. Pinning a channel (1.30/stable) is mandatory for anything you care about. Major version upgrades should be manual.


ARM and Raspberry Pi

All three work on ARM64. K3s has the most battle-tested ARM support and the largest home-lab Pi community — if something’s broken on Pi, someone’s already opened an issue and a workaround exists. K0s works but has a smaller community to Google against. MicroK8s works great if you’re on Ubuntu ARM (which is the sensible OS choice for Pi 4/5 anyway).

For Pi specifically: K3s single-node with Traefik disabled (if you’re bringing your own ingress) and local-path-provisioner for storage is a very common and stable setup. A 4GB Pi 4 can run a small production-ish workload without sweating.


Making the Call

Here’s your decision tree, simplified:

You just want Kubernetes to work in your home lab without thinking too hard: K3s. No contest. The defaults are sane, the community is massive, and you’ll be deploying apps within minutes of running the install script.

You want to choose every component yourself, or you’re embedding Kubernetes in a product/appliance: K0s. The single binary with zero pre-installed cluster components is ideal when you have specific requirements and don’t want to spend time removing K3s’s defaults. Also the right answer if you’re building something for other people to use.

You live in Ubuntu, use snap everywhere, and want the addon system: MicroK8s. If snaps don’t bother you and you want microk8s enable dashboard to just work, it’s a legitimately good experience. Also the path of least resistance for Ubuntu-based environments managed by Canonical tools (Landscape, MAAS, Juju).

The one thing all three have in common: they’re dramatically less painful than trying to run full upstream Kubernetes on the same hardware. Your Saturday morning self will appreciate the difference.

Pick one, spend thirty minutes getting a “hello world” pod running, and then go do something interesting with your cluster instead of fighting the infrastructure. That’s what lightweight Kubernetes distributions are for.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
ZFS Send/Receive Over WireGuard for Off-Site Replication
Next Post
Restic Repository Maintenance: Prune, Check, Forget

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts