How to Install Kubernetes with k3s

Updated June 2026
k3s is a lightweight, certified Kubernetes distribution packaged as a single binary under 100 MB. It is designed for resource-constrained environments, edge computing, IoT devices, and development clusters where a full Kubernetes installation would be impractical. This guide walks through installing k3s on a Linux server, configuring kubectl, deploying workloads, adding worker nodes, and setting up storage and ingress.

k3s was created by Rancher Labs (now part of SUSE) and became a CNCF sandbox project in 2020. It passes the full Kubernetes conformance tests, meaning applications that run on standard Kubernetes will run on k3s without modification. The key differences from upstream Kubernetes are: k3s uses SQLite instead of etcd for its datastore by default (though etcd, MySQL, and PostgreSQL are also supported), it bundles containerd as its container runtime, it includes Traefik as the default ingress controller, it includes a local-path storage provisioner, and it packages the entire control plane into a single process.

Step 1: Prepare the Server and Verify Requirements

k3s runs on most Linux distributions including Ubuntu, Debian, CentOS, RHEL, SUSE, and Alpine. The minimum hardware requirements are modest: 1 CPU core and 512 MB of RAM for a server node, though 2 cores and 2 GB of RAM is recommended for running real workloads. Storage requirements depend on your workloads, but 20 GB of disk space is a reasonable starting point.

The following network ports must be accessible. Port 6443 (TCP) is the Kubernetes API server, needed for kubectl access and agent node communication. Port 8472 (UDP) is used by Flannel VXLAN for inter-node pod networking (only needed in multi-node clusters). Port 10250 (TCP) is the Kubelet metrics port. If you run k3s behind a firewall, ensure these ports are open between your cluster nodes.

k3s requires Linux kernel 4.15 or later with cgroup v1 or v2 support. Most modern Linux distributions meet this requirement. Verify with uname -r and check /sys/fs/cgroup/ for cgroup availability. If your server runs in a virtual machine, ensure the hypervisor does not restrict cgroup access.

Disable swap if it is enabled, as Kubernetes does not work reliably with swap. On Ubuntu and Debian systems, run swapoff -a and remove or comment out swap entries in /etc/fstab. k3s versions since v1.28 support cgroup v2 swap management, but disabling swap entirely remains the simpler and better-tested approach.

Step 2: Install k3s on the Server Node

k3s provides a single installation script that handles downloading the binary, creating systemd unit files, and starting the k3s service. The installation command is: curl -sfL https://get.k3s.io | sh - (from the official k3s.io site). This downloads the latest stable release, installs it to /usr/local/bin/k3s, creates a systemd service, and starts the server.

The server starts the Kubernetes API server, scheduler, controller manager, and etcd replacement (SQLite by default), along with the containerd runtime, CoreDNS for cluster DNS, Traefik for ingress, and a local-path storage provisioner. All of these run as part of the single k3s process, which keeps resource usage much lower than a standard Kubernetes installation where each component runs as a separate process.

You can customize the installation with environment variables. INSTALL_K3S_VERSION pins a specific k3s version. K3S_KUBECONFIG_MODE sets the permissions on the kubeconfig file (e.g., "644" to make it readable by non-root users). Command-line flags can be passed after a double dash in the install command to configure k3s behavior, such as --disable traefik if you want to use a different ingress controller, or --cluster-init to use embedded etcd instead of SQLite for high-availability setups.

Step 3: Configure kubectl and Verify the Cluster

k3s automatically installs kubectl as part of the k3s binary (accessible via k3s kubectl or through a symlink). The kubeconfig file is written to /etc/rancher/k3s/k3s.yaml. To use kubectl without the k3s prefix, copy this file to your user's home directory at ~/.kube/config and adjust the server address if accessing the cluster remotely.

Verify the installation by checking node status: kubectl get nodes should show your server node in a Ready state. Check system pods with kubectl get pods -n kube-system, which should show CoreDNS, Traefik, the local-path provisioner, and the metrics server all in Running status. If any pods are not running, check their logs with kubectl logs -n kube-system followed by the pod name.

