Lightweight Kubernetes (k3s) on RamNode KVM instances. Covers single-node and multi-node (1 server + N agents) topologies.
Assumptions
- RamNode KVM VPS(es), Ubuntu 24.04 LTS
- Private networking between nodes if available (check if your RamNode plan/datacenter offers a private VLAN — otherwise use public IPs + firewall rules restricting the k3s ports to node IPs only)
- At least 1GB RAM per node (2GB+ recommended for anything beyond a toy workload)
1. Base prep (all nodes)
apt update && apt -y upgrade
apt -y install curl ufw open-iscsi nfs-common
swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab # k3s/kubelet expects swap offDisable/verify no conflicting firewall state yet — configure ufw explicitly per role below.
2. Single-node quickstart (server acts as its own worker)
curl -sfL https://get.k3s.io | sh -Check status:
systemctl status k3s
k3s kubectl get nodesKubeconfig is at /etc/rancher/k3s/k3s.yaml. For a non-root/remote kubectl:
mkdir -p ~/.kube
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sed -i "s/127.0.0.1/$(hostname -I | awk '{print $1}')/" ~/.kube/config
chmod 600 ~/.kube/configFirewall for single-node (only if exposing the API remotely):
ufw allow OpenSSH
ufw allow 6443/tcp # k8s API
ufw enable3. Multi-node: server setup
On the first server node:
curl -sfL https://get.k3s.io | sh -s - server \
--write-kubeconfig-mode 644 \
--tls-san <server-public-ip-or-hostname>Grab the node token for joining agents:
cat /var/lib/rancher/k3s/server/node-tokenFirewall on the server node:
ufw allow OpenSSH
ufw allow 6443/tcp # API server
ufw allow from <agent-ip-1> to any port 8472 proto udp # flannel VXLAN, repeat per agent
ufw allow 10250/tcp # kubelet metrics
ufw enableIf your RamNode nodes share a private network, restrict 8472/udp and 10250/tcp to the private subnet instead of per-IP rules — much less maintenance:
ufw allow from 10.0.0.0/24 to any port 8472 proto udp
ufw allow from 10.0.0.0/24 to any port 10250 proto tcp4. Multi-node: agent setup
On each additional VPS meant to be a worker:
curl -sfL https://get.k3s.io | K3S_URL=https://<server-ip>:6443 \
K3S_TOKEN=<token-from-server> sh -Firewall on agents:
ufw allow OpenSSH
ufw allow from <server-ip> to any port 10250 proto tcp
ufw allow from 10.0.0.0/24 to any port 8472 proto udp
ufw enableVerify from the server:
kubectl get nodes -o wide5. HA control plane (optional, 3+ server nodes)
k3s supports embedded etcd for HA. On the first server:
curl -sfL https://get.k3s.io | sh -s - server --cluster-init --tls-san <shared-vip-or-lb-hostname>On subsequent server nodes:
curl -sfL https://get.k3s.io | sh -s - server \
--server https://<first-server-ip>:6443 \
--token <token-from-first-server>Put a load balancer or DNS round-robin in front of the server IPs for --tls-san. RamNode doesn't provide a managed LB — use keepalived/VRRP across the server nodes if you need a floating VIP, or point clients at all server IPs via a small nginx/haproxy edge node.
6. Storage note
k3s ships with local-path-provisioner by default (hostPath-backed, single-node-affinity — fine for small deployments, not for anything needing pod-mobility of PVCs). For real persistent storage across nodes on RamNode VPS instances, options are:
- Longhorn (needs
open-iscsi, already installed above) — good fit for a small multi-node k3s cluster with local disks - NFS server on one node +
nfs-subdir-external-provisioner— simplest if you already have a beefy storage node
7. Uninstall (if needed)
/usr/local/bin/k3s-uninstall.sh # on server
/usr/local/bin/k3s-agent-uninstall.sh # on agentNotes
- k3s replaces iptables-based kube-proxy config and manages its own firewall-adjacent rules for CNI (flannel by default) — don't fight it with overly broad
ufwdeny rules on the pod CIDR (default10.42.0.0/16) or service CIDR (10.43.0.0/16). - For anything customer-facing, put a proper ingress controller (Traefik ships by default with k3s) behind a reverse proxy/CDN rather than exposing NodePorts directly on RamNode public IPs.
