KubernetesWritten by GLWS16 min readUbuntu 24.04 LTS / AlmaLinux 9
Commands run on your server unless a section says otherwise. Replace example usernames, addresses and paths with your own values. Keep a working session open when changing remote access.

What K3s is, and whether you need it

Kubernetes runs containers across machines and keeps them running. K3s is a lightweight, certified Kubernetes distribution packaged as one binary, which makes it practical on a small server. It includes the Traefik ingress controller, a basic load balancer, and a local storage provider.

Kubernetes is worth it when you want to learn it, run many services with declarative configuration, or use tools built for it. For one or two applications, Docker Compose is simpler and uses far less memory. Be honest about which you need.

Check the requirements

The project lists 2 CPU cores and 2 GB of memory as the minimum for a server node, and an SSD for good performance. Kubernetes itself takes a share of memory before your applications start, so a 4 GB plan is a sensible starting point. Each node needs a unique hostname. Run a normal Ubuntu or AlmaLinux image with a recovery console available.

Both systems
nproc
free -h
df -h /
hostnamectl --static
cat /etc/os-release | head -n 3

Install K3s

The installer is a script that downloads the K3s binary, sets up a systemd service and starts a single-node cluster. Download the script and read it before running it. The installer also sets up the kubectl and crictl commands and uninstall scripts.

Both systems
curl -sfL https://get.k3s.io -o k3s-install.sh
less k3s-install.sh
sudo sh k3s-install.sh
sudo systemctl status k3s --no-pager | head -n 5
sudo k3s kubectl get nodes
On AlmaLinux the installer adds an SELinux policy package for K3s when needed. Let it do so, and do not disable SELinux.

Set up kubectl for your own user

The cluster's admin credentials are in /etc/rancher/k3s/k3s.yaml, readable only by root. Copy the file to your own account and point kubectl at it, so you do not need sudo for every command. Treat the file like a root password: anyone with it controls the cluster.

Both systems
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$USER": ~/.kube/config
chmod 600 ~/.kube/config
echo 'export KUBECONFIG=$HOME/.kube/config' >> ~/.bashrc
export KUBECONFIG=$HOME/.kube/config
kubectl get nodes -o wide

Look at what is running

A fresh K3s cluster already runs system pods in the kube-system namespace: DNS, the metrics server, Traefik and the local storage provisioner. Look at them, and at the cluster's resource use. Learning these few commands covers most daily work.

Both systems
kubectl get pods -A
kubectl get storageclass
kubectl top nodes
kubectl get svc -A
free -h

Run a first workload

Create a deployment, expose it inside the cluster and look at it. Then delete it, so the cluster is clean. The next guide deploys an application with HTTPS and persistent storage.

Both systems
kubectl create deployment hello --image=nginx:stable
kubectl rollout status deployment/hello
kubectl get pods -l app=hello
kubectl expose deployment hello --port=80
kubectl get svc hello
kubectl delete svc,deployment hello

Open only the ports you need

The Kubernetes API listens on port 6443. For a single-node cluster, you do not need it reachable from the internet, since you run kubectl on the server. Leave it closed, or reach it through an SSH tunnel. Only web traffic needs to be public: ports 80 and 443 reach Traefik. Ports for flannel and the kubelet matter only between nodes in a multi-node cluster.

The project's documentation says that with UFW or firewalld you must allow traffic from the pod network (10.42.0.0/16) and service network (10.43.0.0/16), or recommends turning firewalld off. Do not leave a firewall with default-deny blocking those ranges, or pods cannot reach each other.

Ubuntu (UFW)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 10.42.0.0/16 to any
sudo ufw allow from 10.43.0.0/16 to any
sudo ufw status verbose
AlmaLinux (firewalld)
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16
sudo firewall-cmd --permanent --zone=trusted --add-source=10.43.0.0/16
sudo firewall-cmd --reload
Use the API from your computer through an SSH tunnel
ssh -N -L 6443:127.0.0.1:6443 deploy@YOUR_SERVER
Also check the earlier guides on Docker published ports: containers and Kubernetes services can bypass the host firewall in similar ways. Check what listens with ss -lntp.

Maintain, back up and remove it

Upgrade by re-running the install script with the release channel or version you want, after reading the release notes. On a single node, K3s keeps cluster state in /var/lib/rancher/k3s, so back up that folder and the node token with the backup guides, and keep your manifests in Git. To start over, the installer provides an uninstall script that removes K3s and its data.

Both systems
sudo ls /var/lib/rancher/k3s/server/
sudo journalctl -u k3s --since "1 hour ago" --no-pager | tail -n 20
Remove K3s completely (destroys the cluster)
sudo /usr/local/bin/k3s-uninstall.sh

Official documentation

These upstream references provide more detail on the commands and workflows in this guide.