Skip to content
Go back

k3sup vs kubeadm for Homelab Clusters

By SumGuy 11 min read
k3sup vs kubeadm for Homelab Clusters

k3sup vs kubeadm for Homelab Clusters

Two philosophies show up at your doorstep: kubeadm, the official upstream bootstrapper that hands you a box of parts and a wrench, and k3sup, a one-shot SSH installer that leans on k3s and says “here’s your cluster, go play.” Both build Kubernetes clusters — but they have very different attitudes about how much work you want to do at 2 AM.

Take a breath. Close those tabs. This isn’t about religious wars. It’s about decisions that affect your nights, your backups, and whether you enjoy debugging CNI CRDs or sipping coffee while your cluster boots itself.

The kubeadm philosophy (what it actually does)

kubeadm is upstream Kubernetes’ official bootstrap tool. It’s honest and blunt: it sets up the control plane components (kube-apiserver, controller-manager, scheduler), generates certs, and gives you join tokens. After that, it’s your job to wire the rest: pick a CNI, choose a storage class, add ingress, metrics, monitoring, and any other opinions you want in your cluster.

Think of kubeadm as buying an engine, gearbox, and chassis. It tells you how to bolt those bits together properly, but it doesn’t install the seats, air conditioning, or infotainment system. That freedom is powerful — and also the reason your first kubeadm cluster inevitably ends with someone on Slack complaining about broken DNS and a flurry of kubectl describe commands.

Core behaviors:

The k3sup philosophy (what it actually does)

k3sup is a tiny remote bootstrapper that uses SSH to install k3s, Rancher’s lightweight Kubernetes distribution. k3sup itself is not Kubernetes — it’s a convenience tool that executes k3s installers over SSH and copies kubeconfig back to your laptop.

k3s is opinionated: it bundles a CNI (Flannel by default), a local-path provisioner for storage, and a default ingress (Traefik in many releases). k3sup leans on that opinionated stack and makes the whole thing a one-liner remote install.

Think of k3sup as buying a pre-built scooter and having a friend deliver it to your driveway and hand you the keys. It’s fast, predictable, and gets you moving.

Practical kubeadm example: init, token, join

Kubeadm flow is explicit. On your control plane node:

kubeadm init (control plane)
sudo kubeadm init --apiserver-advertise-address=192.168.1.10 \
--pod-network-cidr=10.244.0.0/16

That outputs the join command the worker will use, or you can create a token explicitly:

Create token (control plane)
# prints a ready-to-run kubeadm join command with token and discovery hash
sudo kubeadm token create --print-join-command

On a worker node, run the printed command, e.g.:

kubeadm join (worker)
sudo kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

For a control-plane join (HA), generate a cert key and use —control-plane:

kubeadm init (upload certs)
sudo kubeadm init --upload-certs --apiserver-advertise-address=192.168.1.10
# On join node
sudo kubeadm join 192.168.1.10:6443 --token <tok> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane --certificate-key <cert-key>

That’s kubeadm: manual, explicit, and fine-grained.

Practical k3sup example: install, join, server/agent model

k3sup’s magic is simple: it SSHes into the target, runs the k3s installer, and wires kubeconfig back to your laptop. Example server install:

k3sup install (server)
k3sup install --ip 192.168.1.20 --user pi --local --k3s-version v1.30.4+k3s1

Add an agent (worker):

k3sup join (agent)
k3sup join --ip 192.168.1.21 --server-ip 192.168.1.20 --user pi

Make a second server (HA) by joining with the —server flag (k3s will handle control plane replication):

k3sup join --server (HA control plane)
k3sup join --ip 192.168.1.22 --server --server-ip 192.168.1.20 --user pi

k3sup is ideal when you want a simple, repeatable path to a working cluster without hand-holding low-level details.

HA control plane: kubeadm vs k3sup

Both support HA control planes, but the experience and mechanics differ substantially.

kubeadm HA is explicit and hands-on:

k3sup + k3s HA is designed for simplicity:

Bottom line: kubeadm HA gives you complete control and therefore more surfaces to manage; k3sup HA gives you a consistent, smaller-surface workflow that gets redundancy working quickly. For a 3-node homelab, k3sup is the obvious choice. For production at scale, kubeadm’s transparency and fine-grained control is worth the ops complexity.

What gets shipped: vanilla k8s vs k3s defaults

Vanilla kubeadm intentionally ships minimal Kubernetes binaries and certs. It’s a blank canvas: you get the control plane, kubelet, kubectl, and nothing else. You must pick and install:

k3s (thus k3sup installs) is opinionated by default. Typical defaults: Flannel for CNI, a local-path provisioner for PVCs, Traefik for ingress (depending on k3s version), and a small DNS implementation. Out of the box, you have a usable cluster. Pods get IPs, storage works, and external traffic routes to services.

Opinionated defaults are a feature for homelabs: you get a working environment fast without homework. The trade-off is you might outgrow the defaults later (swap Flannel for Calico, replace Traefik with Nginx, add a real storage backend). But early on, you’re not frantically installing manifests at 2 AM just to get DNS working.

