The shape
How it works
-
Identity comes from the scaffold
The
golang-servicetemplate exposes Go runtime, HTTP request count and latency (by matched route, so cardinality stays bounded) and database pool metrics. It also ships aServiceMonitorthat turns the workload's platform labels intocomponentandenvironment. A new service is scraped the moment it runs. -
Platform rules in every cluster
Recording rules join cAdvisor and kube-state-metrics to the pod labels and produce
platform:*series (CPU and memory against limits, restarts, readiness, replicas) carrying the same two labels. The labels are the membership test: no namespace or pod-name filters anywhere. -
Only the contract leaves the cluster
Each Prometheus remote-writes series that carry both labels, and nothing else. Raw Kubernetes metrics stay local.
writeRelabelConfigs: - sourceLabels: [component, environment] regex: ".+;.+" action: keep -
One store, two readers
Grafana's Service Overview dashboard and Backstage's Metrics tab both query Mimir inside the cluster. Pick a component and an environment; every panel is a plain
{component, environment}selector.
Design choices
Measure before shipping
Sending everything would have been ~268,000 series and ~9,000 samples/s, over Mimir's default limits. About 88% of it was API-server histograms nothing on the platform reads, and identical series from two clusters would have collided. The label filter sends ~100 series per environment.
Labels, not an allowlist
A newly onboarded service is included automatically, and a new dashboard panel needs no remote-write change in every environment.
Trade-off: a handful of series per service are sent that nothing visualizes yet.
Write-only from the internet
The public endpoint accepts only authenticated pushes. Each environment has its own credential, generated by Terraform and delivered through Secrets Manager, and the gateway overwrites the tenant header so a writer can't choose one. Reads never leave the management cluster.
Guests never write PromQL
Backstage's Metrics tab is public, so its backend runs a fixed set of queries. The browser supplies a component and an environment, nothing more.
A deliberately small Mimir
Single replicas and no object storage: 48 hours of metrics in memory-backed volumes. That fits clusters rebuilt every day.
Trade-off: an ingester restart loses all metrics. Long-term storage in S3 is the upgrade path.
Not built yet
- Alerting. The rules exist; there is no Alertmanager or routing.
- Workload health panels. Restarts, readiness and OOM kills are recorded but not on the dashboard yet.
- Logs. Services log structured JSON ready for Loki; nothing collects it centrally yet.