$linuxjunkies
>

How to Set Up Kubernetes with k3s

Set up a lightweight Kubernetes cluster with k3s on Linux: single-node or multi-node, kubectl config, and your first real deployment in under 30 minutes.

AdvancedUbuntuDebianFedoraArch12 min readUpdated June 7, 2026

Before you start

  • Root or sudo access on all nodes
  • Unique hostnames and static or stable IPs assigned to each node
  • Outbound HTTPS access to get.k3s.io and container registries
  • kubectl installed on your local workstation for remote management

k3s is a CNCF-certified, lightweight Kubernetes distribution from Rancher that ships as a single binary under 100 MB. It strips out legacy and cloud-specific drivers, bundles containerd, CoreDNS, Traefik, and a local-path storage provisioner, and runs comfortably on a 1 GB RAM server. Whether you are deploying a single-node homelab cluster or a multi-node edge setup, k3s gets you to a working Kubernetes environment in minutes rather than hours.

Prerequisites and Network Planning

Before running a single command, settle these details:

  • OS: Any modern 64-bit Linux. k3s works best on Ubuntu 22.04/24.04 LTS, Fedora 39+, or RHEL/Rocky 9. The kernel must be 5.4 or newer.
  • Resources (per node): 1 vCPU and 512 MB RAM minimum for a server node; agents can run lighter. For real workloads, 2 vCPU and 2 GB RAM is comfortable.
  • Hostnames: Set unique, stable hostnames on every node before installation—k3s registers nodes by hostname.
  • Firewall: If firewalld or ufw is active, open the ports listed below before starting k3s, or the agent nodes will not join.
  • No existing Kubernetes: Remove any prior kubeadm, minikube, or k3s installations first.

Required Ports

PortProtocolPurposeOpen On
6443TCPKubernetes API serverServer node
8472UDPFlannel VXLAN overlayAll nodes
10250TCPkubelet metricsAll nodes
51820UDPWireGuard (if enabled)All nodes

Open Ports — firewalld (Fedora/RHEL/Rocky)

sudo firewall-cmd --permanent --add-port=6443/tcp
sudo firewall-cmd --permanent --add-port=8472/udp
sudo firewall-cmd --permanent --add-port=10250/tcp
sudo firewall-cmd --reload

Open Ports — ufw (Ubuntu/Debian)

sudo ufw allow 6443/tcp
sudo ufw allow 8472/udp
sudo ufw allow 10250/tcp
sudo ufw reload

Step 1 — Install k3s on the Server Node

The official installer script pulls the latest stable release, sets up a systemd service, and writes a kubeconfig to /etc/rancher/k3s/k3s.yaml. Run this on the machine that will act as your control plane.

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

The script detects your init system (systemd), installs the k3s binary to /usr/local/bin, and enables and starts the k3s service immediately. To pin a specific version, set the environment variable before piping:

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION="v1.30.2+k3s1" sh -

Verify the Server is Running

sudo systemctl status k3s
sudo k3s kubectl get nodes

Output will show one node in Ready state with role control-plane,master. It may take 30–60 seconds to reach Ready on a slow VM.

Retrieve the Node Token

Agent nodes authenticate using a token stored on the server. Grab it now.

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

Copy this string — you will paste it on every agent node.

Step 2 — Add Agent Nodes (Multi-Node Setup)

On each machine that will act as a worker, run the installer with the K3S_URL and K3S_TOKEN variables set. Replace the placeholders with your server's IP and the token from Step 1.

curl -sfL https://get.k3s.io | \
  K3S_URL="https://<SERVER_IP>:6443" \
  K3S_TOKEN="<NODE_TOKEN>" \
  sh -

This installs and starts the k3s-agent systemd service. The agent connects to the server API, registers itself, and joins the cluster. Repeat for every additional worker node.

Confirm All Nodes Joined

Back on the server node:

sudo k3s kubectl get nodes -o wide

Every agent should appear as Ready within about a minute. If a node stays NotReady, check its agent service: sudo journalctl -u k3s-agent -f.

Step 3 — Configure kubectl on Your Workstation

k3s installs its own kubectl wrapper, but you will want the standard kubectl binary on your workstation to manage the cluster remotely.

Install kubectl

# Debian/Ubuntu
sudo apt-get install -y kubectl
# Fedora/RHEL/Rocky — kubectl is in the Kubernetes repo
sudo dnf install -y kubectl
# Arch
sudo pacman -S kubectl

Copy the Kubeconfig