Think of it this way: kubeadm is a blank slate that teaches you every decision; k3s is a sensible starting point that you customize as needed.

The CNI choice story — “I picked Calico” pain

This one is a rite of passage:

Calico is powerful, but it has more moving parts than Flannel. It needs BGP speakers, custom resource definitions for network policies, and careful IP pool management. For homelabs, that complexity costs time and sleep. k3s+Flannel trades raw power for reliability. Flannel is simple: overlay VXLAN, minimal dependencies, works out of the box.

If you want Calico for learning or because your homelab demands network policies across pods, fine — but expect additional troubleshooting, more research, and extra moving parts during upgrades. You’ll be reading Calico docs at 2 AM instead of enjoying your services.

If your goal is “learn Kubernetes internals and network policy details,” kubeadm + Calico is educational. If the goal is “run services at home with minimal babysitting,” k3sup + k3s + Flannel is the pragmatic choice. There’s no prize for the harder path if a simpler one works.

Storage class reality — who wires PVCs?

Kubeadm: no storage provisioner by default. That means new PersistentVolumeClaims sit in Pending until you install a provisioner like Local Path Provisioner, Longhorn, or Rook. You have to decide where the volumes live: local SSDs, NFS, or a networked solution.

k3s: ships with local-path-provisioner (or something similar) so PVCs work out of the box for many home setups. It’s not a cloud-grade solution, but for dev/test and even a small homelab, it’s a practical default.

If your NAS is central to your homelab, you’ll probably swap in Longhorn or Rook later. Again: kubeadm gives you options; k3s gives you defaults that are less scary at midnight.

Upgrades: kubeadm upgrade vs re-run k3s/k3sup

kubeadm upgrades are deliberate and multi-step:

This process is well-documented, suitable for production, and gives you fine-grained control over when each component upgrades. But it also means more manual steps, more reading release notes, and more surfaces for things to go wrong.

k3s upgrades are designed for simplicity. With k3sup you re-run the install/join commands with a new —k3s-version to swap binaries. It’s idempotent: the same command works for install, upgrade, or re-run. Simpler and messier at the same time: great for homelabs, but less surgical than kubeadm’s controlled path. k3s is also lighter on the system, so a full re-install on a Raspberry Pi is faster.

A kubeadm upgrade example:

kubeadm upgrade (control plane)
# on control plane
sudo apt-get update && sudo apt-get install -y kubeadm=1.27.3-00
sudo kubeadm upgrade plan # Check what’s going to change
sudo kubeadm upgrade apply v1.27.3
# then upgrade kubelet/kubectl on nodes and restart kubelet
sudo systemctl restart kubelet

And k3s upgrade (via k3sup):

k3sup upgrade (server)
# Re-run install with new version
k3sup install --ip 192.168.1.20 --user pi --k3s-version v1.27.3+k3s1
# Re-run join for agents if needed
k3sup join --ip 192.168.1.21 --server-ip 192.168.1.20 --user pi --k3s-version v1.27.3+k3s1

Same command, new version, cluster updated. Less control, less ceremony, more uptime.

Tear-down: reset vs uninstall

When it’s time to tear down a cluster:

kubeadm:

kubeadm reset
sudo kubeadm reset -f
sudo apt-get purge -y kubeadm kubectl kubelet
sudo rm -rf /etc/cni /var/lib/cni /var/lib/kubelet /etc/kubernetes

k3s:

k3s uninstall
sudo /usr/local/bin/k3s-uninstall.sh
# on agents
sudo /usr/local/bin/k3s-agent-uninstall.sh

k3s tends to be cleaner to remove because fewer external components were manually installed.

When kubeadm IS the right tool

Use kubeadm if you actually need the guarantees and tooling of upstream Kubernetes:

Basically: if you want power and are comfortable with complexity, kubeadm is the right choice.

Conclusion — which wins for your homelab?

k3sup (with k3s) wins for almost every homelab use-case. It’s fast, repeatable, and keeps the nightly gremlins away. For running a few services — Home Assistant, a photo server, a CI runner, or messing with LLMs — k3sup gives you a working Kubernetes cluster in minutes. You’re trading a little upstream purism for a lot of convenience.

kubeadm is excellent if your goal is education, strict upstream parity, or running a production-sized cluster where every component must be intentionally chosen and operated. But if you’re the sort of person who’s already apologizing to their 2 AM self, k3sup will save you hours.

There’s no prize for running upstream Kubernetes at home if a Compose file or k3sup cluster does the job better. Your 2 AM self will appreciate it.

Recommendations quick-hit:

  • Want a cluster in 10 minutes? Use k3sup + k3s.
  • Want to learn Kubernetes internals or prepare for CKA? Use kubeadm.
  • Need HA and don’t mind ops? Either works — kubeadm for control, k3sup for speed.

Happy clustering. Don’t forget to back up your etcd or your k3s datastore before tinkering — and yes, label your nodes so you don’t accidentally schedule your NAS as a control-plane.


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
DIY NAS Build: Compute, Drives, Power Walkthrough
Next Post
Dead Container Took Down Prod

Discussion

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

Related Posts