Files
LedgerLine/docs/roadmap/phase-6.md
T
Movses AslanyanandClaude Opus 5.5 7719ef5fcf Port the observability platform to k3s and ship czy logs to it
k8s/ is now a faithful port of the mentor's Ansible Grafana stack
(Prometheus, Alertmanager, Loki, Tempo, Alloy, Grafana, node-exporter)
for the ledgerline-observability namespace on falken: same versions and
configs, one *.vione.cloud ingress per tool behind Traefik basic auth,
secrets generated by create-secrets.sh into gitignored files.

Two fixes over the Ansible role, both verified live: Tempo's
metrics-generator needs traces_storage or it runs no processors, and
Prometheus needs exemplar-storage to keep exemplars.

Ledgerline stays on czy; an Alloy agent in the Traefik override ships
its container logs to Loki. Roadmap and CLAUDE.md now point at k8s/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:24:38 +03:30

82 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 6 — Dashboards and alerts as code
*Part of `docs/roadmap/` — see [`intro.md`](intro.md) for platform/background context and [`summary.md`](summary.md) for how every phase fits together. Prev: [`phase-5.md`](phase-5.md) · Next: [`phase-7.md`](phase-7.md)*
**Status:** Not started
**Message:** Depends on Phases 3–5 producing traces, logs and metrics worth
dashboarding.
**Time-box:** 2 evenings. This is an explicit requirement from Babak: *destroy and
recreate in seconds.*
### Concepts
- Three levels of "as code", and you should know when each applies:
1. **File provisioning** — YAML in `provisioning/datasources/` and
`provisioning/dashboards/`, plus dashboard JSON files mounted into the
container. Grafana loads them at startup. Simplest, no state, no API tokens,
perfect for a Compose demo. **This alone satisfies the requirement.**
2. **Grafana Foundation SDK** — typed libraries (Go, **Python**, TypeScript, Java,
PHP) that *generate* the dashboard JSON programmatically. Now a dashboard is a
function: `red_dashboard("ledger")`, called seven times in a loop. Reviewable
diffs, reusable panels, no 2000-line JSON blobs. Grafana now points here instead
of Grafonnet (which is legacy and unofficial).
3. **Terraform provider / Grafana Operator / Git Sync** — for state-managed,
multi-environment, or GitOps setups. Overkill here; the right answer *later*,
when this lands on your Kubernetes cluster.
- **Dashboards should answer questions, not display data.** A good service dashboard
answers, in order: is it up, is it serving, is it erroring, is it slow, and where
is the pressure. Panels that nobody looks at during an incident are cost, not value.
- **Alerts as code too.** Grafana alert rules, contact points and notification
policies all provision from YAML. And keep the *alert definition* next to the
dashboard that explains it.
### Resources
- Grafana docs → *Observability as code* (the index page — it lays out Foundation
SDK, file provisioning, Git Sync and Terraform, and tells you which to use when).
- Grafana Foundation SDK repo → the Python examples, especially the `red-method`
example.
- Udemy backbone: dashboard design sections (panel types, transformations,
variables, dashboard best practice).
### Build
Your platform provisions **datasources only** — there is no dashboards provider at
all. So this phase is entirely yours, and the right home for it is inside the
platform's own manifests (`k8s/grafana/`, the k3s port of the Ansible role),
using the same mechanism as everything else.
1. **Extend `k8s/grafana/`.** Add a file-based dashboard provider (a
`provisioning/dashboards/` YAML pointing at a mounted directory) and the
dashboard JSON. Ship both through `configMapGenerator`, exactly as
`datasources.yml` is shipped today, and mount them in `deployment.yaml`.
Two k8s-specific things to work out:
- A ConfigMap is capped at about 1 MiB, and client-side `kubectl apply`
also stores a copy in an annotation. Large generated dashboards push
against that.
- The configMap hash suffix rolls the Grafana pod on every change.
Decide whether that's what you want.
2. **Generate the JSON from code**, don't hand-write it. Use the **Grafana
Foundation SDK (Python)**: one function producing a RED dashboard for a given
service name, looped over the seven services; a second producing a system
overview (service graph, stream lag, pool saturation, error-budget burn). Commit
the generator *and* its output; `k8s/grafana/` ships the output.
3. **The demo is now `kubectl apply -k k8s/`.** Delete every dashboard through
the Grafana UI, re-apply (or go further: `kubectl delete -k k8s/` and rebuild
the whole platform), and watch them all come back.
That is a strictly stronger answer to Babak's "destroy and recreate in seconds"
than a local Makefile target, because it's the same command that builds the
platform.
4. While you're in there, review the provisioned datasources and add what's missing:
`tracesToMetrics` on Tempo (pointing at the Tempo-generated span metrics) is a
worthwhile addition, and the existing `tracesToLogsV2` has no `tags` mapping —
understand why `filterByTraceID: true` alone is sufficient here, and when it
wouldn't be.
5. Add alert rules — see Phase 8 for the Alertmanager-vs-Grafana-alerting choice.
**Done when:** `kubectl apply -k k8s/` restores every dashboard from scratch, and no
dashboard has ever been saved through the Grafana UI.