k3s writes the kubeconfig to /etc/rancher/k3s/k3s.yaml with 127.0.0.1 as the server address. Copy it to your workstation and update the address to the server's actual IP.

# On the server node — print and copy the content
sudo cat /etc/rancher/k3s/k3s.yaml
# On your workstation — paste into the kubeconfig and fix the server address
mkdir -p ~/.kube
# paste or scp the file:
scp user@<SERVER_IP>:/etc/rancher/k3s/k3s.yaml ~/.kube/config
# replace 127.0.0.1 with the real server IP
sed -i 's/127\.0\.0\.1/<SERVER_IP>/g' ~/.kube/config
chmod 600 ~/.kube/config
kubectl get nodes

You should see all nodes without using sudo or the k3s prefix.

Step 4 — Deploy Your First Application

Deploy a simple Nginx web server using a Kubernetes Deployment and expose it with a Service. This confirms that scheduling, networking, and DNS all work end to end.

Create the Deployment

kubectl create deployment nginx --image=nginx:stable-alpine --replicas=2

Expose It as a NodePort Service

kubectl expose deployment nginx --type=NodePort --port=80

Check the Assigned Port

kubectl get svc nginx

The output shows a NodePort in the 30000–32767 range. Hit any node's IP on that port to reach Nginx. For example, if the port is 31240:

curl http://<ANY_NODE_IP>:31240

Watch Pod Status

kubectl get pods -o wide -w

Both replicas should reach Running status. The -o wide flag shows which node each pod landed on, useful for verifying spread across workers.

Step 5 — Deploy with a Manifest File

Imperative commands are fine for testing, but production work uses YAML manifests. Here is a complete example you can apply directly.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-k3s
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-k3s
  template:
    metadata:
      labels:
        app: hello-k3s
    spec:
      containers:
      - name: hello
        image: nginxdemos/hello:plain-text
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello-k3s
spec:
  selector:
    app: hello-k3s
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
EOF
kubectl rollout status deployment/hello-k3s

Verification and Health Checks

# Cluster component status
kubectl get componentstatuses
# All system pods — CoreDNS, Traefik, local-path-provisioner should be Running
kubectl get pods -n kube-system
# Node resource usage (requires metrics-server; k3s includes it by default)
kubectl top nodes

Troubleshooting

Agent Node Stays NotReady

Check the agent journal for TLS or connectivity errors. The most common causes are a wrong token, firewall blocking port 6443, or a clock skew greater than two minutes between nodes.

sudo journalctl -u k3s-agent --since "5 minutes ago"

Pods Stuck in Pending

Usually insufficient resources or a taint on the only node. Describe the pod to see the scheduler's reason:

kubectl describe pod <pod-name>

On a single-node cluster the server node is also a worker by default, so Pending pods are almost always a resource or image-pull issue rather than a scheduling one.

kubeconfig Permission Errors

If kubectl returns a permission denied error reading the kubeconfig, fix the file mode:

chmod 600 ~/.kube/config

Uninstalling k3s

The installer places uninstall scripts on the system. On the server:

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

On agent nodes:

sudo /usr/local/bin/k3s-agent-uninstall.sh
tested on:Ubuntu 24.04Ubuntu 22.04Rocky 9Fedora 40

Frequently asked questions

Does k3s support high-availability control plane?
Yes. k3s supports embedded etcd for HA by initializing the first server with --cluster-init and joining additional server nodes with --server. You need an odd number (3 or 5) of server nodes for quorum.
Can I use k3s with an external database instead of embedded SQLite?
Yes. Pass --datastore-endpoint with a PostgreSQL, MySQL, or etcd connection string when starting the server. This is recommended for any production or HA deployment.
Does k3s work on ARM (Raspberry Pi)?
Yes, k3s ships ARM64 and ARMv7 binaries. The installer script detects the architecture automatically. Ubuntu Server 22.04 LTS for Raspberry Pi is a well-tested combination.
How is k3s different from k0s or kubeadm?
k3s bundles all dependencies including containerd, CoreDNS, and an ingress controller into one binary and automates TLS bootstrapping. kubeadm is the upstream tool that installs full Kubernetes but requires you to manage each component separately. k0s is a similar single-binary approach but without the opinionated bundled add-ons.
How do I upgrade k3s to a newer version?
Re-run the installer script with INSTALL_K3S_VERSION set to the target version on the server first, wait for it to restart, then repeat on each agent node. The Rancher System Upgrade Controller can automate this in a cluster-native way.

Related guides