k3s: Kubernetes Small Enough for a Homelab
Kubernetes has a reputation for complexity that is largely earned. k3s does not remove the complexity of the concepts, but it removes almost all of the complexity of running it.
What k3s is
A single binary under 100MB that packages the whole control plane. It replaces etcd with SQLite by default, strips out legacy and cloud-provider components, and bundles a container runtime, an ingress controller, a load balancer, and local storage.
It is conformant, so manifests written for any Kubernetes run on it.
curl -sfL https://get.k3s.io | sh -
sudo k3s kubectl get nodes
That is a working cluster. On a Raspberry Pi.
# Use standard kubectl
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$USER" ~/.kube/config
kubectl get nodes
Adding a node:
# on the server
sudo cat /var/lib/rancher/k3s/server/node-token
# on the new machine
curl -sfL https://get.k3s.io | K3S_URL=https://server:6443 K3S_TOKEN=<token> sh -
What Kubernetes actually adds
Ask this honestly before adopting it, because for one machine the answer is often “nothing you need.”
Rescheduling. A node dies and its workloads start elsewhere. This is the real feature, and it requires more than one machine to mean anything.
Declarative state. You describe what should exist and a controller works continuously to make reality match. Compose describes what to start.
Rolling updates with rollback. Change an image and Pods are replaced gradually, with health checks gating each step and automatic rollback on failure.
Service discovery. Services get stable DNS names inside the cluster regardless of where Pods are running.
Against that: Pods, Deployments, Services, Ingresses, ConfigMaps, Secrets, PersistentVolumeClaims, and namespaces are all concepts you must hold to do anything, where Compose has services and volumes.
The minimum you need to understand
Pod is one or more containers scheduled together on one node. Rarely created directly.
Deployment manages a set of identical Pods, replacing them when they die or when you change the spec.
Service gives that set a stable address and load-balances across it, because Pod IPs change constantly.
Ingress routes external HTTP by hostname and path to Services.
PersistentVolumeClaim requests storage that outlives a Pod.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx:alpine
ports: [{ containerPort: 80 }]
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector: { app: web }
ports: [{ port: 80, targetPort: 80 }]
kubectl apply -f web.yaml
kubectl get pods,svc
kubectl logs -l app=web -f
kubectl describe pod <name> # where you look when something will not start
kubectl describe is the command that answers most “why is this Pending” questions, in the Events section at the bottom.
What k3s bundles
Traefik as ingress, so an Ingress resource works immediately.
ServiceLB so LoadBalancer services bind a port on the node rather than sitting Pending forever, which is what happens on bare-metal Kubernetes without extra components.
local-path-provisioner so PersistentVolumeClaims get local disk automatically. Adequate on one node, and note that storage tied to a node undermines rescheduling on a cluster.
The honest recommendation
Use Compose if you are running services on one machine and want them to work. Our compose generator covers it, and Quadlet if you would rather have systemd units.
Use k3s if you have several machines and genuinely want workloads to survive one failing, or if learning Kubernetes is itself the goal, which is a completely legitimate reason.
What does not work well is adopting Kubernetes for one machine because it seems more professional, then spending your evenings debugging YAML instead of running services.
Frequently Asked Questions
What makes k3s different from Kubernetes?
It is conformant Kubernetes with the bulk removed: one binary, SQLite instead of etcd by default, legacy and cloud-provider components stripped out, and sensible defaults bundled. Manifests written for Kubernetes run on it unchanged.
Do I need Kubernetes for a homelab?
Almost certainly not. Docker Compose runs the same services with a fraction of the concepts. Kubernetes earns its complexity when you have several machines and want workloads rescheduled automatically when one fails, or when you want to learn it deliberately.
How many machines do I need?
One works fine for learning and for running services. Real high availability needs three control plane nodes for etcd quorum. A single node k3s install still gives you the full API and every concept, without the resilience.
What is the difference between a Pod, a Deployment, and a Service?
A Pod is one or more containers scheduled together. A Deployment manages a set of identical Pods and replaces them when they fail or when you change the image. A Service gives that set a stable address, since individual Pods come and go with different IPs.
How do I expose a service outside the cluster?
k3s bundles Traefik as an ingress controller, so an Ingress resource routes hostnames to services. For anything not HTTP, use a NodePort or the bundled ServiceLB, which binds a port on the node itself.
Should I use k3s or k8s on a Raspberry Pi?
k3s. Full Kubernetes will run on modern Pi hardware and consumes a meaningful share of its memory doing nothing useful. k3s leaves considerably more for your actual workloads.