grafana — validation criteria
Per-image acceptance criteria for the docker.io/grafana/grafana profile.
Validated against …@sha256:5dad0df… (tag 13.0.2), derived by drop-test.
grafana already runs cap_drop: ALL in the reference deployment, so there is no
capability reduction to derive — this profile covers the filesystem dimension.
Representative workload / correctness check
profiles/workloads/grafana.sh drives real function under --read-only, not
liveness:
- /api/health reports the database is "ok";
- create a dashboard and read it back — a real sqlite write on the data volume;
- add a Loki datasource and hit its plugin health endpoint — a running backend
(go-plugin) returns a JSON verdict with a status field even when the target Loki
is unreachable; a backend that failed to start does not.
capabilities — derived by drop-test
- cap_drop: [ALL], cap_add: [] (zero-cap). grafana is a non-root service
(uid 472) on the unprivileged :3000, writing only to its
/var/lib/grafanadata store — no capability is load-bearing. All 14 Docker defaults dropped in turn (under the filesystem dimension'sread_only: true+ the data volume, per the multi-dimension rule); the workload stayed correct every time. Confidence high. - Why this is published even though the reference already drops caps: a
user running the stock
grafanaimage has Docker's default 14 capabilities and has dropped nothing, so "you cancap_drop: ALL,cap_add: []" is a real 14 → 0 reduction for them. The catalog answers the capability question for grafana, not only the filesystem one.
filesystem — derived by drop-test
- read_only: true, tmpfs: []. Under a read-only rootfs with only the
/var/lib/grafanadata volume writable, grafana serves the UI, reads/writes its sqlite DB, and runs backend datasource plugins (prometheus/Loki)./tmpwas the one plausible ephemeral tmpfs candidate and drop-tested as NOT required for this. /var/lib/grafanais a PERSISTENT VOLUME, not tmpfs. It holds grafana's sqlite DB and any installed plugins, which must survive restarts. It is supplied in the derivation as a writable stand-in (run.tmpfs) purely so the read-only rootfs is exercised; it is never part of the tmpfs minimum. Do not put it on tmpfs in a real deployment.- Pass criteria: the workload passes (health db ok + dashboard write/read-back +
a backend datasource plugin running) under
--read-onlywith/var/lib/grafanawritable and no/tmp.
Scope — when to add tmpfs: [/tmp] (confidence: moderate)
grafana's feature surface is large and this workload cannot exercise all of it, so
the minimum is the core + datasource-querying floor. A writable /tmp is
required by features not covered here — verified as real read-only-fs errors at
boot without it:
- runtime plugin installation — grafana's background installer downloads
bundled app plugins (e.g. pyroscope, exploretraces) to /tmp at startup;
- the elasticsearch datasource plugin (writes /tmp during init);
- image rendering (the renderer plugin) and CSV / report export.
A deployment that installs plugins at runtime or uses those features should add
tmpfs: [/tmp] — which is cheap and what the reference compose does conservatively.
Core dashboards + prometheus/Loki datasource querying do not need it.
Scope (run_config + out-of-band conditions)
- Invocation (
derivation.run_config): root (grafana drops to uid 472 internally), thegrafana-data:/var/lib/grafanadata volume,GF_*env,no-new-privileges,cap_drop: ALL. - Out of band (not schema fields): the reference deployment mounts provisioning
- dashboards read-only and logs to console (
mode=console), so no writable/var/log/grafanais needed; amd64. The minimum is only valid for whatprofiles/workloads/grafana.shexercises (see the moderate-confidence scope note).