Skip to content

ADR-017 — Pin All Docker Images to Specific Versions

Generated: 2026-04-27


Decision

All Docker images in chizuru-v2 must be pinned to specific semver tags. No latest, release, or untagged image references are permitted.

Why

59% of images (32 out of 54) were running unpinned tags (latest, release, or no tag at all). This created several risks:

  • Silent breaking changes — a docker compose pull could upgrade a service with breaking changes, no rollback path, and no record of what version was previously running.
  • Non-reproducible deployments — running the same playbook twice could produce different results depending on when latest was pulled.
  • No audit trail — git history showed no version changes because the tag never changed, only the digest behind it.
  • Cascading failures — VPN infrastructure (Netbird, Gluetun) and data services (Immich, Tube-Archivist) were all on latest, meaning a bad upstream push could take down critical infra with no warning.

What Changed

32 images across 16 services were pinned to their current stable versions:

Critical Infrastructure

Service Image Pinned To
Netbird Dashboard netbirdio/dashboard v2.36.0
Netbird Management netbirdio/management v0.69.0
Netbird Signal netbirdio/signal v0.69.0
Netbird Relay netbirdio/relay v0.69.0
Coturn coturn/coturn 4.10.0-r1
Gluetun (x2) qmcgaw/gluetun v3.41.1

Data Services

Service Image Pinned To
Immich Server ghcr.io/immich-app/immich-server v2.7.5 (default)
Immich ML ghcr.io/immich-app/immich-machine-learning v2.7.5 (default)
Tube Archivist bbilly1/tubearchivist v0.5.10
Tube Archivist ES bbilly1/tubearchivist-es 8.19.0
Redis Stack redis/redis-stack-server 7.4.0-v8
Karakeep ghcr.io/karakeep-app/karakeep v0.31.0 (default)
Paperless AI clusterzx/paperless-ai 3.0.9

Applications

Service Image Pinned To
Jellyfin jellyfin/jellyfin 10.11.8
Homepage ghcr.io/gethomepage/homepage v1.12.3
Grimmory grimmory/grimmory v3.0.2
Readeck codeberg.org/readeck/readeck 0.22.3
Shoko shokoanime/server v5.3.3
ROMM rommapp/romm 4.8.1
The Archiver ghcr.io/pauljoda/the-archiver 2.3.0
Yubal ghcr.io/guillevc/yubal v0.7.2
Ladder ghcr.io/everywall/ladder v0.0.22
Byparr ghcr.io/thephaseless/byparr v2.1.0
Browserless ghcr.io/browserless/chromium v2.39.0
qBittorrent (x3) lscr.io/linuxserver/qbittorrent 5.1.4
MediaManager quay.io/maxdorninger/mediamanager 1.12.3
Jackett lscr.io/linuxserver/jackett 0.22.1764
Prowlarr lscr.io/linuxserver/prowlarr 1.35.1
PostgreSQL (mediabot) postgres 17.5

Intentionally Not Pinned

Image Reason
git.eva-00.network/homelab/navidrome-custom:latest Custom build on local Forgejo registry — user controls the image. Tag custom builds with semver when Renovate is deployed.
gtstef/filebrowser:beta File Browser Quantum fork — beta is the only available channel.

Trade-offs

  • More friction for updates — version bumps now require editing docker-compose files and committing. This is intentional — it creates an audit trail and prevents surprise upgrades.
  • Staleness risk — pinned versions can fall behind on security patches if not monitored. Mitigated by deploying Renovate (see RFC: Automated Image Updates).
  • Version lookup overhead — initial pinning required researching 32 images for their current stable tags. Future updates will be automated via Renovate PRs.

Rules Going Forward

  1. Every new service added to chizuru-v2 must use a pinned version tag.
  2. latest, release, and untagged images are not permitted in main.
  3. Version bumps happen through Renovate PRs (once deployed) or manual commits with explicit version changes.
  4. Immich and Karakeep use ${VAR:-default} syntax — the default must be a specific version, not release.
  5. Grouped services (Netbird suite, Immich server+ML) must be updated together in the same commit.