ci: publish rustunnel-server image to GHCR on release tags#91
Merged
Conversation
Wire up multi-arch container publishing so every stable `vX.Y.Z` tag builds `deploy/Dockerfile` and pushes `ghcr.io/joaoh82/rustunnel-server:X.Y.Z` plus `:latest`. Closes the gap where the README promised a Docker deployment but no published image existed anywhere (TUNNEL-20). - New reusable workflow `release-docker.yml` (modeled on publish-mcp-image.yml): QEMU + buildx, linux/amd64 + linux/arm64, GHA layer cache, GITHUB_TOKEN auth. `:latest` only moves for stable tags; `workflow_dispatch` seeds an existing tag. - Wire it into release.yml as `publish-server-image` (needs: publish, stable-only). - Add OCI labels to deploy/Dockerfile runtime stage. image.source links the GHCR package to this repo so the package page renders the README; version/revision come from build-args. Labels are also re-asserted at the build step so seeding from an older tag still links correctly. - Add `make docker-push` (multi-arch buildx --push) + REGISTRY_IMAGE var. - README: new "Pull the published image" section (docker pull / docker run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pull Bot
pushed a commit
to Stars1233/rustunnel
that referenced
this pull request
Jun 14, 2026
The multi-arch image landed in joaoh82#91 built linux/arm64 under QEMU emulation, which compiles the full Rust server + Next.js dashboard on an emulated CPU — ~1hr+ cold, and slow on *every* release (the source changes each tag, so the emulated compile re-runs and the layer cache can't save it). Switch to the canonical native-runner pattern: build each arch on its own native runner (amd64 on ubuntu-latest, arm64 on the free ubuntu-24.04-arm runners), push each by digest, then a merge job stitches them into one multi-arch manifest list tagged :X.Y.Z (+ :latest for stable tags). No emulation — each arch compiles at native speed, in parallel. - Per-arch GHA cache scopes so the two legs don't clobber each other. - OCI labels on each arch image (build-args + labels) AND index-level annotations on the manifest in the merge job, so image.source links the GHCR package to the repo and the package page renders the README. - :latest stays stable-only (hyphen tags are pre-releases). release.yml's publish-server-image job is unchanged (same reusable-workflow call + permissions). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Wire up GHCR-driven container publishing so every stable
vX.Y.Ztag buildsdeploy/Dockerfileand pushesghcr.io/joaoh82/rustunnel-server:X.Y.Z+:latest(multi-arch:linux/amd64+linux/arm64). Closes the gap where the README promised a Docker deployment but no published image existed anywhere.Ref: TUNNEL-20 (surfaced from TUNNEL-14 § 0.3).
Changes
.github/workflows/release-docker.yml(new) — reusable workflow modeled on the existingpublish-mcp-image.yml. QEMU + buildx multi-arch build, GHA layer cache,GITHUB_TOKENauth (packages: write). Pushes the immutable:X.Y.Zalways;:latestonly moves for stable (hyphen-free) tags.workflow_dispatchlets you build an image for an already-cut tag..github/workflows/release.yml— newpublish-server-imagejob (needs: [publish], gated!contains(github.ref_name, '-'), stable-only). Runs automatically onv*tag push.deploy/Dockerfile— OCI labels on the runtime stage (source,description,licenses,version,revision,title,url,documentation).image.sourcelinks the GHCR package to this repo so the package page renders the README;version/revisioncome from build-args. Labels are also re-asserted at the build step so seeding the package from an older tag (whose Dockerfile predates these labels) still links correctly.Makefile—make docker-push(multi-archbuildx --push) +REGISTRY_IMAGEvar.README.md— new "Pull the published image" section (docker pull/docker run); the build path is now "Quick reference (build from source)".Verification
actionlintclean on both workflows (also shellchecks inlinerunscripts).deploy/Dockerfile→ exit 0, 139 MBlinux/arm64image. OCI labels resolve correctly (image.source=https://github.com/joaoh82/rustunnel,version=0.8.1, realrevision,AGPL-3.0). Entrypoint binary runs:rustunnel-server 0.8.1.make -n docker-push/docker-buildresolve correctly.Manual follow-ups after merge
v0.8.1predates this workflow, so it won't auto-build. Run once:gh workflow run release-docker.yml -f tag=v0.8.1(creates:0.8.1+:latest).docker pullworks without auth — same one-time step as the MCP image.web/seo/backlinks.md§ 2 (Docker Hub / GHCR rows) in therustunnel-webrepo once 1–2 land.🤖 Generated with Claude Code