Repository navigation
feat(infra): give new hosts a route out, and let the rehearsal read t… #84
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
| name: docker | |
| # Each architecture builds on a runner of that architecture and pushes an | |
| # untagged, digest-only image; a final job stitches those digests into one | |
| # multi-arch manifest and applies the tags. | |
| # | |
| # The previous single-job build ran linux/arm64 under QEMU on an amd64 runner, | |
| # which took ~60 minutes per push — and arm64 is the architecture actually | |
| # deployed. Both legs also shared one `type=gha` cache, so they raced while | |
| # unpacking the cargo registry into the same cache mount and intermittently | |
| # failed with `.cargo-ok: File exists`. The cache is now scoped per platform. | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository_owner }}/voltius-server | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-24.04 | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runner }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| # IMAGE must be lowercased by hand: the owner is `VoltiusApp`, and a Docker | |
| # ref with uppercase in the repository name is rejected. metadata-action | |
| # lowercases its own tag output, but the digest push and the manifest | |
| # merge below build refs from these variables directly. | |
| - name: Prepare image ref and platform slug | |
| run: | | |
| echo "IMAGE=${REGISTRY}/${IMAGE_NAME,,}" >> "$GITHUB_ENV" | |
| echo "PLATFORM_SLUG=${PLATFORM//\//-}" >> "$GITHUB_ENV" | |
| echo "GIT_SHA=${GITHUB_SHA::7}" >> "$GITHUB_ENV" | |
| env: | |
| PLATFORM: ${{ matrix.platform }} | |
| - uses: actions/checkout@v6 | |
| # No QEMU: each leg is native to its runner. | |
| - name: Set up Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract labels | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| platforms: ${{ matrix.platform }} | |
| build-args: | | |
| GIT_SHA=${{ env.GIT_SHA }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| cache-from: type=gha,scope=${{ env.PLATFORM_SLUG }} | |
| cache-to: type=gha,mode=max,scope=${{ env.PLATFORM_SLUG }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest='${{ steps.build.outputs.digest }}' | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests-${{ env.PLATFORM_SLUG }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| runs-on: ubuntu-24.04 | |
| needs: [build] | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Prepare image ref | |
| run: echo "IMAGE=${REGISTRY}/${IMAGE_NAME,,}" >> "$GITHUB_ENV" | |
| - name: Download digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Set up Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # sha-<short> is the tag to deploy from: `latest` is mutable and two | |
| # overlapping pushes race on it, so the older build can win. | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=sha,format=short | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Create manifest list and push | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.IMAGE }}@sha256:%s ' *) | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect \ | |
| ${{ env.IMAGE }}:${{ steps.meta.outputs.version }} |