all writing

k3s: Kubernetes That Fits in a Homelab

k3s gives a homelab the same orchestration primitives as production Kubernetes, at a fraction of the hardware cost — the honest head-to-head.

Dark editorial cover: large corrugated shipping-container nodes in a hub-and-spoke network map, glowing electric lime-green rim-light and connecting lines converging on one bright central container against a true black void.

My git runner choked on a Friday night. I had a handful of AI agents building three or four separate apps in parallel, each one kicking off a build the moment it pushed, and the single runner pod fell behind and started queueing jobs like a barista during a rush it didn’t staff for.

The fix wasn’t a rebuild, a bigger box, or a support ticket. It was one line:

scale the runner
kubectl scale deployment/forgejo-runner --replicas=3

Three pods, same node pool, jobs draining within a minute. That’s the whole pitch for k3s in a homelab, distilled into one command: it’s not a toy version of Kubernetes, it’s the same orchestration primitives production clusters run on, sized for hardware you’d otherwise call “too small for this.”

Where I started

Before k3s, I ran Docker Swarm and, before that, plain docker compose up on VMs on Proxmox. Both are genuinely good for day-to-day container management — Swarm in particular has built-in DNS-based service discovery and load balancing that “just works” without any extra pieces. I iterate constantly — new app idea most weekends — and Swarm and bare Compose kept working for the boring, single-service cases. Where they ran out of road was the moment I wanted a rolling update that didn’t drop connections, a secret that wasn’t a plaintext file mounted into a container, or an ingress and service-discovery layer that didn’t need me to hand-wire it per app. k3s gave me all three as defaults, not add-ons.

The head-to-head

Here’s the honest comparison, engineering angle only — what each platform actually gives you versus what you have to bolt on yourself, going by the same four questions every time: rolling updates, secrets, ingress, and what it costs at idle. (The idle numbers below are pulled from third-party benchmarks, not vendor specs — treat them as directional, not exact.)

PlatformRolling updatesSecretsIngressIdle footprintLicense / cost
k3sNativeK8s Secrets API, GitOps-readyTraefik, bundled~450–500MBApache 2.0, free
Docker SwarmYes, no readiness gatingDocker secrets, no rotationDNS-based, built-in LBMinimal, no extrasApache 2.0, free
Proxmox + ComposeManualEnv vars / plaintextHand-wired per appBare Docker onlyAGPLv3, free (support optional)
TrueNAS SCALE AppsCompose-levelCompose env/secretsApp-template dependentAppliance-levelOpen source CE, free (paid Enterprise tier)
UnraidManual recreationPlaintext env varsNone built-inAppliance-levelProprietary — license required, from ~$49
kubeadm (vanilla k8s)NativeFull Secrets API, etcd-backedYour choice of controller≥2 cores / ≥2GB RAM minApache 2.0, free

A few of those rows are worth a second look on their own.

kubeadm is where the “fraction of the hardware cost” claim gets concrete. k3s ships as a single binary under 100MB. Its agent (worker) minimum is 1 core / 512MB RAM — k3s’s own server (control-plane) node wants the same 2 cores / 2GB RAM as kubeadm’s baseline, so the real saving shows up as you add workers: every extra k3s agent costs 512MB, every extra kubeadm node costs 2GB, and that’s before you’ve stood up an ingress controller, a CNI, or anything else k3s bundles for free. The other half of the gap is the datastore: standard Kubernetes runs on etcd, a distributed key-value store that wants its own resources and its own operational attention; k3s defaults to an embedded SQLite database with near-zero overhead. The catch is that SQLite only backs a single k3s server — there’s no HA control plane without switching to embedded etcd or an external database. That’s a real constraint, just not one to lose sleep over in a homelab: one server node is exactly what I run.

TrueNAS SCALE is the twist I didn’t expect. It actually ran k3s under the hood for its Apps feature for years — until the 24.10 “Electric Eel” release, when iXsystems ripped it out in favor of a native Docker engine, because the k3s-based system had become “cumbersome and complicated to manage” for their appliance users. That’s not a knock against k3s. It’s a difference in who the tool is for: an appliance optimized for point-and-click app installs doesn’t want rolling updates and a Secrets API, it wants one button that doesn’t break. A developer iterating on their own infrastructure wants exactly the opposite.

Nomad is the honest outlier. A bare Nomad agent idles around 60–80MB in third-party benchmarks — genuinely lighter than k3s’s bundled 450–500MB. But that’s the agent alone, with no ingress controller, no service mesh, no DNS, nothing k3s ships by default. The real comparison isn’t “80MB vs 500MB,” it’s “80MB plus whatever you bolt on” versus “500MB with half the pieces already in the box.” And the ecosystem argument tips it further: most self-hosted apps ship Helm charts or Kubernetes manifests; almost none ship Nomad job specs. It’s also not free-as-in-freedom the way the rest of this list is — HashiCorp relicensed Nomad under BSL 1.1 in 2023, source-available rather than OSI open source. Free to run in a homelab, just not Apache 2.0.

k0s is genuinely leaner than k3s, if you’re chasing the smallest possible footprint — benchmarked around 400–600MB at a steady 12% idle CPU against k3s’s ~20%. It’s plain vanilla Kubernetes with nothing extra bundled in, which is also its tradeoff: no Traefik, no opinionated defaults, more assembly required. Apache 2.0, same as k3s — no licensing catch here. If minimal resource use is the entire goal, k0s earns a look. If you want the biggest pile of tutorials and homelab-specific guides when something breaks at midnight, k3s wins on sheer ecosystem gravity.

The hardware this runs on

None of this is running on a rack of enterprise gear. The whole cluster lives on three secondhand small-form-factor PCs — Dell OptiPlex and Lenovo ThinkCentre Micro/Tiny boxes, corporate lease returns, upgraded with aftermarket RAM — for under R19,000 total. I wrote up the actual hunt for that hardware in Using AI to hunt homelab deals in South Africa. The point that matters here: this is genuinely modest hardware running a full GitOps-driven cluster — ArgoCD, Traefik with real TLS, ingress, ephemeral CI runners — and it does it comfortably. That’s the resource-cost argument from the table above, made physical.

The moment it clicked

The scaling story up top is the punchiest example, but the first time it actually clicked for me was smaller: pushing a commit to main and watching ArgoCD pick it up, diff it against the live cluster, and reconcile the change without me touching kubectl at all. Git as the source of truth, the cluster as a thing that converges toward it instead of a thing you imperatively poke — that’s a genuinely different way to think about infrastructure than docker compose up -d ever was.

The runner-scaling moment is the same idea under load. Multiple agents building separate apps at once isn’t a scenario I planned for, it’s just what happens when you let AI agents loose on a weekend. The infrastructure not caring — just bumping a replica count and moving on — is the actual payoff of everything in the table above.

The learning curve is real, and worth it

I won’t pretend this was free. kubectl, Helm charts, and Kubernetes’ own vocabulary — Deployments vs. StatefulSets vs. DaemonSets, what a Service actually routes to, why an Ingress needs a controller before it does anything — took real time to get comfortable with, more than Swarm or Compose ever asked of me. That tax is the honest tradeoff against everything above. I paid it once. Every weekend project since has been cheaper because of it.

k3s isn’t Kubernetes-lite in the sense of missing pieces. It’s the full toolset, sized for the hardware I can actually afford, and it gave me a homelab that behaves like production infrastructure instead of a pile of containers I have to babysit.

Jacques Bronkhorst
Principal engineer who ships across the stack — enterprise .NET by day, an over-engineered home lab by night. Writes it all down at jcqb.dev.
next up
Consistent AI-generated covers for a static blog