Scaling Prometheus to Production›Modules · Cheat sheet & self-check
Learning Hub / Observability & Reliability / Scaling Prometheus to Production

Modules · wrap-up

Cheat sheet & self-check

Every command from this section on one page.

01 · kube-prometheus-stack baseline

Install & inspect

helm repo add prometheus-community https://prometheus-community.github.io/helm-chartsChart repository
helm install kps prometheus-community/kube-prometheus-stack -n monitoring --create-namespaceInstall the stack
kubectl get prometheus,alertmanager,servicemonitors,podmonitors,prometheusrules -AOperator resources
kubectl port-forward -n monitoring svc/kps-kube-prometheus-stack-prometheus 9090Prometheus UI (service name depends on release name)

PromQL patterns

sum by (job) (rate(http_requests_total[5m]))Requests/s per job
sum(rate(http_requests_total{code=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))Error ratio
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))p95 latency
up == 0Targets that can't be scraped

02 · Why Prometheus doesn't scale

Find the load

prometheus_tsdb_head_seriesActive series in the head block
topk(10, count by (__name__) ({__name__=~".+"}))Metrics with the most series (expensive query)
Status → TSDB Status (web UI)Top metrics, labels and label values by series count
promtool tsdb analyze /prometheusCardinality analysis of a data directory

Stop it

metric_relabel_configs: action: labeldrop / dropDrop a label or a whole metric at scrape time
ServiceMonitor spec.sampleLimitFail a scrape that returns too many samples
Prometheus CR spec.enforcedSampleLimitA global per-scrape cap

03 · MinIO object storage

Bucket setup (mc client)

mc alias set lab https://s3.internal.example ACCESS_KEY SECRET_KEYConfigure a target
mc mb lab/thanosCreate a bucket
mc ls --recursive lab/thanos | headSee uploaded blocks
mc admin info labServer/drive health (MinIO)

Client configs

Thanos objstore: type: S3, config: { bucket, endpoint, access_key, secret_key, insecure }Thanos bucket config
Mimir: common.storage.backend: s3 (+ endpoint, bucket names per component)Mimir storage config

04 · Thanos: sidecar, store, querier

Components

thanos sidecarNext to Prometheus: uploads 2h blocks, serves recent data via StoreAPI
thanos storeServes historical blocks from the bucket via StoreAPI
thanos query --endpoint=<sidecar/store>:10901 --query.replica-label=prometheus_replicaGlobal PromQL with dedup
thanos query-frontendSplits, caches and retries queries in front of the querier
thanos receiveAccepts remote-write instead of using sidecars

Prometheus Operator

prometheusSpec.thanos.objectStorageConfig (Secret ref)Enable the sidecar with upload
prometheusSpec.externalLabels: { cluster: prod-eu-1 }Identify the source of every series
prometheusSpec.replicas: 2HA pair; operator adds prometheus_replica label

05 · Thanos: compactor, downsampling, hot/cold

Compactor

thanos compact --wait --objstore.config-file=objstore.yml --data-dir=/var/thanos/compactRun continuously (one per bucket)
--retention.resolution-raw=30d --retention.resolution-5m=180d --retention.resolution-1h=2yRetention per resolution
--deduplication.replica-label=prometheus_replicaVertical compaction: dedup HA replicas in storage
thanos_compact_halted == 1Alert: compactor stopped (e.g. overlapping blocks)

Inspect

thanos tools bucket inspect --objstore.config-file=objstore.ymlList blocks, resolutions, time ranges
thanos tools bucket web --objstore.config-file=objstore.ymlVisual block timeline

06 · Retention by data priority

Techniques

Recording rules → keep aggregates long, raw shorte.g. job:http_requests:rate5m kept for years
metricRelabelings action: drop (by __name__)Never store unused metrics
Separate Prometheus/tenant per priority tierDifferent retention per destination
Mimir per-tenant compactor_blocks_retention_periodRetention override per tenant

Find unused metrics

Grafana dashboards + rules → list of used metric namesWhat's actually queried
mimirtool analyze grafana / prometheus / rulerMimir's usage analysis tooling
Query logs (Prometheus query_log_file, query-frontend logs)Ad-hoc usage

07 · Grafana Mimir

Write path

remote_write url: http://<mimir-gateway>/api/v1/pushPrometheus → Mimir
headers: { X-Scope-OrgID: team-a }Tenant ID on every request (when multi-tenancy is on)
distributor → ingesters (replication factor 3) → blocks to object storageWhere samples go

Operate

helm install mimir grafana/mimir-distributed -n mimir --create-namespace -f values.yamlInstall (Helm repo https://grafana.github.io/helm-charts)
-target=all (monolithic) vs per-component targetsDeployment modes
runtime config overrides: ingestion_rate, max_global_series_per_userPer-tenant limits
mimirtoolRules, alertmanager config, analysis and remote-read tools

08 · Thanos vs Mimir

Quick contrast

Thanos: sidecar + querier fan-out (or Receive)Add-on to existing Prometheus; incremental adoption
Mimir: remote-write into a central clusterCentral, multi-tenant service
Downsampling: Thanos yes; Mimir noLong-range query speed vs raw fidelity
Licence: Thanos Apache-2.0; Mimir AGPLv3Check your organisation's policy

09 · Federation & multi-cluster

Federation

scrape job with metrics_path: /federate and params: { match[]: [ '{__name__=~"job:.*"}' ] }Pull aggregated series from another Prometheus
honor_labels: trueKeep the source's labels

Remote write & agents

prometheus --agent (older: --enable-feature=agent)Scrape + WAL + remote-write only; no local queries or rules
kind: PrometheusAgent (Prometheus Operator)Agent mode as a custom resource
writeRelabelConfigsChoose which series to send
prometheus_remote_storage_samples_pending / _failed_totalRemote-write health

10 · Capstone: cost, HA & the platform view

Back-of-envelope formulas

samples/s = active series ÷ scrape interval (s)500k ÷ 30 s ≈ 16.7k samples/s
bytes/day ≈ samples/s × 86,400 × ~1–2 bytes≈ 1.5–3 GB/day compressed (before replicas)
memory: measure bytes per active series on your versionPlan headroom (2× for spikes and queries)

Must-haves

HA Prometheus pairs (or agents) + dedupNo single scraper
Alertmanager cluster (3 replicas)Alerts survive a pod loss
Meta-monitoring + Watchdog to an external receiverKnow when monitoring is down