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.