K3s is designed to be a minimalist, single-binary Kubernetes distribution that’s easy to install and run, especially for single-node setups.

Here’s a quick demo of K3s in action. Imagine you’ve just SSH’d into a clean server (let’s say a fresh Ubuntu 22.04 LTS VM).

First, download and run the installation script:

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

This single command bootstraps a fully functional Kubernetes control plane and worker node on your machine. No complex YAML manifests, no lengthy configuration files to start.

After a minute or two, you’ll see output indicating K3s has started. To verify, check the status of the K3s service:

sudo systemctl status k3s

You should see active (running). Now, let’s interact with it using kubectl. K3s automatically installs kubectl and configures it to talk to your local cluster. The configuration is usually found at /etc/rancher/k3s/k3s.yaml. To use it without sudo and with your regular user, you can copy this configuration to your ~/.kube/config or set the KUBECONFIG environment variable:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes

This will output something like:

NAME      STATUS   ROLES                  AGE   VERSION
my-host   Ready    control-plane,master   5m    v1.27.4+k3s1

You’ve just launched a Kubernetes cluster. Let’s deploy a simple application, like Nginx. Create a file named nginx-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # Tell Kubernetes to run 2 pods
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest # Use the latest Nginx image
        ports:
        - containerPort: 80

Now, apply this deployment:

kubectl apply -f nginx-deployment.yaml

You’ll see deployment.apps/nginx-deployment created. To see the pods running:

kubectl get pods -l app=nginx

Output will show two pods, likely in a Running state:

NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-6b975d6c5b-abcde   1/1     Running   0          30s
nginx-deployment-6b975d6c5b-fghij   1/1     Running   0          30s

To expose this Nginx deployment to the outside world, we need a Service. Create nginx-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx # This selects the pods with the label 'app: nginx'
  ports:
    - protocol: TCP
      port: 80 # The port the service listens on
      targetPort: 80 # The port the pods listen on
  type: LoadBalancer # K3s's built-in Klipper Load Balancer will handle this

Apply the service:

kubectl apply -f nginx-service.yaml

You’ll see service/nginx-service created. Now, check the service:

kubectl get service nginx-service

The output will show an EXTERNAL-IP. For K3s running locally, this will typically be 127.0.0.1 or 0.0.0.0 if exposed externally.

NAME            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-service   LoadBalancer   10.43.100.50   127.0.0.1     80:30123/TCP   15s

You can now access your Nginx deployment by navigating to http://127.0.0.1 in your browser. The 30123 is the NodePort that Klipper Load Balancer has assigned.

K3s achieves this simplicity by bundling essential components like containerd (a container runtime), Flannel (a CNI network plugin), CoreDNS, Traefik (an ingress controller), and a lightweight etcd alternative called SQLite, all into a single binary. For HA setups, it can connect to external etcd or use its embedded database in a clustered mode. The k3s server command starts the control plane, and k3s agent joins nodes. The LoadBalancer service type in K3s is handled by Klipper Load Balancer, a lightweight network load balancer that runs as a Deployment within the cluster itself, proxying traffic to your services.

What most people miss is how K3s manages its embedded SQLite database for single-node clusters. When you run k3s server without any specific database flags, it defaults to using SQLite, storing its data in /var/lib/rancher/k3s/server/db/k3s.db. This file is essentially your entire cluster’s state – all Kubernetes objects, configurations, and secrets. If this file gets corrupted or accidentally deleted, your cluster is gone. For production, you’d typically configure K3s to use an external PostgreSQL or etcd for resilience, or run K3s in a multi-node HA configuration where the embedded database is clustered.

The next step in your K3s journey is exploring its ingress capabilities with Traefik and how to manage persistent storage for stateful applications.

Want structured learning?

Take the full K3s course →