NEWS Earn Money with Onidel Cloud! Affiliate Program Details - Check it out

How to Deploy a Production‑Ready k3s Cluster on 3 Ubuntu 24.04 VPS with Cilium (eBPF), Traefik Ingress, and Let’s Encrypt (2025 Guide)

Introduction

Deploying a production-ready Kubernetes cluster can be complex and resource-intensive. K3s, the lightweight Kubernetes distribution by Rancher, solves this challenge by providing a fully compliant Kubernetes experience with minimal resource requirements and simplified deployment.

In this comprehensive guide, we’ll deploy a high-availability k3s cluster across three Ubuntu 24.04 VPS instances. We’ll replace the default Flannel CNI with Cilium for enhanced eBPF-based networking, configure Traefik as our ingress controller, and implement automatic TLS certificate management with Let’s Encrypt.

By the end of this tutorial, you’ll have a production-ready cluster capable of running containerized workloads with enterprise-grade networking, security, and automated certificate management.

Prerequisites

Before starting this deployment, ensure you have the following resources and access:

  • Infrastructure: 3 Ubuntu 24.04 LTS VPS instances with at least 2GB RAM and 2 vCPU each
  • Network: All servers should have public IP addresses and unrestricted communication between them
  • Domain: A registered domain name with DNS management access
  • Access: Root or sudo access on all three servers
  • Security: SSH key-based authentication configured for secure access

Resource Requirements: Each node requires minimum 2GB RAM, 2 vCPU cores, and 20GB storage. For production workloads, consider scaling to 4GB RAM per node.

Step 1: Prepare All Servers

First, update all three Ubuntu 24.04 systems and install essential packages:

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install required packages
sudo apt install -y curl wget apt-transport-https ca-certificates

# Disable swap (required for Kubernetes)
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# Enable required kernel modules
echo 'br_netfilter' | sudo tee /etc/modules-load.d/k8s.conf
echo 'overlay' | sudo tee -a /etc/modules-load.d/k8s.conf
sudo modprobe br_netfilter
sudo modprobe overlay

Configure kernel parameters for Kubernetes networking:

# Configure sysctl parameters
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF

# Apply sysctl parameters
sudo sysctl --system

Step 2: Install k3s Master Node

On your designated master node (first server), install k3s with Cilium-compatible configuration:

# Install k3s server with disabled default CNI
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable-network-policy --flannel-backend=none --disable=traefik" sh -s -

# Enable and start k3s
sudo systemctl enable k3s
sudo systemctl start k3s

# Get node token for worker nodes
sudo cat /var/lib/rancher/k3s/server/node-token

Important: Save the node token output – you’ll need it for joining worker nodes. Also note the master node’s IP address.

Step 3: Join Worker Nodes

On the remaining two servers (worker nodes), join them to the cluster:

# Replace MASTER_IP with your master node's IP and TOKEN with the saved token
curl -sfL https://get.k3s.io | K3S_URL=https://MASTER_IP:6443 K3S_TOKEN=TOKEN sh -

# Enable k3s agent
sudo systemctl enable k3s-agent

Verify cluster formation from the master node:

# Check cluster nodes
sudo k3s kubectl get nodes

# All nodes should show as Ready (may take a few minutes)

Step 4: Deploy Cilium CNI with eBPF

Install the Cilium CLI and deploy Cilium as the container network interface:

# Install Cilium CLI
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz{,.sha256sum}

# Install Cilium with eBPF optimization
cilium install --version 1.14.5

Wait for Cilium to initialize and verify the installation:

# Check Cilium status
cilium status --wait

# Verify connectivity
cilium connectivity test

Step 5: Configure Traefik Ingress Controller

Create a custom Traefik configuration with Let’s Encrypt integration:

# Create traefik-config.yaml
cat <<EOF | sudo k3s kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-config
  namespace: kube-system
data:
  traefik.yml: |
    entryPoints:
      web:
        address: ":80"
        http:
          redirections:
            entryPoint:
              to: websecure
              scheme: https
      websecure:
        address: ":443"
    certificatesResolvers:
      letsencrypt:
        acme:
          email: [email protected]
          storage: /data/acme.json
          httpChallenge:
            entryPoint: web
EOF

Important: Replace [email protected] with your actual email address for Let’s Encrypt notifications.

Deploy Traefik with the custom configuration:

# Create traefik-deployment.yaml
cat <<EOF | sudo k3s kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      containers:
      - name: traefik
        image: traefik:v3.0
        ports:
        - containerPort: 80
        - containerPort: 443
        - containerPort: 8080
        volumeMounts:
        - name: config
          mountPath: /etc/traefik
        - name: data
          mountPath: /data
      volumes:
      - name: config
        configMap:
          name: traefik-config
      - name: data
        hostPath:
          path: /var/lib/traefik
---
apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: kube-system
spec:
  type: LoadBalancer
  selector:
    app: traefik
  ports:
  - name: web
    port: 80
    targetPort: 80
  - name: websecure
    port: 443
    targetPort: 443
EOF

Step 6: Test Your Deployment

Deploy a test application to verify your cluster functionality:

# Create test-app.yaml
cat <<EOF | sudo k3s kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: test-app-service
spec:
  selector:
    app: test-app
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-app-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt"
spec:
  tls:
  - hosts:
    - test.yourdomain.com
    secretName: test-tls
  rules:
  - host: test.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: test-app-service
            port:
              number: 80
EOF

Point your domain’s DNS A record to your master node’s public IP address and test HTTPS access.

Best Practices

Implement these production security practices for your k3s cluster:

  • Network Security: Consider implementing CrowdSec protection on your VPS instances
  • Backup Strategy: Set up automated encrypted backups for your cluster data
  • Resource Monitoring: Deploy monitoring solutions like Prometheus and Grafana
  • Access Control: Implement RBAC policies and use SSH key authentication
  • Regular Updates: Keep k3s, Cilium, and Traefik updated to latest versions

Security Warning: Never expose the Kubernetes API server directly to the internet without proper authentication and network security measures.

Conclusion

You’ve successfully deployed a production-ready k3s cluster with enterprise-grade networking through Cilium’s eBPF technology, automated ingress management via Traefik, and secure TLS termination with Let’s Encrypt certificates.

This setup provides a robust foundation for running containerized applications with high-performance networking, automatic certificate management, and scalable ingress capabilities. Your cluster is now ready to handle production workloads with the reliability and security features required for modern applications.

For additional security enhancements, consider exploring post-quantum TLS implementations or IPv6-ready service exposure to future-proof your infrastructure.

Share your love