Key Takeaway
k3s does not shrink the control-plane floor: its server minimum is 2 CPU cores and 2 GB of RAM, the RAM kubeadm asks of every machine. Its savings are 512 MB agents, one binary that bundles the datastore, ingress, and load balancer, and fewer moving parts to operate, which is what makes Kubernetes workable on Indonesian startup VPS budgets.
Upstream Kubernetes installed with kubeadm documents at least 2 GB of RAM per machine, workers included, and 2 CPUs for control-plane machines, which is a real constraint for Indonesian startups on entry-level VPS tiers at Biznet, IDCloudHost, or Hostinger (formerly Niagahoster). k3s, the lightweight Kubernetes distribution Rancher created and now a CNCF Sandbox project, documents the same 2-core, 2 GB minimum for a server node but only 1 core and 512 MB for an agent, and ships as a single binary with SQLite as its default datastore and a built-in service load balancer. This guide walks through a production-grade 3-node k3s cluster that runs real workloads.
k3s vs Full Kubernetes: What's Different
k3s keeps upstream Kubernetes conformance and today removes only two things: the in-tree storage drivers and the in-tree cloud provider, both of which have out-of-tree replacements (CSI drivers and cloud controller managers). Early k3s releases removed more, which is where older descriptions come from. It uses SQLite by default for a single server (embedded etcd for HA, or an external MySQL, MariaDB, Postgres, or etcd) and bundles containerd, Flannel CNI, CoreDNS, Traefik ingress, ServiceLB, a kube-router network policy controller, and local-path-provisioner. k3s submits CNCF conformance results for each Kubernetes minor version (1.35 through 1.37 as of 17 October 2026), so standard kubectl commands and manifests work without modification.
Resource Requirements Comparison
The k3s documentation lists a minimum of 2 CPU cores and 2 GB of RAM for a server node and 1 core and 512 MB for an agent; kubeadm asks for 2 GB of RAM on every machine and 2 CPUs on control-plane machines. So the saving is on the workers, not the control plane. k3s's own resource profiling measured a server with a test workload at about 1.6 GB of RAM at the 95th percentile, and an agent at about 275 MB. Give the server 2 GB or more and expect little headroom for workloads on it; agents can be much smaller than a kubeadm worker.
When to Choose k3s Over Managed Kubernetes
k3s is the right choice when your team has the operational capacity to manage a small cluster, your workloads fit on 3–5 nodes, and you want to stay off a single cloud vendor. The managed control-plane fee is often not the deciding cost: as listed on 17 October 2026, GKE charges a flat $0.10 per cluster per hour but its free tier credit covers one zonal or Autopilot cluster per billing account, and DigitalOcean includes the DOKS control plane at no cost, charging extra only for a high-availability control plane. What you pay for in both cases is worker nodes; with k3s you pay instead in the time your 2–5 engineers spend on upgrades, backups, and incident response.
Disable Traefik at install time (--disable traefik) if you plan to use a different ingress controller; adding the flag later also deletes the deployed Traefik. Do not reach for the community ingress-nginx controller: Kubernetes retired it in March 2026 and it gets no further releases or security fixes. The bundled Traefik v3 also supports the Gateway API, the replacement the Kubernetes project recommends. If you want MetalLB instead of k3s's ServiceLB, start every server with --disable servicelb first.
Installing k3s: Server and Agent Nodes
k3s installation is a single curl command that downloads, installs, and starts k3s as a systemd or openrc service. The server node exposes the Kubernetes API on port 6443 and stores a node token at /var/lib/rancher/k3s/server/node-token that agents use to join. For a production 3-node setup on budget VPSs, use 1 server node and 2 agent nodes: this gives workload redundancy but leaves the control plane as a single point of failure. A highly available control plane with embedded etcd needs three or more server nodes (an odd number, for quorum), or two or more servers with an external database such as MySQL or Postgres.
Server and Agent Installation Commands
The installation script accepts environment variables and flags that customize k3s without a separate config file. Passing --tls-san with your server's public IP or domain adds it as a Subject Alternative Name on the API server certificate, which kubectl needs when it connects from outside the cluster. The admin kubeconfig is owned by root with mode 600, so run kubectl on the server with sudo (or set --write-kubeconfig-mode). After the agents join, check the cluster with sudo kubectl get nodes -o wide; every node should report Ready.
#!/bin/bash
# 1. Install k3s server node (control plane)
curl -sfL https://get.k3s.io | sh -s - server \
--disable traefik \
--flannel-backend=vxlan \
--tls-san=YOUR_PUBLIC_IP
# 2. Retrieve node token for agents
K3S_TOKEN=$(sudo cat /var/lib/rancher/k3s/server/node-token)
echo "Token: $K3S_TOKEN"
# 3. Join agent nodes (run on each worker VPS; paste the token from step 2)
curl -sfL https://get.k3s.io | K3S_URL=https://SERVER_IP:6443 \
K3S_TOKEN=PASTE_NODE_TOKEN sh -
# 4. Verify cluster (the admin kubeconfig is root-owned, mode 600)
sudo kubectl get nodes -o wide
---
# sample-deployment.yaml — runs on k3s unchanged
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: nginx:1.30-alpine
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
namespace: production
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 80
type: ClusterIPConfiguring kubectl for Remote Access
k3s writes the admin kubeconfig to /etc/rancher/k3s/k3s.yaml with the server address set to 127.0.0.1. Copy it to your machine and replace 127.0.0.1 with the server's public IP or name. Point KUBECONFIG at the file, or merge it into an existing config by setting KUBECONFIG to both paths and saving the output of kubectl config view --flatten. k3s refreshes the certificates in its own copy on every start, so update your copy when they rotate. Never expose the API port (6443) publicly without IP allowlisting; restrict it to your team's addresses with a firewall rule.
Persistent Storage with Longhorn
k3s's default local-path-provisioner creates PersistentVolumes on the local disk of whichever node a pod is scheduled on; if that node fails, the data goes with it. Longhorn provides distributed block storage that replicates volumes across nodes, so a pod can be rescheduled without losing data, and it integrates as a StorageClass, so existing PersistentVolumeClaims work unchanged. Check the hardware first: Longhorn's documentation recommends at least 3 nodes with 4 vCPUs and 4 GiB of RAM each and SSD or NVMe storage, which is above the smallest budget tiers. On smaller nodes, keep stateful data on local-path volumes with tested backups, or in a managed database.
Installing and Configuring Longhorn
Longhorn installs with kubectl apply or a Helm chart; version 1.13, the current release on 17 October 2026, requires Kubernetes 1.34 or newer and, for its default V1 data engine, open-iscsi on every node, which the longhornctl preflight check verifies. The web UI is served by the longhorn-frontend ClusterIP service with no authentication by default, so reach it through kubectl port-forward or an Ingress with authentication. Longhorn's default replica count is 3, and its own guidance is to use 3 when you have three or more storage nodes and 2 otherwise. Configure a backup target (S3-compatible, NFS, SMB/CIFS, or Azure Blob Storage) for disaster recovery backups.
k3s ships with Traefik as the default ingress controller, but it does not provision TLS certificates on its own. Services exposed via Ingress without TLS send everything, session cookies included, in plaintext. Install cert-manager at a pinned version (on 17 October 2026 its docs used kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.21.2/cert-manager.yaml) and configure a ClusterIssuer with Let's Encrypt before creating any publicly accessible Ingress or Gateway resources. It is a short job that protects every service in the cluster.
CI/CD Integration with GitHub Actions
Deploying to k3s from GitHub Actions requires reaching the API server (port 6443), either by exposing it behind an allowlist or through a tunnel such as Cloudflare Tunnel or ngrok to avoid public exposure. Store the kubeconfig as a GitHub Actions secret, then use the azure/setup-kubectl action to install kubectl in your pipeline. A complete deploy workflow builds the Docker image, pushes it to a registry, updates the Deployment image tag with kubectl set image, and verifies the rollout with kubectl rollout status.
Resource Requests and Limits on Budget Nodes
On budget VPS nodes, forgetting resource requests and limits is the fastest path to an unstable cluster. Without limits, a misbehaving pod can consume all available memory and trigger the OOM killer, evicting other pods. Define requests (the amount reserved for scheduling) and limits (the hard cap) for every deployment. The manifest above starts a small web service at 64Mi requests / 128Mi limits for memory and 50m requests / 200m limits for CPU; treat those as a starting point and adjust them to measured usage.
Upgrading k3s with Zero Downtime
k3s supports automated upgrades through Rancher's system-upgrade-controller, which reads Plan custom resources that say which nodes to upgrade and to which version, or follow a release channel such as stable (v1.36.5+k3s1 on 17 October 2026). The example plans upgrade servers first, then agents, one node at a time with the node cordoned; draining is optional. Do not skip Kubernetes minor versions, because the controller will not stop an unsupported jump, and stay on a supported line: the Kubernetes project maintains the three most recent minor releases, 1.37, 1.36, and 1.35 on that date. With draining enabled, applications that have at least 2 replicas and a PodDisruptionBudget keep serving while each node is upgraded.
Pair the k3s kubeconfig with a desktop Kubernetes IDE for a GUI view of the cluster. Lens has a free Personal plan for individuals and small organizations, while larger organizations need a paid subscription; OpenLens builds stopped after Lens closed its source, and Freelens is an actively maintained, MIT-licensed open-source alternative. These tools show live CPU and memory per pod and open a shell into any container, which is often faster for debugging than raw kubectl commands.
Cost Optimization and Scaling Strategy
Cluster cost is the sum of its VPS nodes, so compare the current price lists of Biznet, IDCloudHost, or Hostinger for the sizes above: a server with at least 2 cores and 2 GB, agents sized to your workloads, and 4 vCPU / 4 GiB nodes if you run Longhorn. As your workload grows, add agent nodes incrementally by running the same join command on each new VPS. When you outgrow 5–6 nodes, migrating to a managed Kubernetes service usually becomes the better trade, as the operational overhead of managing more nodes exceeds the cost savings.
Monitoring k3s with Prometheus and Grafana
Deploy the kube-prometheus-stack Helm chart (Prometheus Operator, Grafana, and Alertmanager) for cluster observability with pre-built dashboards for node CPU, memory, disk, and workload metrics. On budget nodes, reduce Prometheus retention to 7 days and set resource requests around 200m CPU / 512Mi RAM so monitoring does not crowd out workload pods. The community Grafana dashboard 15282 (K3S cluster monitoring) adds cluster, pod, container, and systemd-service views of CPU, memory, and filesystem usage built from cAdvisor metrics.
Key terms in this article include k3s, Longhorn, etcd, and Flannel CNI.
Related Articles
- Kubernetes Deployment Strategies: Blue-Green, Canary, and Rolling Updates
- CI/CD Pipeline with GitHub Actions: From Code to Production
Sources
- k3s Official Documentation
- Longhorn — Cloud Native Distributed Block Storage
- Kubernetes — Cluster Architecture
- IDCloudHost — Panduan Kubernetes untuk Developer Indonesia
- K3s — Requirements
- K3s — Resource Profiling
- K3s — Automated Upgrades
- Kubernetes — Installing kubeadm
- Kubernetes — Releases
- Kubernetes — Ingress NGINX Retirement: What You Need to Know
- Longhorn — Best Practices (v1.13.0)
- Google Kubernetes Engine pricing
- DigitalOcean Kubernetes pricing

