# k3s Lightweight Kubernetes for Indonesian Startups: Production Setup on Budget VPS

> A practical guide to running a production k3s Kubernetes cluster on Indonesian VPS providers, covering the node sizes k3s actually documents, installation, ingress after the ingress-nginx retirement, TLS, Longhorn storage, upgrades and monitoring, and the trade-offs against managed Kubernetes.

URL: https://www.matthewswong.com/en/blog/kubernetes-k3s-production-lightweight-indonesia/

- Author: Matthews Wong (https://www.matthewswong.com/en/about/)
- Published: 2026-03-28
- Updated: 2026-10-17
- Category: DevOps

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.

### Configuring 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.

> **Configure TLS Before Exposing Services to the Internet**

> 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.

## 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.

### 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.

## 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.

### 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.

## 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.

> **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.

## Source links

- https://docs.k3s.io/
- https://longhorn.io/docs/
- https://kubernetes.io/docs/concepts/overview/components/
- https://idcloudhost.com/blog/kubernetes-untuk-pemula/
- https://docs.k3s.io/installation/requirements
- https://docs.k3s.io/reference/resource-profiling
- https://docs.k3s.io/upgrades/automated
- https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
- https://kubernetes.io/releases/
- https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/
- https://longhorn.io/docs/1.13.0/best-practices/
- https://cloud.google.com/kubernetes-engine/pricing
- https://docs.digitalocean.com/products/kubernetes/details/pricing/

## FAQ

### Why choose k3s over full Kubernetes (kubeadm) for a budget VPS in Indonesia?

Not because the server is smaller: the k3s docs list 2 CPU cores and 2 GB of RAM as the server minimum, while kubeadm asks for 2 GB on every machine and 2 CPUs on control-plane machines. The difference is on the workers, where a k3s agent needs 1 core and 512 MB, and in operations, since k3s ships as one binary with its datastore, ingress controller, and load balancer bundled. It also avoids managed Kubernetes fees, though those are often small: GKE's free tier covers one zonal or Autopilot cluster per billing account, and DigitalOcean includes the DOKS control plane at no cost.

### Is k3s a fully compliant Kubernetes distribution or a cut-down alternative?

k3s is a conformant Kubernetes distribution and submits CNCF conformance results for each Kubernetes minor version, so standard kubectl commands and manifests work without modification. Today it removes only the in-tree storage drivers and the in-tree cloud provider, both replaceable with CSI drivers and cloud controller managers. Early releases removed more, which is why older articles describe it as more stripped down.

### How does Longhorn solve the data-loss risk of k3s's default storage?

k3s's local-path-provisioner keeps a PersistentVolume on the disk of the node where the pod runs, so losing that node loses the data. Longhorn replicates volumes across nodes so a pod can be rescheduled to a healthy node, and it plugs in as a StorageClass. Its default replica count is 3, and Longhorn recommends 3 when you have three or more storage nodes and 2 otherwise. Longhorn's documentation recommends nodes with at least 4 vCPUs and 4 GiB of RAM, so check that your VPS sizes qualify.

### How can k3s be upgraded without causing downtime for running applications?

Install Rancher's system-upgrade-controller and create Plan resources that target a version or a release channel such as stable; the example plans upgrade servers first, then agents, one node at a time with the node cordoned. Enable draining in the plan and give each application at least 2 replicas and a PodDisruptionBudget so it keeps serving while a node is upgraded. Never skip a Kubernetes minor version, because the controller does not block an unsupported jump.

### What is the recommended approach for TLS and persistent storage before exposing services publicly?

Install cert-manager at a pinned version and configure a ClusterIssuer with Let's Encrypt before creating any public Ingress or Gateway resources, because k3s's bundled Traefik does not provision certificates on its own and services without TLS send session cookies in plaintext. For storage, move stateful workloads to Longhorn only if your nodes meet its recommended hardware, and configure a backup target such as an S3-compatible bucket or an NFS share. On smaller nodes, use local-path volumes with tested backups or a managed database.

---

- HTML version: https://www.matthewswong.com/en/blog/kubernetes-k3s-production-lightweight-indonesia/
- Bahasa Indonesia: https://www.matthewswong.com/id/blog/kubernetes-k3s-production-lightweight-indonesia/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
