On this page
In the overview post I argued that most homelabs don’t need Kubernetes — and I meant it. So this guide starts with the honest question of whether you should, and only then shows you how. The how is genuinely one command; the whether is where the real decision lives.
This guide uses placeholders. Swap them for yours before you paste:
10.0.0.30— the IP of your k3s server node.YOUR_NODE_TOKEN— the join token you’ll read off the server in Task 4.
Rule of thumb: if a value looks specific to one machine, it’s a placeholder to change — not a literal to copy.
When it’s worth it — and when it isn’t
Before you install anything, sit honestly in one of these two columns:
- Reach for Docker Compose instead if you run your services on one machine and it’s working. Compose is simpler, easier to reason about, and there’s no shame in it powering a great homelab for years.
- Reach for Kubernetes if you want self-healing and high availability across several machines, you’ve outgrown a single host, or — the most common honest reason — you want to learn the thing that runs most of the cloud. Learning is a completely valid reason; just name it as the reason, so you’re not surprised by the complexity you signed up for.
If you landed in the second column, here’s the good news about staying light.
What makes k3s the right starting point
You don’t begin with upstream Kubernetes and its pile of separately-installed components. You begin with k3s: a fully compliant Kubernetes distribution shipped as a single binary under 100 MB, using about half the memory of standard Kubernetes. Crucially, it bundles the pieces a cluster needs so you’re not wiring them together yourself:
Those defaults — containerd, Flannel, CoreDNS, Traefik, ServiceLB, and local-path storage — are exactly the choices a beginner would otherwise agonize over. k3s makes sensible ones for you, and you can swap any of them later.
Task 1: Install k3s
On the machine you want as your server node — a mini PC, a VM, or an LXC container with a couple of gigabytes of RAM — run the official installer:
curl -sfL https://get.k3s.io | sh -
That single command installs k3s, starts it as a system service, and brings up a complete single-node cluster. When it finishes, you already have Kubernetes running.
k3s writes a kubeconfig — the file that tells kubectl how to reach your cluster — to /etc/rancher/k3s/k3s.yaml, and installs its own bundled kubectl. Check the node is ready:
sudo k3s kubectl get nodes
You should see one node with status Ready. That’s a real, compliant Kubernetes cluster answering you.
Task 2: Deploy your first app
Remember from the overview: you don’t create pods directly, you declare a Deployment and let Kubernetes manage the pods. Create one from an image:
sudo k3s kubectl create deployment web --image=nginx
sudo k3s kubectl scale deployment web --replicas=3
sudo k3s kubectl get pods
Watch what happens: three pods appear. Delete one with kubectl delete pod <name> and a replacement takes its place within seconds — the reconciliation loop from the overview, happening in front of you. That self-healing is the entire reason to be here.
Task 3: Install real apps with Helm
Typing out manifests by hand gets old fast. Helm is Kubernetes’ package manager: it installs applications from pre-built packages called charts, turning a complex deployment into one command. A chart lives in a repository; installing it creates a named release on your cluster.
The pattern is always the same — add a repository, refresh the index, then install:
helm repo add podinfo https://stefanprodan.github.io/podinfo
helm repo update
helm install my-demo podinfo/podinfo
helm list
That installs podinfo, a tiny demo app made for exactly this — a safe first chart to prove the workflow. helm list shows your releases; helm uninstall my-demo removes one cleanly. From here, deploying most self-hosted apps is a matter of finding their chart.
You can go a long way with plain kubectl apply -f app.yaml manifests, and reading a few by hand teaches you what Helm is doing under the covers. Reach for Helm when the manifests get repetitive — not before you understand them.
Task 4: Grow to more than one node (optional)
A single node is a perfectly good place to stay. But the moment you want workloads to schedule across several machines, you join agent nodes to your server.
sudo cat /var/lib/rancher/k3s/server/node-token
On the new machine, run the same installer but point it at the server’s URL and that token:
curl -sfL https://get.k3s.io | K3S_URL=https://10.0.0.30:6443 K3S_TOKEN=YOUR_NODE_TOKEN sh -
Back on the server, sudo k3s kubectl get nodes now lists both. Kubernetes will start scheduling pods across them — you’ve turned two boxes into one pool.
Each machine needs a unique hostname. If two nodes share one, pass K3S_NODE_NAME=some-unique-name on the install line so the cluster can tell them apart.
Where to go next
You’ve got a real cluster, a self-healing app, and Helm for everything else. The honest next step is to use it for something you’d actually run — then decide, with real experience behind you, whether Kubernetes has earned a permanent place in your lab or taught you what you came to learn. Either outcome is a win.
Related posts:
- What Is Kubernetes? A Plain-English Homelab Guide — the concepts (pods, nodes, control plane, services, ingress) this guide puts into practice.
- Deploy k3s on a single node (playbook) — the copy-paste version of Task 1.
- Add a worker node to a k3s cluster (playbook) — the copy-paste version of Task 4.
- Install Helm and deploy your first chart (playbook) — the copy-paste version of Task 3.
- Your First Docker Compose Stack — the simpler alternative that’s the right call for most homelabs.
- Proxmox VM vs LXC: Which to Use — choosing what your k3s nodes run on.
- What Is Traefik? The Reverse Proxy, Explained — the ingress controller k3s ships by default.
- Build a Proxmox Cluster — pooling machines at the hypervisor layer, next to pooling them with Kubernetes.
Sources: Kubernetes documentation, k3s documentation, Helm documentation.
Comments
Comments are powered by GitHub Discussions — sign in with a GitHub account to join the conversation.