CFN Cloud
Cloud Future New Life
en zh
2025-10-03 · 0 views

Build a Cluster Quickly with K3s

A lightweight Kubernetes distribution with a one-line install.

K3s is a lightweight Kubernetes distribution that removes many of the heavy defaults while keeping the core API experience. It bundles containerd, flannel, and a simple storage provisioner, so you can stand up a cluster in minutes for labs, edge, or small staging environments.

This quick start focuses on the practical steps you actually need: install, join a worker, confirm the cluster is healthy, and run a small workload. It also includes the common pitfalls that usually slow people down on day one.

Why K3s

  • Small footprint with sane defaults for edge and lab clusters.
  • Faster bootstrap when you do not need a large control plane footprint.
  • Compatible with standard Kubernetes YAML and tooling.

Prerequisites

  • 64-bit Linux host, 2 CPU cores and 2-4GB memory for a starter control plane.
  • Ports open between nodes: 6443 (Kubernetes API) and 8472/udp (flannel VXLAN).
  • If you have strict firewalls, allow 10250 for kubelet metrics and 2379-2380 if you enable embedded etcd.
  • curl and systemd available on the host.

Sizing and expectations

K3s is still Kubernetes, so the control plane benefits from stable CPU and IO. For a single-node demo, 2 cores and 2GB RAM can work, but you will feel pressure as you add more Pods. For a small team test environment, 4 cores and 8GB RAM is a safer baseline, especially if you run monitoring stacks or CI jobs.

Plan the cluster as if it can be thrown away. If you are using the default embedded SQLite datastore, treat the cluster as a fast lab, not a production system. For production or high availability, you should switch to embedded etcd or an external datastore.

If you plan to run build or test workloads, consider a dedicated worker node for those jobs. Build containers often consume CPU and disk aggressively and can make the control plane feel unstable. A simple separation between control plane and build nodes keeps the API responsive.

Install the control plane

The default install brings up a single-server control plane with containerd and flannel.

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

Check service status and logs:

sudo systemctl status k3s
sudo journalctl -u k3s -n 200 --no-pager

Get kubeconfig and set your environment:

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

If you are working from a remote client, copy the file and replace 127.0.0.1 with the server IP:

scp user@<server-ip>:/etc/rancher/k3s/k3s.yaml ~/.kube/k3s.yaml
sed -i 's/127.0.0.1/<server-ip>/g' ~/.kube/k3s.yaml
export KUBECONFIG=~/.kube/k3s.yaml

Basic configuration file

K3s reads /etc/rancher/k3s/config.yaml if present. This is where you pin cluster CIDRs or disable built-in components.

# /etc/rancher/k3s/config.yaml
write-kubeconfig-mode: "0644"
cluster-cidr: "10.42.0.0/16"
service-cidr: "10.43.0.0/16"
disable:
  - traefik
  - metrics-server

After editing, restart the service:

sudo systemctl restart k3s

Control plane datastore and HA

By default, K3s uses an embedded SQLite database, which is great for simplicity but not ideal for HA. If you need multiple servers, look at embedded etcd support and follow the official HA guide. In practice, start with a single-server cluster, learn the operational surface area, and then design a multi-server control plane only when you have a clear reliability requirement.

When you move beyond a single server, plan for backups. A simple approach is to snapshot the datastore before upgrades and keep at least a few recovery points.

Join a worker node

Grab the server token and install the agent on another node:

sudo cat /var/lib/rancher/k3s/server/node-token
curl -sfL https://get.k3s.io | K3S_URL=https://<server-ip>:6443 K3S_TOKEN=<token> sh -

Verify that the node joins:

kubectl get nodes -o wide

Storage: local-path provisioner

K3s ships with local-path-provisioner, which is perfect for quick testing. Create a PVC and see it bind automatically:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
kubectl apply -f pvc.yaml
kubectl get pvc

Deploy a sample workload

Deploy a small web server and expose it:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: web
        image: nginx:1.27
        ports:
        - containerPort: 80
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 80
kubectl apply -f deploy.yaml
kubectl apply -f svc.yaml
kubectl get pods -o wide
kubectl port-forward svc/hello 8080:80

Open http://localhost:8080 in your browser to verify the service.

Ingress and add-ons

K3s ships with Traefik by default. If you disable it, you can install another ingress controller, such as NGINX Ingress, using the standard Helm chart. The key idea is that you should pick one ingress controller and make sure the Service type and DNS configuration match your environment.

You can also decide whether to keep metrics-server in a tiny lab cluster. It is useful for kubectl top and basic autoscaling tests, but it adds resource overhead. If you disable it, remember that HPA will not work without metrics.

Service exposure patterns

For quick demos, kubectl port-forward is the safest and least intrusive option. It does not require cluster-wide networking changes and keeps services private. If you want other machines to reach a workload, use a NodePort service and open the port on the node firewall. For more realistic setups, pair an ingress controller with a DNS name and TLS so you can test host-based routing and certificates.

In edge environments, you might prefer host networking for simplicity, but that couples the Pod directly to node ports and can cause conflicts. Start with Service and Ingress patterns unless you have a strong reason to break out of the cluster network model.

Access control basics

The kubeconfig file grants full access, so keep it private. Set restrictive permissions on /etc/rancher/k3s/k3s.yaml and avoid copying it into shared locations. For multi-user environments, create dedicated service accounts and kubeconfigs with least privilege.

If a token or kubeconfig leaks, rotate it immediately and rejoin agents with a new token to reduce exposure.

Verify and troubleshoot

Start with a quick inventory:

kubectl get nodes
kubectl get pods -A
kubectl get events -A

If nodes are NotReady, check:

  • journalctl -u k3s on the server and journalctl -u k3s-agent on the worker.
  • Firewall rules for 6443 and 8472/udp.
  • DNS issues in kube-system (CoreDNS pods should be Running).

If Pods are Pending, confirm storage and resource requests:

kubectl describe pod <pod-name>
kubectl get pvc,pv

Operational tips

  • Label nodes early so you can target workloads with nodeSelector or affinity rules.
  • Use namespaces to separate experiments and avoid leaking test workloads into production-like areas.
  • Keep your image pulls efficient; cache frequently used images on nodes if bandwidth is limited.
  • Track the cluster version and only upgrade after you read the K3s release notes for breaking changes.

Uninstall

On the server:

sudo /usr/local/bin/k3s-uninstall.sh

On the agent:

sudo /usr/local/bin/k3s-agent-uninstall.sh

Quick checklist

  • The resource matches the intent you described in YAML.
  • Namespaces, RBAC, and images are correct for the target environment.
  • Health checks and logs are in place before promotion.
  • Networking ports are open between nodes.

References