Kubernetes has a reputation problem. Everyone agrees it's the thing you should learn, and almost everyone who's tried following a "getting started" guide has e…
Kubernetes has a reputation problem. Everyone agrees it's the thing you should learn, and almost everyone who's tried following a "getting started" guide has ended up staring at a CrashLoopBackOff error with no idea why. Most of that pain comes from people trying to learn Kubernetes on a full production-grade cluster setup when what they actually needed was something small, fast, and forgiving to break. That's exactly what k3s is for — a genuinely lightweight Kubernetes distribution, built by Rancher, that installs in one command and runs happily on a laptop, an old mini PC, or a $5 VPS. This guide gets you from nothing to a working cluster you can actually experiment on.
Prerequisites / What You'll Need
- A Linux machine (a VM, an old laptop, a Raspberry Pi, or a cheap VPS all work)
- At least 512MB of RAM free, though 1GB+ is more comfortable
curl installed
kubectl on your local machine, if you're managing the cluster remotely
- About 20 minutes, most of which is waiting for things to download
Why k3s and Not Just "Kubernetes"
Full upstream Kubernetes (usually installed via kubeadm) wants multiple gigabytes of RAM, a handful of separate components running as systemd services, and a fair bit of manual networking configuration before you even get a cluster that boots. k3s packages all of that — the API server, scheduler, controller manager, kubelet, and a lightweight container runtime — into a single binary under 100MB. It swaps out etcd for SQLite by default too, which is a big part of why it's so much lighter. For learning purposes, running small self-hosted workloads, or edge deployments, it's not a "toy" version of Kubernetes either — it's a certified, CNCF-conformant distribution. It's just... reasonable.
Step 1: Install k3s on the Server Node
SSH into the machine that'll act as your cluster's control plane, then run the official installer:
curl -sfL https://get.k3s.io | sh -
That's the whole install. Behind the scenes it downloads the k3s binary, sets it up as a systemd service, and starts a single-node cluster immediately.
Check that it came up cleanly:
sudo k3s kubectl get nodes
You should see your node listed with a status of Ready. If it's stuck on NotReady for more than a minute or two, something's off — check the logs before moving on:
sudo journalctl -u k3s -f
Step 2: Grab Your Kubeconfig
k3s writes a kubeconfig file to /etc/rancher/k3s/k3s.yaml. If you want to manage the cluster from your local laptop instead of SSHing in every time, copy it over:
sudo cat /etc/rancher/k3s/k3s.yaml
Paste that content into ~/.kube/config on your local machine, then edit one line — the server: field will say https://127.0.0.1:6443, which only makes sense from inside the server itself. Change it to your server's actual IP or hostname:
server: https://your-server-ip:6443
Test the connection:
kubectl get nodes
If that comes back with the same node list you saw locally, you're managing the cluster remotely now, and honestly, this is the point where it starts feeling like a real setup rather than a science experiment.
Step 3: Add a Worker Node (Optional, but Worth Doing)
A single-node cluster is fine for learning, but if you have a second machine lying around, adding it as a worker makes the whole exercise feel a lot closer to reality. On the server node, grab the node token:
sudo cat /var/lib/rancher/k3s/server/node-token
Then on the second machine, join it to the cluster:
curl -sfL https://get.k3s.io | K3S_URL=https://your-server-ip:6443 K3S_TOKEN=<token-from-above> sh -
Back on the control plane, confirm it joined:
kubectl get nodes
You should now see two nodes — one with a control-plane role, one plain worker.
Step 4: Deploy Something to Prove It Works
Nothing builds confidence in a cluster like watching something actually run on it. Deploy a basic Nginx pod:
kubectl create deployment hello-k3s --image=nginx
kubectl expose deployment hello-k3s --port=80 --type=NodePort
Find which port it landed on:
kubectl get svc hello-k3s
Look for the 80:XXXXX/TCP mapping under PORT(S) — that second number is your NodePort. Hit it directly:
curl http://your-server-ip:<nodeport>
You should get back the default Nginx welcome page HTML. That's a full request going through Kubernetes' service networking, landing on a pod, and coming back — which, the first time you see it work, is a genuinely satisfying moment.
Step 5: Explore the Built-In Extras
k3s doesn't just give you bare Kubernetes — it ships with a few things pre-installed that you'd normally have to set up separately on a vanilla cluster: a local storage provisioner, the Traefik ingress controller, and CoreDNS. Check what Traefik gave you for free:
kubectl get pods -n kube-system
You'll see Traefik running already, which means you can define an Ingress resource right away without installing anything extra — genuinely one of the nicer conveniences of k3s over a from-scratch cluster.
Step 6: Write Your First Manifest File
Typing kubectl create commands is fine for testing, but real Kubernetes work lives in YAML files you can version control. Create deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-yaml
spec:
replicas: 2
selector:
matchLabels:
app: hello-yaml
template:
metadata:
labels:
app: hello-yaml
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
Apply it:
kubectl apply -f deployment.yaml
Notice replicas: 2 — kill one of the pods and watch Kubernetes bring it right back:
kubectl get pods -l app=hello-yaml
kubectl delete pod <one-of-the-pod-names>
kubectl get pods -l app=hello-yaml
That self-healing behavior, more than anything else, is the actual point of Kubernetes — it's not really about containers, it's about a system that keeps your desired state true even when things fail underneath it.
Common Pitfalls / Troubleshooting
- Node stuck at
NotReady. Nine times out of ten this is a firewall blocking internal cluster traffic. k3s needs several ports open between nodes — check sudo journalctl -u k3s -f for the specific complaint rather than guessing.
kubectl from your laptop times out. Usually means port 6443 isn't open on the server's firewall for your local IP. sudo ufw allow 6443/tcp (scoped to a specific source if you can) fixes this in most cases.
- Worker node won't join. The token is sensitive to whitespace — copy it carefully, and double-check you're using the exact
K3S_URL with https:// and the right port.
- Everything works until a reboot. k3s installs itself as a systemd service and should survive reboots automatically, but if it doesn't come back, check
sudo systemctl status k3s — sometimes it's a disk that unmounted differently than expected on boot.
- Confusing SQLite's limits with "k3s isn't real Kubernetes." For a single small cluster it's genuinely fine, but if you outgrow it, k3s supports swapping in an external datastore (etcd, Postgres, MySQL) for HA setups — it's a config change, not a reinstall.
Wrapping Up
A k3s cluster you can break, rebuild, and break again is worth more for actually learning Kubernetes than a perfectly configured production cluster you're too nervous to touch. Once this is running, the natural next moves are wiring up a proper Ingress with a real hostname instead of NodePorts, trying Helm to install something more complex than an Nginx demo, and eventually pointing a CI pipeline at it so deployments happen automatically instead of by hand.
Further Reading
Hashtags
#kubernetes #k3s #devops #selfhosted #homelab #containers #cloudnative #linux #sysadmin #infrastructureascode #cncf #docker #techblog #nginx #opensource #kubectl #edgecomputing #microservicesarchitecture #yaml #devopsengineering #platformengineering #itinfrastructure #techtutorial #learnkubernetes #containerorchestration #clustermanagement #cloudcomputing #softwareengineering #sysadminlife