Skip to content

Publish multi-arch Docker image to GHCR and Docker Hub - #8

Merged
Lucifix merged 1 commit into
mainfrom
feature/docker-hub
Sep 15, 2026
Merged

Lucifix merged 1 commit into
mainfrom
feature/docker-hub

Conversation

@Lucifix

@Lucifix Lucifix commented Sep 15, 2026

Copy link
Copy Markdown
Owner

What does this change?

Adds .github/workflows/docker-publish.yml. On every push to main, on v*.*.* tags and on manual runs, it runs typecheck and tests. Then it builds linux/amd64 and linux/arm64 on native runners, pushes them by digest and merges them into one multi-arch manifest on ghcr.io/lucifix/model-workshop-manager. If DOCKERHUB_USERNAME/DOCKERHUB_TOKEN secrets are set, that manifest is copied to Docker Hub without a second build.

  • Tags: pushes to main get latest and sha-xxxxxxx. Release tags vX.Y.Z get X.Y.Z, X.Y and X, and never move latest.
  • docker-compose.yml now pulls the published image (APP_IMAGE_TAG, defaults to latest), so a Portainer stack or a curl'd compose file works without cloning the repo.
  • docker-compose.override.yml is picked up automatically in a repo clone and adds build:, so docker compose up -d --build still builds from source.
  • Dockerfile now sets DATABASE_URL, DATA_DIR, UPLOAD_DIR and BACKUP_DIR to the mounted paths. The app's own defaults are relative paths, so a bare docker run would otherwise write data into the container instead of the volume.
  • README: split into "pull the published image" (with a Portainer snippet) and "build from source". APP_IMAGE_TAG added to the env table.

Reviewer notes / known follow-ups

The pre-PR review found these; none are fixed in this PR:

  • A new GHCR package starts out private. After the first publish it has to be set to Public, or pulls from the README fail.
  • The README snippet's workshop-data volume has no name:, but docker-compose.yml pins one. Switching between the two gives you a different, empty volume.
  • A manual run from a branch other than main produces no tags, so the merge step fails.
  • In a clone, a local --build gets the same name as the published :latest, so a pull and a build overwrite each other.
  • The Docker Hub image name uses DOCKERHUB_USERNAME as-is, so the secret must be lowercase.

Related issue

None.

Checklist

  • Ran npm run lint:fix and npm run fmt at the repo root (fmt:check passes)
  • Added/updated backend tests for behavior changes (if applicable): n/a, infra only
  • npm run typecheck and npm run build pass: not run locally, no app code changed
  • Followed existing conventions (comments explain why not what)

Screenshots

n/a

Adds a publish workflow that tests, builds amd64/arm64 natively, merges a
multi-arch manifest on GHCR and mirrors it to Docker Hub when credentials are
set. docker-compose.yml now pulls the published image so Portainer stacks and
curl'd compose files need no clone; docker-compose.override.yml keeps
building from source in a repo checkout. Data paths are baked into the image
so a bare docker run writes to the mounted volumes.
@Lucifix
Lucifix merged commit 760a87c into main Sep 15, 2026
6 checks passed
@Lucifix
Lucifix deleted the feature/docker-hub branch September 15, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant