Sign inSign up

cplieger/registry-stats

By cplieger

Updated about 14 hours ago

Track how many times your container images are pulled — with a ready-made Grafana dashboard

Image
Developer tools
Monitoring & observability
Web analytics
0

10K+

cplieger/registry-stats repository overview

registry-stats

Track how many times your container images are pulled, with a ready-made Grafana dashboard.

What it does

When you publish a container image to Docker Hub or GitHub Container Registry (GHCR), each registry tracks how many times that image has been downloaded, but there's no built-in way to see those numbers over time, compare trends, or get alerts. Registry Stats solves this by polling the registries on a schedule and exposing the download counts as Prometheus metrics for dashboards and alerting.

  • Prometheus metrics (/metrics): pull counts as gauges, scraped by any Prometheus-compatible collector for native Grafana dashboards
  • Supports both explicit repos (myuser/myapp) and owner wildcards (myuser/*) to discover public repos on each poll. Docker Hub wildcards collect up to 198 repositories per owner: its unauthenticated API refuses offsets of 100 or more, so Registry Stats reads two pages of 99. GHCR wildcards read up to fifty listing pages, about 1,500 packages as GitHub currently paginates them; reaching that cap logs a truncation warning. Each poll logs the collected count, and the advertised total where the registry publishes one.
Why this design
  • Stateless: no on-disk persistence required. The app exposes current counts; time-series history lives in your Prometheus/Mimir backend.
  • Minimal dependencies: the only runtime dependencies are the maintainer's own httpx, health, metrics, webhttp, scheduler, slogx, envx, and runesafe libraries, which supply retry/backoff, the health probe, Prometheus exposition, the HTTP server lifecycle, the poll loop, UTC logging, environment parsing, and the bound on scraped text reaching the log stream. Small, auditable supply chain.
  • Distroless, rootless container: runs as nonroot on gcr.io/distroless/static-debian13 with no shell or package manager, minimising attack surface.
  • Public repos only: avoids credential management entirely.
Limitations
  • Public repositories only. Docker Hub uses the unauthenticated API. GHCR download counts are scraped from public package pages. Private repositories and packages are not supported.
  • GHCR scraping is fragile. Download counts and package listings are extracted from GitHub's HTML, not an official API. If GitHub changes their page structure, scraping will break. The container logs a clear error with a link to open an issue when this happens.
  • No historical backfill. The registries only expose current totals. Time-series data is built by your Prometheus backend as scrapes accumulate.

Pull

docker pull cplieger/registry-stats:latest

Also published to ghcr.io/cplieger/registry-stats with identical images and tags. Release versions are tagged vX.Y.Z alongside latest.

Quick start

# Example compose for registry-stats. See the README for all configuration options and hardening.
services:
  registry-stats:
    image: ghcr.io/cplieger/registry-stats:latest
    container_name: registry-stats
    restart: unless-stopped

    environment:
      # Set at least one repo; leaving both empty makes the container report unhealthy after the first collect.
      DOCKERHUB_REPOS: ""  # owner/repo or owner/* format, comma-separated
      GHCR_REPOS: ""  # owner/package or owner/* format, comma-separated
      POLL_INTERVAL_HOURS: "1"  # 0 = collect once then serve

    ports:
      # This endpoint has no authentication, so the example publishes it to this host only.
      # For a collector on another host, publish on that trusted interface: "192.168.1.10:9100:9100", never "9100:9100".
      - "127.0.0.1:9100:9100"

Documentation

License

GPL-3.0-or-later. See LICENSE. The image carries the license text of every bundled component under /usr/share/licenses/.

Tag summary

Content type

Image

Digest

sha256:d8cf52268

Size

4.1 MB

Last updated

about 14 hours ago

docker pull cplieger/registry-stats