Files
Anthias/.github
Viktor Petersson 8041fc30e4 ci: switch primary registry to ghcr, drop legacy srly-ose namespace (#2761)
Make `ghcr.io/screenly/anthias-*` the canonical source for Anthias
container images and demote Docker Hub's `screenly/anthias-*` to a
parallel mirror during the migration window. The legacy
`screenly/srly-ose-*` namespace is dropped entirely (matrix push +
latest-* mirror). The compose templates are flipped to ghcr in the
same change so `bin/upgrade_containers.sh` regenerates with ghcr
on the next run.

Why
---

Two motivations stack:

1. Docker Hub's anonymous-pull rate limit (100 pulls / 6h per IP) bites
   end-users when a fleet of devices behind one NAT all run
   `bin/upgrade_containers.sh` at once, not just CI. GHCR has no such
   limit for public packages, and storage is free unlimited. Authed
   pushes from CI also get a much higher quota under the GitHub Actions
   token than under our shared Docker Hub bot.
2. d568602's publish-latest hit Docker Hub's 429 rate limit on retag
   #52 (`srly-ose-redis:latest-pi3`) — the legacy namespace doubled the
   manifest GETs in the loop and bought no real back-compat in
   exchange. `docker-compose.yml.tmpl` has pointed installs at
   `screenly/anthias-*` since 2023-02 (b9998438), and
   `bin/upgrade_containers.sh` regenerates compose from the template
   on every upgrade, so any device that has run an upgrade in the past
   three years is on `screenly/anthias-*` already.

What ships
----------

* `tools/image_builder/__main__.py` — `namespaces` becomes
  `['ghcr.io/screenly/anthias', 'screenly/anthias']`. GHCR is listed
  first so it's the primary push target; Docker Hub is the parallel
  mirror. The buildx matrix now pushes both `<short-hash>-<board>`
  tags to both registries on every build.
* `.github/workflows/docker-build.yaml` — adds job-scoped
  `permissions: { contents: read, packages: write }` on `buildx` and
  `publish-latest` (not at workflow level, so `run-tests` doesn't
  inherit), plus a `Login to GitHub Container Registry` step using
  `${{ github.actor }}` + `${{ secrets.GITHUB_TOKEN }}` in both jobs.
  The publish-latest mirror loop iterates over both namespaces (GHCR
  first) inside the same retry-wrapped retag block, so `latest-<board>`
  advances atomically across both registries or not at all.
* `docker/labels.j2` — new shared partial that emits the OCI image
  labels (`source`, `url`, `licenses`, `title`, `description`).
  `image.source` is the load-bearing one for GHCR: it links the
  package to its source repo, which makes the package inherit the
  repo's visibility and grants repo collaborators push/delete access.
* `docker/Dockerfile.{base,redis,viewer}.j2` — include the new
  partial. `Dockerfile.base.j2` covers server / celery /
  wifi-connect / test (which all `{% include 'Dockerfile.base.j2' %}`);
  `redis.j2` and `viewer.j2` have their own production-stage `FROM`
  so include `labels.j2` directly.
* `docker-compose.yml.tmpl`, `docker-compose.balena.yml.tmpl`,
  `docker-compose.balena.dev.yml.tmpl` — flip 15 `image:` lines from
  `screenly/anthias-*` to `ghcr.io/screenly/anthias-*`. Devices pick
  this up on next `bin/upgrade_containers.sh` (the script regenerates
  `docker-compose.yml` from the template).

Retry-with-backoff seatbelt around `imagetools` calls (originally
added in 8099a14a) is preserved.

Deployment notes
----------------

After this lands, the docker-build workflow will run on master and
publish to GHCR for the first time. Before merging, set
`Screenly`'s default-new-package visibility to "Public" at
https://github.com/organizations/Screenly/settings/packages so the
five new packages don't land private. (`org.opencontainers.image.source`
auto-links each package to this repo but does not set visibility.)

Migration-window risk: between merge and `publish-latest` completion
(~80 min), `ghcr.io/screenly/anthias-*:latest-<board>` tags don't
exist yet. Devices that run `bin/upgrade_containers.sh` in that
window will fail to pull and stay on their existing containers (no
auto-fallback to Docker Hub). They'll pull successfully on the next
upgrade attempt. To minimise impact, merge during a low-fleet-upgrade
window.

Phase 3 (months later, separate PR): stop publishing `latest-*` to
Docker Hub once enough fleet has rotated through an upgrade.
`<short-hash>-<board>` tags on Docker Hub stay around indefinitely
for explicit pins.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:50:33 +01:00
..
2022-11-29 17:23:12 +00:00
2023-03-31 15:43:25 +00:00
2020-06-15 10:34:03 +01:00
2018-08-13 17:43:45 +01:00