-
Notifications
You must be signed in to change notification settings - Fork 0
Add arm64 release packages and multi-arch Docker images #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ usage() { | |
| echo "-h Show this screen" | ||
| echo "-t (linux|darwin) Target OS Default:(linux)" | ||
| echo "-i (systemd|sysv) Target init system Default:(systemd)" | ||
| echo "-a (amd64|386) Arch Default:(amd64)" | ||
| echo "-a (amd64|386|arm64) Arch Default:(amd64)" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The help message now includes |
||
| echo "-d debug output" | ||
| echo "-b build only, do not generate packages" | ||
| echo "-N do not build; use existing ./build/bin/orchestrator binary" | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,121 @@ | ||||||||||||||||||||||||||||
| # Releasing and publishing packages | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| `orchestrator` release artifacts are built and published automatically by the [`Release` workflow](../.github/workflows/release.yml). The workflow fires on any pushed tag matching `v*` and produces: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| - `tar.gz`, `.deb`, and `.rpm` packages attached to a GitHub Release | ||||||||||||||||||||||||||||
| - A multi-arch Docker image pushed to `ghcr.io/proxysql/orchestrator` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Both artifact sets cover `linux/amd64` and `linux/arm64`. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ## Triggering a release | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
| git tag v4.30.1 | ||||||||||||||||||||||||||||
| git push origin v4.30.1 | ||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| That's the whole trigger. The workflow picks up the tag name as the release version, strips the leading `v`, and uses `4.30.1` for package versions and Docker tags. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### Prerelease (release candidate) tags | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Tags that contain `rc` (e.g. `v4.30.1-rc1`) are handled specially: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| - The GitHub Release is marked as a prerelease. | ||||||||||||||||||||||||||||
| - The Docker `latest` tag is **not** updated — only the specific version tags are pushed. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Use this for testing the release pipeline end-to-end on a fork before cutting a real release. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ## What runs | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| The workflow has three jobs: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### 1. `build-and-release` (matrix: amd64, arm64) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Runs on `ubuntu-latest` (amd64) and `ubuntu-24.04-arm` (arm64) — GitHub's native ARM runners, free for public repos. No QEMU, no cross-compilation: each job builds on its own native architecture, so CGO (`go-sqlite3`) works without any special toolchain. | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a discrepancy between the PR description (which mentions using
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Each matrix job: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| 1. Installs Go, `fpm`, and `rpmbuild`. | ||||||||||||||||||||||||||||
| 2. Runs `./build.sh -a <goarch>` with `RELEASE_VERSION` set from the tag. | ||||||||||||||||||||||||||||
| 3. Collects everything `build.sh` writes to `/tmp/orchestrator-release/` and uploads it to the GitHub Release. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Per arch, `build.sh` produces three variants (see `package_linux` in [`build.sh`](../build.sh)): | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| - `orchestrator` — full package (binary + web resources + sample configs + systemd unit) | ||||||||||||||||||||||||||||
| - `orchestrator-cli` — binary only | ||||||||||||||||||||||||||||
| - `orchestrator-client` — the `orchestrator-client` shell script only | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Each variant is emitted as `.tar.gz`, `.deb`, and `.rpm`. Package names differ by arch (`_amd64.deb` / `_arm64.deb`, `.x86_64.rpm` / `.aarch64.rpm`), so the two matrix jobs don't collide when uploading to the same Release. | ||||||||||||||||||||||||||||
|
Comment on lines
+42
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Package formats are overstated in this section.
Suggested doc fix-Each variant is emitted as `.tar.gz`, `.deb`, and `.rpm`. Package names differ by arch (`_amd64.deb` / `_arm64.deb`, `.x86_64.rpm` / `.aarch64.rpm`), so the two matrix jobs don't collide when uploading to the same Release.
+The full `orchestrator` package is emitted as `.tar.gz`, `.deb`, and `.rpm`. The `-cli` and `-client` variants are emitted as `.deb` and `.rpm` only. Package names differ by arch (`_amd64.deb` / `_arm64.deb`, `.x86_64.rpm` / `.aarch64.rpm`), so the two matrix jobs don't collide when uploading to the same Release.🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Both matrix jobs call `softprops/action-gh-release@v2` — the action is idempotent and will attach to the existing Release created by whichever job finishes first. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### 2. `docker-build` (matrix: linux/amd64, linux/arm64) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Each arch builds [`docker/Dockerfile`](../docker/Dockerfile) natively on its own runner and pushes **by digest** to `ghcr.io/proxysql/orchestrator` (no tag yet). The digest is uploaded as a workflow artifact for the merge job to consume. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### 3. `docker-merge` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Downloads both digests, runs `docker/metadata-action` to compute tags from the git tag: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| - `type=semver,pattern={{version}}` — e.g. `4.30.1` | ||||||||||||||||||||||||||||
| - `type=semver,pattern={{major}}.{{minor}}` — e.g. `4.30` | ||||||||||||||||||||||||||||
| - `type=raw,value=latest` — only when the tag does **not** contain `rc` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Then uses `docker buildx imagetools create` to assemble a multi-arch manifest under all those tags, and inspects the result. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ## Verifying a release | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### GitHub Release page | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| After the workflow completes, the Release page should list (for version `X.Y.Z`): | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
| orchestrator-X.Y.Z-linux-amd64.tar.gz | ||||||||||||||||||||||||||||
| orchestrator-X.Y.Z-linux-arm64.tar.gz | ||||||||||||||||||||||||||||
| orchestrator_X.Y.Z-1_amd64.deb | ||||||||||||||||||||||||||||
| orchestrator_X.Y.Z-1_arm64.deb | ||||||||||||||||||||||||||||
| orchestrator-X.Y.Z-1.x86_64.rpm | ||||||||||||||||||||||||||||
| orchestrator-X.Y.Z-1.aarch64.rpm | ||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Plus the `-cli` and `-client` variants in `.deb` and `.rpm` form for each arch. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### Docker manifest | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
| docker buildx imagetools inspect ghcr.io/proxysql/orchestrator:X.Y.Z | ||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| The output should list both `linux/amd64` and `linux/arm64` entries. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Pull and smoke-test each arch: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
| docker run --rm --platform linux/amd64 ghcr.io/proxysql/orchestrator:X.Y.Z orchestrator --version | ||||||||||||||||||||||||||||
| docker run --rm --platform linux/arm64 ghcr.io/proxysql/orchestrator:X.Y.Z orchestrator --version | ||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ## Local reproduction | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| The release workflow does the same thing you can do locally with `build.sh` — see [Building and testing](build.md) and [`build.sh`](../build.sh). To produce ARM64 packages on a non-ARM host (outside of CI), run inside an arm64 container: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
| docker run --rm -it --platform linux/arm64 \ | ||||||||||||||||||||||||||||
| -v $PWD:/src -w /src \ | ||||||||||||||||||||||||||||
| ubuntu:24.04 bash -c ' | ||||||||||||||||||||||||||||
| apt-get update && | ||||||||||||||||||||||||||||
| apt-get install -y golang git ruby ruby-dev build-essential rpm && | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||||||||||||
| gem install --no-document fpm && | ||||||||||||||||||||||||||||
| ./build.sh -a arm64 | ||||||||||||||||||||||||||||
| ' | ||||||||||||||||||||||||||||
|
Comment on lines
+100
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The local arm64 recipe is missing
Suggested doc fix docker run --rm -it --platform linux/arm64 \
-v $PWD:/src -w /src \
ubuntu:24.04 bash -c '
apt-get update &&
apt-get install -y golang git ruby ruby-dev build-essential rpm &&
gem install --no-document fpm &&
+ export GOPATH="$(go env GOPATH)" &&
./build.sh -a arm64
'📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ## Permissions and secrets | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| The workflow relies on `GITHUB_TOKEN` with `contents: write` (for the Release) and `packages: write` (for GHCR) — both declared in [`release.yml`](../.github/workflows/release.yml). No additional secrets are required. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ## Troubleshooting | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| - **Workflow didn't run after tagging.** The tag must start with `v` (see the `on.push.tags` filter). Tags pushed without `git push --tags` or without pushing the specific ref won't trigger it. | ||||||||||||||||||||||||||||
| - **A matrix job failed mid-way and part of the release is missing.** The workflow uses `fail-fast: false`, so the other arch still completes. Re-running only the failed job from the Actions UI is safe — the GitHub Release and GHCR both accept re-uploads (fpm uses `-f` to overwrite, `action-gh-release` replaces files of the same name). | ||||||||||||||||||||||||||||
| - **Docker manifest is missing one arch.** If `docker-build` succeeded for only one arch, `docker-merge` will still run but `imagetools create` will produce a single-arch manifest. Re-run the failed `docker-build` job, then re-run `docker-merge`. | ||||||||||||||||||||||||||||
|
Comment on lines
+119
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Yes, in GitHub Actions, when a job depends on a matrix job via needs, the dependent job gets skipped if any matrix leg (individual job instance from the matrix) fails, unless the dependent job has an if: always (or equivalent condition like if: ${{ !failure && !cancelled }}) condition. The official documentation states: "Use jobs..<job_id>.needs to identify any jobs that must complete successfully before this job will run. [...] If a job fails or is skipped, all jobs that need it are skipped unless the jobs use a conditional expression that causes the job to continue." A matrix job is treated as a single logical job composed of multiple legs. If any leg fails (and fail-fast: true default or explicit, or even with fail-fast: false if not all succeed), the matrix job does not complete "successfully." Thus, dependents via needs are skipped without an overriding if condition. This behavior is confirmed across Stack Overflow examples (e.g., test_finish skipped when matrix test has failures) and GitHub issues discussing propagation of failure/skip states through needs dependencies. Citations:
🏁 Script executed: # First, find the workflow file(s) referenced in release.md
find . -name "*.md" -path "*/docs/*" | xargs grep -l "docker-merge\|docker-build" | head -5Repository: ProxySQL/orchestrator Length of output: 82 🏁 Script executed: # List GitHub Actions workflow files
git ls-files ".github/workflows/" 2>/dev/null || fd -e ".yml" -e ".yaml" ".github/workflows"Repository: ProxySQL/orchestrator Length of output: 213 🏁 Script executed: # Read the release.yml workflow file to examine docker-merge and docker-build jobs
cat .github/workflows/release.ymlRepository: ProxySQL/orchestrator Length of output: 4254 Update the Docker manifest recovery note to reflect actual job dependency behavior. The documentation incorrectly states that Suggested doc fix-- **Docker manifest is missing one arch.** If `docker-build` succeeded for only one arch, `docker-merge` will still run but `imagetools create` will produce a single-arch manifest. Re-run the failed `docker-build` job, then re-run `docker-merge`.
+- **Docker manifest is missing one arch.** If either `docker-build` matrix leg fails, `docker-merge` is skipped because it depends on `docker-build`. Re-run the failed `docker-build` job, then re-run `docker-merge`.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Can a GitHub Actions workflow running in a forked repository publish to a hardcoded GHCR image in the upstream owner's namespace (for exampleghcr.io/proxysql/orchestrator) using the fork'sGITHUB_TOKEN, or must the image name use the fork repository/owner namespace?💡 Result:
No, a GitHub Actions workflow running in a forked repository cannot publish to a hardcoded GHCR image in the upstream owner's namespace (e.g., ghcr.io/proxysql/orchestrator) using the fork's GITHUB_TOKEN. The GITHUB_TOKEN is scoped to the repository where the workflow runs (the fork) and only grants write access to packages in that repository's namespace (e.g., ghcr.io/forkowner/forkrepo). Publishing to the upstream namespace requires write permission on the upstream package, which the fork's GITHUB_TOKEN lacks. To publish to the upstream image: - Use a Personal Access Token (PAT) with write:packages scope for the upstream owner/org, stored as a secret in the fork. - Grant the fork repository explicit write access to the upstream package via the package settings ("Manage Actions access"). All examples and docs use ${{ github.repository }} or similar for the current repo's namespace, confirming GITHUB_TOKEN does not cross namespaces without explicit package-level grants (which forks typically don't have by default).
Citations:
🏁 Script executed:
Repository: ProxySQL/orchestrator
Length of output: 782
🏁 Script executed:
Repository: ProxySQL/orchestrator
Length of output: 1276
🏁 Script executed:
Repository: ProxySQL/orchestrator
Length of output: 446
The hardcoded GHCR namespace blocks the documented fork dry-run flow.
The documentation states that RC tags can be used to test the release pipeline end-to-end on a fork, but the hardcoded
ghcr.io/proxysql/orchestratorimage name at lines 99, 141, 152, and 158 prevents this from working. A fork'sGITHUB_TOKENcannot push to the upstream owner's namespace—it only has write access to its ownghcr.io/${{ github.repository }}namespace. Either derive the image name from the current repository or update the documentation to remove the fork dry-run promise.Suggested refactor
🤖 Prompt for AI Agents