Files
homelab-gitops/docs/cpu-sizing.md
T

3.4 KiB

CPU sizing and balancing

Review on 2026-10-31

Prometheus was queried for the 95th percentile of five-minute CPU rates over its available history within the previous 14 days, sampled every 15 minutes:

quantile_over_time(0.95,
  (sum by(namespace,pod,container)
    (rate(container_cpu_usage_seconds_total{container!="",container!="POD"}[5m]))
  )[14d:15m])

The largest observed replica value was considered for shared workload sizing. New pods have shorter histories; this is not a guarantee of fourteen complete days per workload. These measurements include the recent recovery period.

The starting recommendation is p95 times 1.2, rounded upwards. Request floors are retained for startup, databases, recovery, and bursty workloads. Requests are not CPU limits. Memory requests and limits are unchanged.

Reviewed changes include Elasticsearch/Kibana, Netflow, Authentik, Traefik, InfluxDB, MKTXP, Mastodon, Paperless, scanner/PDF editor, Uptime Kuma, TURN, Home Assistant, WordPress, Grafana and Prometheus. Busy services without CPU requests receive explicit reservations. Elasticsearch retains a 500m floor per data node for startup/recovery, substantially above its measured baseline.

Matrix is still a legacy Helm release. Its canonical values live in matrix/authentication/values.yaml in the homelab workspace: the main Synapse process gets 500m, federation sender 225m, and other workers 50m. Init-container requests can make effective pod reservations higher than the main container. The shared RBD claim and worker/offload affinity remain unchanged.

Ceph daemons, the API server, Cilium, CoreDNS, Argo CD, and ingress already have no CPU limits. Their low or absent requests are not interpreted as spare physical capacity; Descheduler uses measured CPU. The legacy Ceph CSI operator CPU cap is removed in rook/deploy/examples/csi-operator.yaml. Ceph daemon resources are left alone to avoid a storage-wide restart. CPU caps are also removed from the Elastic operator/data nodes, InfluxDB, MKTXP, and TURN.

Deliberate exclusions

  • Do not infer batch, transcoding, game-server or GPU requirements from idle CPU measurements. Their explicit reservations are retained.
  • Do not resize workloads that are down or lack representative history.
  • Do not automatically rewrite operator-managed database resources or apply VPA mutation alongside Argo. This review changes owning configuration only.
  • Loops and Pixelfed charts hard-code some resource requests; overriding an unsupported values key would do nothing. Those require a separate chart interface change before their requests can be tuned through GitOps.
  • Small existing requests are retained where a reduction offers little useful headroom. The aim is schedulability and contention protection, not identical requests across applications.

Ongoing operation

Descheduler runs automatically; request changes are reviewed configuration, not a continuously mutating autoscaler. Repeat the history review after a representative week or a substantial workload change. Never set every request from a single current-usage sample. Monitor pending pods, CPU throttling, latency, and node CPU usage as well as reserved capacity.

For a new request change, render the owning chart, inspect all container/init resources, and reconcile through Argo (or the existing legacy Helm installer). Keep the prior commit as rollback; do not delete PVCs to resolve placement.