The true Kubernetes cluster

Now it’s time to create my true Kubernetes cluster, and still use K3s as distribution.


So I ordered a cheap VPS to handle the master node (in the user agreement there is a closure that indicate 99.9% uptime)


Setup the VPS

Configuration

Operating system

I usually use Ubuntu in my homelab, and having something homogenous is better than having different OS.

Default configuration: Firewall

My VPS provider allows me to configure an upfront firewall so that I don’t need to do IPTables command and have headaches.

Default configuration: SSH

To ensure the security of the VPS, we’ll need to pimp some SSH server option.
We have to set PermitPasswordAuthentication to false.

I’m not a fan of disabling root authentication (Yes I know, I love risk), so I keep this but the attacker need an authorized ssh key anyway to access to my VPS.

Update the system

Even if my VPS is brand new and cloud-init should update all the packages. I prefer to update the source lists and upgrade packages.

Create the management user

You can chose any name as a management user to upgrade K3s, don’t forget to put the user in the sudoer list.

Create a WireGuard server

I will work on an API to create wireguard configuration automatically (to setup node automatically)

  1. Install wireguard: apt install wireguard [openresolv] ([] means optional)

  2. Enable IP forward: sysctl -w net.ipv4.ip_forward=1

  3. Create the interface.

# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <generated by wg genkey>
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Address = 10.6.99.1/24 # The subnet I want
ListenPort = 51820

# Worker 1-x
[Peer]
PublicKey = <get it by the remote device or generate it on the server>
PresharedKey = <generated by wg genpsk>
AllowedIPs = 10.6.99.x/32
  1. Start the server at the system boot: systemctl enable --now wg-quick@wg0

  2. Create the client config:

    [Interface]
    PrivateKey = <generated by wg genkey>
    Address = 10.6.99.x/24
    
    [Peer]
    PublicKey = <server public key>
    PresharedKey = <preshared key generated on the VPS>
    AllowedIPs = 10.6.99.0/24
    Endpoint = <VPS IP>:51820
    PersistentKeepalive = 25
  3. Look if it works, and it works 🎉

Add Kubernetes

This cluster is not HA

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.30.2+k3s1 sh -s - server \
--write-kubeconfig-mode 644 \
--tls-san <VPS IP> \
--flannel-iface wg0 \
--node-ip 10.6.99.1 \
--node-external-ip <VPS IP> \
--advertise-address 10.6.99.1

You need to wait a bit before be able to use the Kubernetes API or adding node to the cluster.

Look if it works

Run: kubectl get no; and you shall see your master node marked as Ready

NAME                STATUS   ROLES                  AGE     VERSION
cloud.legodard.fr   Ready    control-plane,master   5m42s   v1.30.2+k3s1

Get the join token

You can get the join token by running: cat /var/lib/rancher/k3s/server/token

Setup workers

Configure WireGuard

  1. Install wireguard package: apt install wireguard [openresolv] ([] means optional)

  2. Add the client configuration (see above)

  3. Start wireguard at boot: systemctl enable --now wg-quick@wg0

  4. Look if you can ping the VPS using wireguard IP: ping 10.6.99.1

Add the worker node

The join procedure is quite hard:

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.30.2+k3s1 \
K3S_URL=https://10.6.99.1:6443 \
K3S_TOKEN="<look Get join token>" \
sh -s - \
--node-ip 10.6.99.x \
--flannel-iface wg0

Bootstrap the cluster

I made a GitHub repository to handle my Kubernetes configuration.

Install the basics

You need to follow in this way to bootstrap the cluster:

  1. Apply cert-manager stack

  2. Apply vault stack

  3. Apply argocd stack

And voilà

You successfully created the Kubernetes cluster.