Software & Configuration

K3s, Lightweight Kubernetes

Install K3s on a VPS for a production-ready Kubernetes cluster, single-node setup, kubectl, Helm and basic deployments

K3s is Kubernetes reduced to ~70MB, ideal for VPS deployments. It is production-ready, uses containerd, and includes Traefik ingress controller built-in. Perfect for running containerized workloads without the overhead of full Kubernetes.


Requirements

  • CPU: 2 vCPU minimum (4 recommended)
  • RAM: 2GB minimum (4GB recommended)
  • OS: Linux x64 (Ubuntu, CentOS, Alpine, etc.)
  • Network: Port 6443 (API) and 10250 (kubelet) accessible between nodes

Single-Node Installation

Install K3s server (acts as both control plane and worker):

curl -sfL https://get.k3s.io | sh -

Check status:

systemctl status k3s
kubectl get nodes

Configure kubectl

Export kubeconfig for local access:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

Or copy to standard location:

mkdir -p ~/.kube
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
chmod 600 ~/.kube/config

Verify:

kubectl get nodes
kubectl get pods --all-namespaces

Deploy Your First Application

Example: Nginx Deployment

Create deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80

Deploy:

kubectl apply -f deployment.yaml

Check deployment status:

kubectl get deployments
kubectl get pods
kubectl logs deployment/nginx

Services

Expose your deployment as a service:

kubectl expose deployment nginx --port=80 --target-port=80 --type=ClusterIP --name=nginx-svc

Or define in YAML:

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx

List services:

kubectl get svc

Ingress with Traefik

K3s includes Traefik ingress controller by default. Create an IngressRoute:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: nginx-ingress
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`example.com`)
      kind: Rule
      services:
        - name: nginx-svc
          port: 80

Apply:

kubectl apply -f ingressroute.yaml

For HTTPS with Let's Encrypt:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: nginx-https
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`example.com`)
      kind: Rule
      services:
        - name: nginx-svc
          port: 80
  tls:
    certResolver: letsencrypt

Helm Package Manager

Install Helm:

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version

Add Helm repositories:

helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

Search for charts:

helm search repo nginx

Install a chart:

helm install my-nginx stable/nginx-ingress

List releases:

helm list

Uninstall:

helm uninstall my-nginx

Common kubectl Commands

List resources:

kubectl get pods
kubectl get nodes
kubectl get services
kubectl get deployments
kubectl get all

View logs:

kubectl logs deployment/nginx
kubectl logs -f pod-name              # follow
kubectl logs pod-name -c container    # specific container

Execute commands in pod:

kubectl exec -it pod-name -- /bin/sh

Describe resource:

kubectl describe pod pod-name
kubectl describe node node-name

Delete resource:

kubectl delete pod pod-name
kubectl delete deployment nginx

Apply configuration:

kubectl apply -f file.yaml

Watch resources:

kubectl get pods --watch

Updating K3s

Re-run the installation script to upgrade to the latest version:

curl -sfL https://get.k3s.io | sh -

Or pin a specific version:

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.27.0 sh -

Check version:

kubectl version

Multi-Node Cluster

On Server Node

Get the token:

cat /var/lib/rancher/k3s/server/node-token

On Worker Node

Join the cluster:

curl -sfL https://get.k3s.io | K3S_URL=https://server-ip:6443 K3S_TOKEN=token sh -

Replace server-ip with the server's IP and token with the token from above.

Verify:

kubectl get nodes

Disabling Traefik (to Save Resources)

If you don't need Traefik:

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik" sh -

Or for existing installation, edit /etc/systemd/system/k3s.service and add --disable traefik to the ExecStart line, then:

systemctl daemon-reload
systemctl restart k3s

Common Issues

High Memory Usage

K3s is lightweight but can use significant memory with many pods. Monitor:

kubectl top nodes
kubectl top pods

Certificate Errors

K3s generates self-signed certificates. For multi-node clusters, ensure NTP is synchronized:

timedatectl status
timedatectl set-ntp true

For multi-node K3s clusters on separate VPS, ensure ports 6443 (API server) and 10250 (kubelet) are open between nodes. Use firewall rules or security groups in your control panel.

On VPS with 1GB RAM, K3s runs but with tight margins. Disable Traefik if not needed: --disable traefik. Monitor resource usage closely with kubectl top nodes.

On this page