DarDevOps ·DarDev Team · 5 min read

Resource limits and requests: defaults for SMEs

Starting CPU and memory requests and limits for k3s clusters running a handful of services—defaults DarDev uses with SME teams before tuning from metrics.

Kubernetes resource requests and limits dashboard for a small k3s cluster

Kubernetes resource requests tell the scheduler how much CPU and memory to reserve for a pod; limits cap how much a container can consume before the kernel throttles CPU or kills the process for memory. On a single-node k3s cluster—the setup many SMEs start with—you still need both fields on every production workload, or one noisy neighbor can evict your API while a batch job spikes.

DarDevOps runs k3s for SME pilots across MENA. The defaults below suit three to eight services on one or two nodes. Measure with Prometheus, adjust quarterly, and keep staging limits aligned with production.

Requests vs limits in plain language

Requests are the reservation. The scheduler uses them to decide which node fits the pod. Limits are the ceiling. If a container exceeds its memory limit, Linux OOM-kills it. If it exceeds its CPU limit, the cgroup throttles it—latency rises instead of a clean restart.

Setting limits without requests drops QoS to BestEffort—the first pods evicted under memory pressure. Always set requests; set limits on every production container.

Starter defaults for k3s SME workloads

These values assume 8 vCPU and 16 GiB RAM with k3s, ingress, Postgres, Redis, and two to four app Deployments. Leave 15% headroom for kube-system and metrics-server.

  • Stateless HTTP API (Node, Go, or similar): requests 100m CPU / 256Mi memory; limits 500m CPU / 512Mi memory
  • Background worker or queue consumer: requests 100m / 256Mi; limits 1000m / 1Gi (burst CPU OK, watch memory)
  • Redis cache: requests 100m / 256Mi; limits 500m / 512Mi; add persistence only if you accept restart data loss
  • Postgres (single replica on k3s): requests 250m / 1Gi; limits 2000m / 2Gi; prefer managed Postgres when RPO matters
  • Ingress controller (Traefik bundled with k3s): requests 50m / 128Mi; limits 500m / 256Mi
  • Metrics exporters: requests 50m / 64Mi; limits 200m / 128Mi

JVM and.NET APIs often need 512Mi request and 1Gi limit after profiling a cold start. Read container_memory_working_set_bytes under load instead of copying cloud "small" tiers.

Quality of Service and why it matters on one node

Guaranteed QoS (requests equal limits) survives eviction longest. Burstable works for APIs with headroom. BestEffort pods—no requests—disappear first on a crowded k3s node. Put production APIs and databases in Guaranteed or tight Burstable; cap CronJob limits so batch work cannot starve the API.

Namespace quotas before you add the tenth Deployment

ResourceQuota caps total requests per namespace; LimitRange injects defaults when YAML omits resources. Split staging and production even on one cluster—staging 4 CPU / 8Gi requests, production 6 CPU / 12Gi is a workable SME split. Pair quotas with staging environments that match production or load tests lie.

Tune from metrics, not guesses

After two weeks of traffic, raise requests to p95 CPU and memory plus buffer; set memory limits at p99 or 20% above peak working set. Fix OOMKilled workers before the API. Alert on throttling and pressure—monitoring deploy health with Prometheus lists PromQL we use after rollouts. Manual quarterly review beats VPA until you exceed roughly fifteen pods.

k3s-specific notes for SME operators

  • k3s bundles Traefik, local-path storage, and ServiceLB—budget resources for kube-system separately from app namespaces
  • Single-node clusters have no real failure domain; limits protect against process-level leaks, not node loss
  • Embedded SQLite or single-replica Postgres on the same node as the API doubles memory pressure—watch combined requests vs node capacity
  • Disable unused bundled components (e.g. servicelb if you use host nginx) to reclaim CPU for workloads
  • Control plane restarts during upgrades—Guaranteed QoS on critical pods reduces reschedule risk
kubectl top pods output beside a Grafana panel showing container memory working set
Compare kubectl top with Prometheus history before changing limits—spot checks miss weekend batch peaks.

Common mistakes we see in reviews

  • Identical limits in staging and production without identical load—staging starves or production over-provisions
  • Memory limit equal to request on JVM apps—GC spikes cause restarts; leave headroom
  • No limits on workers that parse uploads—one large file OOMs the node
  • Copying hyperscaler "small" pod sizes onto a 4 GiB VPS—scheduler pending forever
  • Frozen day-one requests after traffic growth

Start with the table defaults, add namespace quotas, then iterate from metrics. DarDevOps applies these patterns on k3s and managed clusters before recommending heavier autoscaling—platform overview and contact paths live at dardev.net/products.

Do I need limits if I trust my developers?

Yes. Limits protect the node from runaway memory in one container—bad input, dependency leak, or stuck goroutine. Requests protect everyone else from scheduling onto an already full node. Trust is not a cgroup policy.

What if I omit CPU limits entirely?

Many teams set CPU requests but leave limits unset so APIs are not throttled under burst. Keep memory limits—they prevent a single pod from taking down k3s on a small VPS. Revisit CPU limits if noisy neighbors appear in kubectl top.

How much headroom should a single k3s node keep free?

Target sum of memory requests at 80–85% of allocatable memory after kube-system. CPU requests can sit higher because not every pod peaks simultaneously, but leave room for system daemons and image pulls during rollouts.

Should Postgres run inside k3s for an SME?

For pilots and internal tools, a single Postgres Deployment with the limits above is acceptable if backups and restore are tested. For customer-facing RPO requirements, managed Postgres or a dedicated VM reduces blast radius—limits do not replace durability planning.

When should we move from k3s to a multi-node cluster?

When resource quotas block routine deploys, node CPU sustained above 70% with raised requests, or you need pod disruption budgets across failure domains. Until then, disciplined requests and limits on k3s beat an under-resourced three-node cluster with no quotas.

Get company news

Releases and announcements — confirm from your inbox.

Subscribe to updates