For remote access from your workstation, copy the kubeconfig file to your local machine and change the server address from 127.0.0.1 to the server's public IP or hostname. Ensure port 6443 is accessible from your workstation. Many teams also set up a bastion host or VPN for secure remote cluster access rather than exposing the API server directly to the internet.

Step 4: Deploy Your First Workload

With the cluster running, deploy a test application to verify everything works end to end. The simplest approach is to create a Deployment and a Service. A Deployment manages a set of identical pods, ensuring the desired number are always running. A Service provides a stable network endpoint that routes traffic to the pods.

Create a YAML file defining a Deployment with a container image (such as nginx or a simple web application), then apply it with kubectl apply -f. Verify the pods are running with kubectl get pods. Create a Service of type ClusterIP for internal access or type NodePort to expose the application on a port on every cluster node.

For external HTTP access, Traefik (included with k3s) handles ingress routing. Create an Ingress resource that maps a hostname to your Service, and Traefik will route incoming HTTP requests accordingly. If your server has a public IP, point a DNS record to it and access your application through the hostname defined in the Ingress.

Scale the deployment by changing the replicas count with kubectl scale deployment or by updating the YAML file and reapplying it. Kubernetes distributes pods across available nodes and restarts failed pods automatically. Rolling updates are the default strategy, meaning new versions of your application are deployed gradually while old versions continue serving traffic until the new ones are healthy.

Step 5: Add Worker Nodes to the Cluster

A single-node k3s cluster is useful for development and small workloads, but production deployments benefit from separating the control plane from worker nodes. Adding a worker node to a k3s cluster requires the server's node token and the installation script run in agent mode.

The node token is stored on the server at /var/lib/rancher/k3s/server/node-token. On the worker machine, run the installation script with environment variables that point it to the server: set K3S_URL to https://server-ip:6443 and K3S_TOKEN to the node token value. The script installs k3s in agent mode, which runs only the kubelet and container runtime, not the control plane components.

After the agent starts, verify it appears in kubectl get nodes on the server. The new node will show as Ready within a minute. Kubernetes will automatically schedule pods on the new node based on available resources. You can add labels and taints to nodes to control which workloads run where, for example restricting GPU workloads to nodes with GPUs or keeping database pods on nodes with fast SSD storage.

For high availability, k3s supports multi-server clusters using embedded etcd. Initialize the first server with the --cluster-init flag, then join additional server nodes using the same mechanism as agents but with the K3S_URL pointing to the first server. A three-server cluster provides control plane redundancy, surviving the loss of one server without affecting cluster operations.

Step 6: Configure Persistent Storage and Ingress

k3s includes a local-path provisioner that creates persistent volumes backed by directories on the node's local filesystem. This is suitable for development and single-node clusters, but production workloads that need storage resilience across node failures require a distributed storage solution.

Longhorn, also created by Rancher Labs and a CNCF sandbox project, provides distributed block storage for Kubernetes. It replicates data across multiple nodes, supports snapshots and backups, and integrates with Kubernetes through standard PersistentVolumeClaim resources. Install Longhorn with kubectl apply from its official YAML manifest or via Helm, then set it as the default StorageClass to replace the local-path provisioner for new PersistentVolumeClaims.

For ingress configuration, Traefik handles HTTP and HTTPS routing by default. Create IngressRoute resources (Traefik's custom resource) or standard Kubernetes Ingress resources to define routing rules. Traefik supports automatic Let's Encrypt certificate provisioning, middleware for rate limiting and authentication, and TCP/UDP routing in addition to HTTP.

If you prefer a different ingress controller, disable Traefik during k3s installation with --disable traefik and install your preferred controller (Nginx Ingress Controller, HAProxy, or Caddy) using Helm or kubectl. The NGINX Ingress Controller is the most widely used alternative and has the broadest documentation coverage.

Key Takeaway

k3s delivers a fully conformant Kubernetes cluster in a single binary with minimal resource requirements. Installation takes minutes, and the bundled components (containerd, Traefik, CoreDNS, local-path storage) provide a working cluster out of the box. Add worker nodes with a single command and Longhorn for production storage resilience.