The dashboard that lies
Metrics, logs and traces, and the most dangerous graph of all, the empty one. Break the watching instead of the thing being watched, and find where the truth is written.
Observability is how you find out what a system is doing without stopping it. It rests on three signals:
- Metrics: numbers over time, such as requests per second or memory used. Cheap to keep, good for graphs and alerts. On the tilt platform: Prometheus, drawn by Grafana.
- Logs: what the program said, line by line. On the platform: Loki.
- Traces: the path one request took through several services, and how long each hop took. On the platform: Tempo.
Every other lesson breaks the thing you’re watching. This one breaks the watching.
Three empty dashboards on a healthy cluster
This happened three times on the tilt platform:
- Argo CD’s monitor asked for a port named
metrics, but every Argo CD service publisheshttp-metrics. - Loki’s monitor selected the label
app: loki, but the chart had moved toapp.kubernetes.io/name. - cert-manager had no monitor at all.
Each time, Kubernetes was content, Prometheus reported nothing wrong, and eighteen panels read as a calm, healthy system.
How a scrape is wired
With the Prometheus Operator, you don’t edit Prometheus’s config. You create a ServiceMonitor, which says “scrape the Services with this label, on the port with this name”. Both are matched exactly. Get either wrong and the operator generates no scrape target, and it doesn’t consider that an error. Nothing failed, so nothing alerts.
- A ServiceMonitor names a label and a port name. Both must match a real Service exactly - "metrics" is not "http-metrics".
- The operator turns each match into a scrape target. No match, no target - and it does not count that as an error.
- Prometheus scrapes /metrics on the pods behind the Service. Its /targets page is the one place a missing target shows.
- Grafana draws what Prometheus stored. No target means an empty panel on a perfectly healthy cluster.
Existence is not freshness
Look at what the lab’s grader checks. It asserts four separate facts on purpose, because the first can pass while the other three fail:
- the ServiceMonitor exists;
- the port it names actually exists on the Service;
- Prometheus has a healthy target;
- the data is fresh: the last scrape was recent.
“There’s a series called hello” and “something scraped hello a moment ago” are different questions. Ask the second.
A Grafana panel is empty. The pods are Ready and the ServiceMonitor exists with no events. What's the quickest place to find the problem?
An empty panel usually means nothing is being scraped. Kubernetes can't tell you that, because from its point of view nothing failed. Prometheus's targets page shows what it was actually told to scrape.
A ServiceMonitor says port: metrics. The Service's port is named http and is number 9898. What happens?
ServiceMonitors name ports, not numbers. A mismatch is accepted, generates nothing, and stays silent. That's exactly the Argo CD story.
Which signal answers 'which of my five services made this one request slow?'
A trace follows one request across services with timings for each hop. Metrics give totals and logs give lines, and neither connects the hops on its own.
Everything above ran in your browser. Now do it on a real cluster with tilt lab 08-empty-dashboard (profile observability). You need Docker, kind and Tilt, about 15 GB of free disk and 8 GB of spare RAM. Setup guide · Can my machine run it?
PROFILE=observability ./scripts/platform.sh up
kubectl apply -f labs/08-empty-dashboard/servicemonitor.yaml
./scripts/platform.sh lab 08 # 4/4
./labs/08-empty-dashboard/break.sh
# open https://prometheus.localhost/targets and search for hello
./labs/08-empty-dashboard/fix.sh && ./scripts/platform.sh lab 08Sources
Missions and quizzes above earn their own XP. This marks the lesson done.