Skip to content

Docker metrics reference (ARM64 + cgroup v2)

docker-exporter exposes per-container CPU, memory, network, disk I/O, state, and health as Prometheus text at /metrics — including container_memory_working_set_bytes computed correctly on ARM64 + cgroup v2 (Raspberry Pi 5). Metric names are cAdvisor-compatible, so existing Grafana dashboards work unchanged.

All per-container metrics carry the base labels id, image, and name. Some add extra labels, noted below.

Exporter

MetricTypeLabelsDescription
docker_exporter_upgaugeDocker daemon reachable (1 = up, 0 = down).
docker_exporter_scrape_duration_secondsgaugeDuration of the last scrape, in seconds.
docker_exporter_inspect_failures_totalcounterTotal container-inspect failures since start.
docker_exporter_stats_failures_totalcounterTotal container-stats fetch failures since start.

Alert on both failure counters. docker_exporter_up only tells you the daemon answered the container list — a scrape can be up and still be lying. When an inspect fails, that container's health and restart_policy read unknown; when a stats fetch fails, its cpu/memory/network series report 0 rather than disappearing, which is indistinguishable from a genuinely idle container.

promql
rate(docker_exporter_inspect_failures_total[5m]) > 0
rate(docker_exporter_stats_failures_total[5m]) > 0

CPU

MetricTypeLabelsDescription
container_cpu_usage_seconds_totalcounterid, image, nameCumulative CPU usage in seconds.

Memory

MetricTypeLabelsDescription
container_memory_usage_bytesgaugeid, image, nameCurrent memory usage in bytes (includes cache).
container_memory_working_set_bytesgaugeid, image, nameWorking set: usage − inactive_file (v2), usage − cache (v1).
container_memory_cachegaugeid, image, nameCache: inactive_file (v2), cache (v1).
container_memory_limit_bytesgaugeid, image, nameMemory limit in bytes.

container_memory_working_set_bytes is the metric cAdvisor reports as zero on ARM64 + cgroup v2 — a known upstream bug (cAdvisor #3469, closed "not planned" 2025-12-09). It matches what docker stats reports. Why cAdvisor gets it wrong →

See the full docker-exporter vs. cAdvisor comparison → for footprint and metric-coverage differences.

Network

MetricTypeLabelsDescription
container_network_receive_bytes_totalcounterid, image, name, interfaceCumulative network bytes received.
container_network_transmit_bytes_totalcounterid, image, name, interfaceCumulative network bytes transmitted.

Disk I/O

MetricTypeLabelsDescription
container_blkio_device_usage_totalcounterid, image, name, operationCumulative block I/O bytes (operation = read/write).

Block I/O metrics emit only after a container reports non-zero bytes — containers that never touch disk produce no blkio series, keeping cardinality down.

State, health & lifecycle

MetricTypeLabelsDescription
container_stategaugeid, image, name, state, restart_policy1 if state == "running", 0 otherwise.
container_exit_codegaugeid, image, name, restart_policyExit code of a container in a terminal state (exited/dead).
container_health_statusgaugeid, image, name, status1 for the container's current health status.
container_start_time_secondsgaugeid, image, nameContainer creation time as a Unix timestamp.
container_last_seengaugeid, image, nameLast scrape time as a Unix timestamp.
  • restart_policy lives only on container_state and container_exit_code — adding it to every family would multiply series counts for no benefit. It lets alerting exclude one-shot containers by label — e.g. select container_state{restart_policy!="no"} in a ContainerStopped alert instead of maintaining a name denylist.
  • container_exit_code is the failure signal for one-shot containers (restart: "no" migrations, batch jobs). container_state collapses to 0 for anything not running and cannot tell Exited(0) from Exited(1), so a job that ran and failed looks exactly like one that ran and succeeded. The value is the raw code — 137 (OOM/SIGKILL), 1, 78 — because the number is the diagnosis.
    • Emitted only for exited/dead containers. A running container's inspect reports ExitCode: 0, and a created one has never run; publishing either would read as "succeeded".
    • Absent, never 0, when the inspect fails — the exporter has no exit code to report and will not invent one. docker_exporter_inspect_failures_total is the signal for that case.
    • The series appears when a one-shot finishes and disappears when the container is replaced, so container_exit_code{restart_policy="no"} != 0 resolves on redeploy.
  • container_health_status emits one series per container, with status set to the current Docker health (healthy, unhealthy, starting, or none when the container has no HEALTHCHECK).

Endpoints

PathDescription
/metricsPrometheus exposition (text/plain; version=0.0.4; charset=utf-8).
/healthLiveness — 200 ok if the Docker daemon is reachable.
/readyReadiness — 200 ready if the Docker daemon is reachable.

The image ships a HEALTHCHECK that runs the binary's built-in --health flag — a lightweight TCP liveness probe against its own listening port (no shell or wget, so it works on distroless) — so docker ps shows health out of the box. That probe only confirms the HTTP server is accepting connections; the /health endpoint additionally pings the Docker daemon and returns 503 if it is unreachable.

Sample output

Trimmed to a few lines, container names anonymized:

text
# HELP docker_exporter_up Whether the Docker daemon is reachable (1 = up, 0 = down)
# TYPE docker_exporter_up gauge
docker_exporter_up 1
# TYPE docker_exporter_scrape_duration_seconds gauge
docker_exporter_scrape_duration_seconds 2.18
# TYPE container_cpu_usage_seconds_total counter
container_cpu_usage_seconds_total{id="abc...",image="nginx:alpine",name="web-app"} 145.26
# TYPE container_memory_working_set_bytes gauge
container_memory_working_set_bytes{id="abc...",image="nginx:alpine",name="web-app"} 37371904
# TYPE container_state gauge
container_state{id="abc...",image="nginx:alpine",name="web-app",state="running",restart_policy="unless-stopped"} 1
# TYPE container_exit_code gauge
container_exit_code{id="def...",image="myapp/migrate:1.4",name="db-migrate",restart_policy="no"} 1
# TYPE container_health_status gauge
container_health_status{id="abc...",image="nginx:alpine",name="web-app",status="healthy"} 1

Stability

Metric names and labels follow SemVer. Any breaking change to a metric name or label requires a major version bump — none are planned.

Next