ci: publish multi-arch container image to GHCR on release#70
Merged
Conversation
Every tagged release now publishes a linux/amd64 + linux/arm64 image to ghcr.io/deveshctl/layerx alongside the existing archives, deb/rpm packages, Homebrew tap, and Scoop bucket. The image reuses the exact binary produced by GoReleaser so `layerx --version` stays identical across every install path. - Dockerfile: multi-stage build on gcr.io/distroless/static-debian12 :nonroot. Runs as uid 65532, WORKDIR /home/nonroot, exec-form ENTRYPOINT so signals reach the TUI cleanly. Per-arch binary picked from dist/layerx_linux_<arch>*/layerx via buildx TARGETARCH. - release.yml: new ghcr job (needs: goreleaser) that downloads the goreleaser-built binaries as a workflow artifact, sets up QEMU + Buildx, logs in to ghcr.io with GITHUB_TOKEN, computes tags/labels via docker/metadata-action, and pushes via docker/build-push-action with GHA cache. Tag scheme: latest, vX.Y.Z, vX.Y, vX (pre-release tags skip latest + the major/minor rollups). workflow_dispatch trigger runs the full build with push: false for dry-run testing. - README: new 'Container image' install section with Docker, Podman, and archive-mode examples, plus the --group-add note for reaching Docker's root:docker socket from the nonroot user inside a distroless image (which has no /etc/group to resolve the name). - docs/releasing.md: new file documenting the release flow and the one-time public-visibility flip required after the first GHCR publish.
docs/releasing.md is a maintainer-only runbook — its contents (cutting a tag, flipping GHCR visibility, dry-running the workflow) are only actionable by someone with push access to this repo, so shipping it in the public tree and linking to it from the user-facing README sends readers to a page that is not for them. Remove the file and the README link. Keep the one-sentence user-visible note about the first-release private-GHCR behaviour in the README, but drop the dead link to the removed doc. Update the workflow comment that pointed at the deleted file to reference the gh CLI command directly. CONTRIBUTING.md still contains a reference to docs/releasing.md; that link predates this PR and points at a file that also did not exist on main before this change, so it is a pre-existing broken link and left untouched here.
5d18e50 to
35c317d
Compare
distroless/static ships no terminfo database. Without TERM set, termenv (used by lipgloss v2) sees a dumb terminal and disables all colour output. COLORTERM=truecolor is required to activate 24-bit hex colour codes — without it, the palette defined in tui/styles.go gets quantized or dropped.
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.
Summary
Adds a
ghcrjob to the release workflow that packages the same GoReleaser-built Linux binaries into a multi-arch OCI image (linux/amd64 + linux/arm64) and pushes it toghcr.io/deveshctl/layerxon every tagged release.The image reuses the exact binary produced by GoReleaser, so
layerx --versionis bit-identical across brew, scoop, deb, rpm, direct-download, and the container image.What's in the change
Dockerfile— distroless-static:nonroot base, exec-form ENTRYPOINT, uid 65532, WORKDIR/home/nonroot. Copies the platform-specific binary out ofdist/(GoReleaser's layout) rather than building Go inside the image..github/workflows/release.yml— newghcrjob. Uploads the Linux binaries as a workflow artifact from thegoreleaserjob, downloads them, builds and pushes withdocker/build-push-actionand QEMU for arm64. Tags:latest(non-prerelease only),vX.Y.Z,vX.Y,vX. All action SHAs pinned.packages: writeis scoped to this job only.workflow_dispatchtrigger — added so the Dockerfile + buildx wiring can be dry-run on a feature branch before cutting a real tag. On dispatch, GoReleaser runs--snapshot --skip=publish --skip=sign, the SLSAprovenancejob is skipped, and the image is built withpush: false.docker run/podman runrecipes for Docker on Linux (with the--group-add \$DOCKER_GIDnote for the distroless base), Docker Desktop, rootless Podman, and archive mode. New FAQ entry on when to reach for the container vs. the native binary.docs/releasing.md— new file documenting the tag → release flow, the first-time GHCR "flip to public" step, and theworkflow_dispatchdry-run procedure.CHANGELOG.md—[Unreleased]entry.Trade-offs called out in the docs
--group-add \$DOCKER_GIDbecause the distroless base has no/etc/groupfor name resolution.xkey) writes into the container FS unless the user bind-mounts an output dir.Notes
docs/releasing.mddocuments this.