Lesson 12 Prometheus, Grafana & Loki
Theme:
Lesson 12 · Slide 1

Lesson 12 — Prometheus, Grafana & Loki

You can’t operate what you can’t see. Metrics, logs, and the four golden signals for the URL shortener.

Cloud Infra & DevOps Module 5 Prometheus Observability
Lesson 12 · Slide 2

From “it deploys” to “I’d take this pager”

L09–L11 state

L09–L11 got the app running on Kubernetes with TLS. It deploys. It starts.

L12 goal

L12 makes the running app observable — you can answer “is it slow?”, “is it failing?”, “how much traffic?” without SSH-ing into a pod.

“Operability starts at the point you stop trusting kubectl logs.”
Lesson 12 · Slide 3

The three pillars (the honest version)

Tip: Start with metrics + logs. Buy tracing the day a real on-call incident says you would have saved an hour.
Lesson 12 · Slide 4

The four golden signals

Source: Google SRE Book. Every dashboard in this lesson populates exactly these four.

Lesson 12 · Slide 5

/metrics on the API

from prometheus_client import Counter, Histogram, make_wsgi_app

REQ = Counter("http_requests_total", "Requests", ["route", "code"])
LAT = Histogram("http_request_duration_seconds", "Latency", ["route"])

Counter + histogram + a WSGI /metrics route. The histogram buckets default to the Prometheus standard (5 ms → 10 s), which already covers a web API. route is the Flask endpoint name — not the URL — so cardinality stays bounded.

Lesson 12 · Slide 6

/metrics on the worker

from prometheus_client import start_http_server, Counter, Histogram

JOBS = Counter("worker_jobs_processed_total", "Jobs processed", ["outcome"])
DUR  = Histogram("worker_job_duration_seconds", "Job duration")

# In main():
start_http_server(9090)   # metrics-only sidecar port

Workers don’t have an HTTP API of their own, so they expose metrics on a dedicated port. Prometheus scrapes it via pod annotation prometheus.io/port: "9090" — no Service or Ingress needed.

Lesson 12 · Slide 7

Helm values — wiring the stack

observability:
  enabled: true   # false in dev; true in prod
  prometheus:
    scrapeInterval: 15s
  grafana:
    adminPassword: changeme   # override in prod
  loki:
    retention: 168h

A single observability.enabled: true gates the scrape annotations on both pods. In prod, swap to a managed Prometheus (AMP, Grafana Cloud) by adding remoteWrite config.

Lesson 12 · Slide 8

PromQL in 60 seconds

# 5xx error rate
rate(http_requests_total{code=~"5.."}[5m])

# p95 latency
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# request rate by route
sum by (route) (rate(http_requests_total[1m]))

Three queries covering three of the four golden signals. Saturation is container_cpu_usage_seconds_total and container_memory_working_set_bytes.

Lesson 12 · Slide 9

The alert rules

- alert: ApiHighErrorRate
  expr: sum(rate(http_requests_total{code=~"5.."}[5m]))
          / sum(rate(http_requests_total[5m])) > 0.02
  for: 10m

- alert: ApiHighLatency
  expr: histogram_quantile(0.95,
          rate(http_request_duration_seconds_bucket[5m])) > 1.0
  for: 10m

Two examples; the full file ships four. Alerts fire only after for: 10m — avoid pager-fatigue on transient blips. Never omit the for: window.

Lesson 12 · Slide 10

Loki + Promtail

Loki stores logs indexed by labels (not full-text), so you query by:

{namespace="url-shortener", pod=~"api-.*"} |= "500"

First narrow by label (cheap), then grep the matched stream (still cheap). Promtail is the DaemonSet that scrapes /var/log/pods/… and ships to Loki.

Three cardinality rules: (1) drop __path__ — it changes per pod restart; (2) never promote request-id into a label; (3) drop debug logs in production.

Lesson 12 · Slide 11

The Grafana dashboard — 6 panels

Grid layout: 2 columns × 3 rows. The dashboard JSON ships in observability/grafana-dashboards/api-golden-signals.json.

Lesson 12 · Slide 12

What we instrumented

sample-app/
  api/app.py             # + /metrics route, + REQ/LAT counters
  worker/worker.py       # + start_http_server(9090), + job counters
  helm/values.yaml       # + observability: { enabled: false } default
  helm/values-prod.yaml  # observability.enabled: true
  observability/
    prometheus-rules.yaml
    grafana-dashboards/api-golden-signals.json
    loki-values.yaml
    RUNBOOK.md
    README.md
Lesson 12 · Slide 13

What we’re not doing (yet)

Rule of thumb: instrument, alert, dashboard — in that order. Everything else waits for an incident to justify the cost.
Lesson 12 · Slide 14

Recap & what’s next

Coming up: Lesson 13 — HPAs scale the API up under load, PDBs keep capacity during node drains, blue/green is a one-line Helm values flip.