Secure HA Kubernetes on bare metal using k3s
Walkthrough deploying secure HA Kubernetes on bare metal using k3s and embedded etcd.

This walkthrough will leave you with a
kubeconfigto a fully functional, secure cluster.
What is k3s?
Kubernetes is was too hard for the solo developer. Using k3s you can deploy Kubernetes in a couple of commands per node. The Kubernetes distribution is:
- fully conformant
- production-ready
- lightweight
- packaged in a single binary
I personally run 3 SKVM-4G from MaxKVM for 18$/month with student discount. Each node has 2 EPYC cores, 4GB ECC, 3TB traffic @ 1GBs, 75GB NVME; unmatched for that price.
1. Setup node iptables
To isolate network communication we need to setup some firewall rules on each node. This tutorial will use ufw to configure iptables but you may use any other tool. I assume that each node will have two distinct network interfaces:
eth0assigned with a public IP used for internet communicationeth1assigned with a private IP used for intranet communication
We will start by blocking incoming and allowing outgoing traffic.
sudo ufw default allow outgoing
sudo ufw default deny incoming
Further we need to enable ssh access to the node.
sudo ufw allow ssh
We allow communication through the intranet. You can also add each node IP seperately.
In this example eth1 is part of the subnet 172.16.0.0/12.
sudo ufw allow from 172.16.0.0/12
We allow communication to the CNI (Container Network Interface) from the Pod CIDR.
sudo ufw allow in on cni0 from 10.42.0.0/16
We allow communication to the Kubernetes API.
sudo ufw allow 6443/tcp
2. Install Kubernetes
To join nodes k3s needs a shared secret. We can generate one with:
openssl rand -base64 32
2.1 First node
We configure necassary installation parameters on the server:
K3S_TOKENthe secret we generated in step 2INSTALL_K3S_EXECarguments the k3s installer is called with--cluster-initthis node initializes a completely new cluster-i {eth1_ip}this node uses the internal IP--flannel-iface eth1the cluster network is build on the intranet--disable traefikk3s ships with outdated traefik as ingress
export K3S_TOKEN="{generated_secret}" &
export INSTALL_K3S_EXEC="server \
--cluster-init \
-i {eth1_ip} \
--flannel-iface eth1 \
--disable traefik"
Now we execute the install script.
curl -sfL https://get.k3s.io | sh -
2.2 Other nodes
Configuration is similar to the first node. Now we do not initialize a cluster, but join the cluster that was created in 2.1.
export K3S_TOKEN="{generated_secret}" &
export INSTALL_K3S_EXEC="server \
--server https://{node1_internal_ip}:6443 \
-i {eth1_ip} \
--flannel-iface eth1 \
--disable traefik"
Also execute the install script.
curl -sfL https://get.k3s.io | sh -
2.3 Finalize
On any node run kubectl get nodes to check if your cluster was build sucessfully.
Now remove from /etc/systemd/system/k3s.service on every node:
--cluster-initif it is the first node--serverelse
at the bottom of the file.
Reload and check the node after editing.
systemctl daemon-reload
service k3s restart
kubectl get nodes
Copy /etc/rancher/k3s/k3s.yaml to your machine.
After that replace localhost with a node or loadbalancer IP and you are done.
