K3s on Raspberry Pi makes running a full Kubernetes cluster on low-power, inexpensive ARM64 devices a reality.

Here’s a K3s cluster running on three Raspberry Pis:

# On the master node:
curl -sfL https://get.k3s.io | sh -

# On each agent node:
curl -sfL https://get.k3s.io | K3S_URL=https://<master_ip>:6443 K3S_TOKEN=<node_token> sh -

This setup allows you to experiment with Kubernetes, deploy lightweight applications, or even build a small home lab. The master node acts as the control plane, managing the cluster, while the agent nodes run your workloads.

The magic of K3s lies in its minimal footprint. It bundles essential Kubernetes components into a single binary, reducing dependencies and simplifying installation. For Raspberry Pi, this means less RAM and CPU overhead, making it feasible to run on devices with as little as 1GB of RAM.

Let’s break down how it works internally. K3s uses SQLite as its default datastore, which is efficient for smaller clusters. For larger or more resilient deployments, it can be configured to use external databases like etcd, PostgreSQL, or MySQL. The K3s server process combines the Kubernetes API server, controller manager, scheduler, and etcd (if using the default SQLite). The K3s agent (kubelet and kube-proxy) connects to the server, registers itself as a node, and begins accepting pods.

The K3S_URL environment variable points the agent to the master node’s API server, and K3S_TOKEN is the shared secret that authenticates the agent to the cluster. You can retrieve the node_token from the master node at /var/lib/rancher/k3s/server/node-token.

When you deploy an application, say a simple Nginx deployment:

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

You apply this using kubectl apply -f nginx-deployment.yaml. The K3s API server receives this request, the scheduler assigns the pods to available agent nodes, and the kubelet on those nodes pulls the Nginx image and starts the containers.

The primary levers you control are the Kubernetes resources themselves: Deployments, Services, Ingress, ConfigMaps, Secrets, etc. K3s also offers some cluster-level configurations, such as enabling the Traefik Ingress controller (enabled by default), setting up a different datastore, or configuring network plugins. For instance, to specify a custom datastore:

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--datastore-endpoint 'postgres://user:password@host:port/database'" sh -

A common point of confusion is how K3s handles storage. By default, it uses local storage on each node. For persistent data, you’ll want to explore CSI (Container Storage Interface) drivers. K3s ships with a local-path-provisioner that creates persistent volumes from directories on the host. For more robust solutions, you might integrate with network storage like NFS or cloud provider storage if your Pis are connected to one.

The next concept to explore is setting up a more resilient cluster, perhaps by using an external etcd cluster or a managed database for your K3s datastore, and understanding how to manage node failures.

Want structured learning?

Take the full K3s course →