Sunday, July 13, 2025

Homelab Adventures, part 7: Success with K3s

A working Kubernetes, at last

Time for another try at getting a working Kubernetes cluster running. 

This time I'm going to use K3s, a lightweight, full Kubernetes implementation targeted at resource-constrained environments.

I right-click on the debian12-202506 template I created previously, select Clone, and keep the default linked clone option to create a VMfor the Kubernetes server node. 

Once it starts I ssh in, and sudo to check the VM.

Except there's no sudo command.

I make a note to research what Debian's replaced it with (it's not the only distro moving away from  sudo), but for now I just apt install sudo.

Everything looks good, so I reboot and (mostly) follow the instructions in the Quick-Start Guide:

root@k3s-server:~# curl -o k3s.bundle -sfL https://get.k3s.io
root@k3s-server:~# bash k3s.bundle

# Did it work?
root@k3s-server:~# kubectl get node
NAME         STATUS   ROLES                  AGE     VERSION
k3s-server   Ready    control-plane,master   2m11s   v1.32.5+k3s1

I've got my control plane.

I clone another VM to use as an agent node, and spin it up.

I copy over the install bundle from k3s-server and grab the token needed by agent nodes to connect to the server:

root@k3s-server:~# scp k3s.bundle root@k3s-agent-0:.
root@k3s-server:~# cat /var/lib/rancher/k3s/server/node-token # Output is a long, mostly hex string

Then over on the agent machine:

root@k3s-agent-0:~# export K3S_TOKEN='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' # The node token
root@k3s-agent-0:~# export K3S_URL='https://k3s-server:6443'
root@k3s-agent-0:~# chmod +x k3s.bundle
root@k3s-agent-0:~# ./k3s.bundle

Now back on k3s-server:

root@k3s-server:~# kubectl get node
NAME          STATUS   ROLES                  AGE     VERSION
k3s-agent-0   Ready                           3m49s   v1.32.5+k3s1
k3s-server    Ready    control-plane,master   47m     v1.32.5+k3s1

It looks like I have a two node, working Kubernetes cluster at last.

Let's test it.

Take the helm

While you don't have to use Helm to manage Kubernetes applications, it's ubiquitous in the Kubernetes world. Also, at this point I'm primarily interested in verifying that my cluster actually works, so deploying a "known good" configuration makes sense.

I follow the instructions to install Helm using apt, because I'd like to manage any dependencies through my distro's standard package manager:

k3s-server:~# curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | tee /usr/share/keyrings/helm.gpg

Whoops- no gpg. I fix that, and try again:

root@k3s-server:~# curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | tee /usr/share/keyrings/helm.gpg
root@k3s-server:~# apt-get install -y apt-transport-https
root@k3s-server:~# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" > /etc/apt/sources.list.d/helm-stable-debian.list
root@k3s-server:~# apt-get update
root@k3s-server:~# apt-get install -y helm

Now add a Helm repo:

root@k3s-server:~# helm repo add bitnami https://charts.bitnami.com/bitnami
root@k3s-server:~# helm list
Error: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp [::1]:8080: connect: connection refused

This isn't any port I've configured. I track down where K3s puts its Kubernetes config, and specify that on the command line, installing the Helm chart for MySQL:

root@k3s-server:~# helm install bitnami/mysql --generate-name --kubeconfig /etc/rancher/k3s/k3s.yaml
root@k3s-server:~# kubectl get pods -w --namespace default
NAME                 READY   STATUS     RESTARTS   AGE
mysql-1750452535-0   0/1     Init:0/1   0          43s
mysql-1750452535-0   0/1     Init:0/1   0          48s
mysql-1750452535-0   0/1     PodInitializing   0          51s
mysql-1750452535-0   0/1     Running           0          52s
mysql-1750452535-0   0/1     Running           0          107s
mysql-1750452535-0   1/1     Running           0          107s

root@k3s-server:~# helm list --kubeconfig /etc/rancher/k3s/k3s.yaml
NAME                NAMESPACE   REVISION   UPDATED                                 STATUS          CHART       APP VERSION
mysql-1750452535    default     1          2025-06-20 16:49:00.679899596 -0400 EDT deployed        mysql-13.0.29.3.0

Over to the agent machine, and confirm that MySQL is actually running.

k3s-agent-0:~# ps -eaf|grep mysql
1001        2882    2739  1 16:49 ?        00:00:01 /opt/bitnami/mysql/bin/mysqld

Success! I've got a small, working Kubernetes cluster at last.

Mission Accomplished banner on the USS Abraham Lincoln (CVN-72) (1).jpg
By U.S. Navy photo by Photographer's Mate 3rd Class Juan E. Diaz. (RELEASED) - Source, Public Domain, Link

I'll clean things up before I pause my VMs. I uninstall the MySQL Helm chart:

root@k3s-server:~# helm uninstall mysql-1750452535 --kubeconfig /etc/rancher/k3s/k3s.yaml
release "mysql-1750452535" uninstalled
root@k3s-server:~# helm list --kubeconfig /etc/rancher/k3s/k3s.yaml
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP VERSION
root@k3s-server:~#
root@k3s-server:~# kubectl get pods  --namespace default
No resources found in default namespace.

So what are my plans going forward? 

  • I want to explore Kubernetes more, especially the ability to dynamically scale the number of active agent nodes.
  • I need to dig into Kubernetes networking, and learn how to set things up so an application can communicate across nodes.
  • At some point, I'll write a test application, and a Helm chart to deploy it.
Finally, at some point I'd like to get back to figuring out why my original Kubernetes The Hard Way deployment failed.