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