Skip to content
docktionary

Clusters & cloud

Cost optimization

A cluster's bill is mostly node hours. Almost every cost lever comes down to running fewer, better-utilized nodes, and paying less for each one.

Requests, not usage, drive the bill

The scheduler packs nodes based on what Pods request, not what they actually use. A Pod that requests 2 CPU but uses 200m still reserves 2 CPU worth of node capacity that nothing else can use — it's the single most common source of a cluster that "should" be over-provisioned but is somehow still full.

terminal
kubectl top pods --containers    # actual usage right now
kubectl describe node <node> | grep -A5 "Allocated resources"  # requested vs. capacity

Set requests close to real steady-state usage (measured, not guessed) and let limits — not requests — provide headroom for spikes.

Bin packing and pool sizing

Fewer, larger nodes generally pack better than many small ones, since every node reserves some capacity for the kubelet and system daemons regardless of size — that overhead is paid once per node, not once per Pod.

Spot / preemptible nodes

Spot instances (AWS), preemptible/Spot VMs (GCP), and Spot VMs (Azure) run at a steep discount — commonly 60–90% off on-demand — in exchange for the provider being able to reclaim them with short notice. A good fit for a node pool running stateless, horizontally scaled, interruption-tolerant workloads; a poor fit for a database's StatefulSet.

yaml
# Keep latency-sensitive or stateful workloads off the spot pool entirely
spec:
  template:
    spec:
      nodeSelector:
        cloud.google.com/gke-spot: "true"
      tolerations:
        - key: cloud.google.com/gke-spot
          operator: Equal
          value: "true"
          effect: NoSchedule

Autoscale down, aggressively but safely

A cluster autoscaler that never scales down is just a fixed-size cluster with extra steps. Pair it with a PodDisruptionBudget on anything that shouldn't lose too many replicas at once, so scale-down evictions stay safe, and check that nothing is pinning nodes open unnecessarily (a DaemonSet-only node, or Pods without a PodDisruptionBudget that the autoscaler is being conservative around).

Reserved / committed-use discounts

For the baseline load that's never going away — the minimum node count a cluster never drops below — a 1- or 3-year commitment (Reserved Instances, Committed Use Discounts, Azure Reservations) on top of autoscaling for the variable part is usually the biggest single line-item saving available, with zero application changes required.

Where to actually look first

  • Namespaces or Deployments with requests far above real usage.
  • Idle non-production clusters left running outside working hours.
  • Oversized persistent volumes provisioned once and never resized down.
  • Cross-zone or cross-region traffic between chatty services, which cloud providers meter and charge for separately from compute.