-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(actions): run build parallel on multiple runners and build arm n…
…atively also adds reusable workflow for this building way
- Loading branch information
1 parent
1f96211
commit 4aef4f6
Showing
2 changed files
with
256 additions
and
70 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
name: Build and push docker container (parallelized multi-arch build with native arm builders) | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
context: | ||
default: "." | ||
required: false | ||
type: string | ||
file: | ||
required: false | ||
type: string | ||
|
||
title: | ||
required: true | ||
type: string | ||
description: | ||
required: false | ||
type: string | ||
|
||
app-version: | ||
default: '0.1.0' | ||
required: false | ||
type: string | ||
revision: | ||
default: 1 | ||
required: false | ||
type: number | ||
|
||
platforms: | ||
default: 'linux/amd64,linux/arm64' | ||
required: false | ||
type: string | ||
buildkit-mount-caches: | ||
description: "JSON object: `{id1: target1, id2: target2}`." | ||
required: false | ||
type: string | ||
buildkit-mount-cache-ids-append-platform: | ||
description: "If true, the workflow will append `-{{ platform }}` to the end of cache mount id (eg. `-linux/amd64`)." | ||
default: false | ||
type: boolean | ||
|
||
registry: | ||
default: ghcr.io | ||
required: false | ||
type: string | ||
image-name: | ||
required: true | ||
type: string | ||
secrets: | ||
registry-username: | ||
required: true | ||
registry-password: | ||
required: true | ||
|
||
jobs: | ||
vars: | ||
name: Preprocess variables | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- name: Preprocess variables | ||
id: vars | ||
run: | | ||
platforms="${{ inputs.platforms }}" | ||
{ | ||
echo "version=${{ inputs.app-version }}-r${{ inputs.revision }}" | ||
echo "platforms<<9743a66f914cc249efca164485a19c5c" | ||
echo "[\"${platforms//,/\",\"}\"]" | ||
echo "9743a66f914cc249efca164485a19c5c" | ||
} >> "$GITHUB_OUTPUT" | ||
outputs: | ||
version: ${{ steps.vars.outputs.version }} | ||
platforms: ${{ steps.vars.outputs.platforms }} | ||
|
||
build: | ||
name: Build container for ${{ matrix.platform }} | ||
runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} | ||
needs: vars | ||
permissions: | ||
contents: read | ||
packages: write | ||
# This is used to complete the identity challenge | ||
# with sigstore/fulcio when running outside of PRs. | ||
id-token: write | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
platform: ${{ fromJSON(needs.vars.outputs.platforms) }} | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | ||
|
||
# Workaround: https://github.com/docker/build-push-action/issues/461 | ||
- name: Setup Docker buildx | ||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0 | ||
|
||
- name: Log into registry ${{ inputs.registry }} | ||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 | ||
with: | ||
registry: ${{ inputs.registry }} | ||
username: ${{ secrets.registry-username }} | ||
password: ${{ secrets.registry-password }} | ||
|
||
- name: Extract Docker metadata | ||
id: meta | ||
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1 | ||
with: | ||
images: ${{ inputs.registry }}/${{ inputs.image-name }} | ||
labels: | | ||
org.opencontainers.image.title=${{ inputs.title }} | ||
org.opencontainers.image.description=${{ inputs.description }} | ||
- name: Prepare variables | ||
id: vars | ||
run: | | ||
platform='${{ matrix.platform }}' | ||
image='${{ steps.meta.outputs.tags }}' | ||
[ '${{ inputs.buildkit-mount-cache-ids-append-platform }}' = 'true' ] && id_suffix='-${{ matrix.platform }}' | ||
{ | ||
echo "platform-pair=${platform//\//-}" | ||
echo "platform-pair-un=${platform//\//_}" | ||
echo "image=${image%%:*}" | ||
echo "cache-map<<9743a66f914cc249efca164485a19c5c" | ||
jq --arg 'id_suffix' "$id_suffix" 'to_entries | map({(.key): {target: .value, id: "\(.key)\($id_suffix)"}}) | add' << 9743a66f914cc249efca164485a19c5c | ||
${{ inputs.buildkit-mount-caches }} | ||
9743a66f914cc249efca164485a19c5c | ||
echo "9743a66f914cc249efca164485a19c5c" | ||
echo "cache-paths<<9743a66f914cc249efca164485a19c5c" | ||
jq -r 'to_entries | .[].key' << 9743a66f914cc249efca164485a19c5c | ||
${{ inputs.buildkit-mount-caches }} | ||
9743a66f914cc249efca164485a19c5c | ||
echo "9743a66f914cc249efca164485a19c5c" | ||
} >> $GITHUB_OUTPUT | ||
cat $GITHUB_OUTPUT | ||
- name: Setup buildkit mount cache | ||
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | ||
if: steps.vars.outputs.cache-paths | ||
with: | ||
path: | | ||
${{ steps.vars.outputs.cache-paths }} | ||
key: buildkit-mount-${{ inputs.title }}-${{ steps.vars.outputs.platform-pair }}-${{ github.sha }} | ||
restore-keys: | | ||
buildkit-mount-${{ inputs.title }}-${{ steps.vars.outputs.platform-pair }}- | ||
- name: Inject buildkit mount cache into docker | ||
uses: reproducible-containers/buildkit-cache-dance@5b6db76d1da5c8b307d5d2e0706d266521b710de # v3.1.2 | ||
if: steps.vars.outputs.cache-paths | ||
with: | ||
cache-map: | | ||
${{ steps.vars.outputs.cache-map }} | ||
- name: Build and push Docker image | ||
id: build-and-push | ||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0 | ||
with: | ||
context: ${{ inputs.context }} | ||
file: ${{ inputs.file }} | ||
push: true | ||
platforms: ${{ matrix.platform }} | ||
outputs: type=image,"name=${{ steps.vars.outputs.image }}",push-by-digest=true,name-canonical=true,push=true | ||
labels: ${{ steps.meta.outputs.labels }} | ||
cache-from: type=gha,scope=buildkit-layer-${{ inputs.title }}-${{ steps.vars.outputs.platform-pair }} | ||
cache-to: type=gha,mode=max,scope=buildkit-layer-${{ inputs.title }}-${{ steps.vars.outputs.platform-pair }} | ||
|
||
# Workaround for https://github.com/actions/runner/pull/2477 | ||
- name: Export digest | ||
run: | | ||
mkdir -p ${{ runner.temp }}/digests | ||
digest="${{ steps.build-and-push.outputs.digest }}" | ||
touch "${{ runner.temp }}/digests/${digest#sha256:}" | ||
- name: Upload digest as an artifact | ||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 | ||
with: | ||
name: digests-${{ inputs.title }}-${{ steps.vars.outputs.platform-pair }} | ||
path: ${{ runner.temp }}/digests/* | ||
if-no-files-found: error | ||
retention-days: 1 | ||
|
||
outputs: | ||
image: ${{ steps.vars.outputs.image }} | ||
# https://github.com/actions/runner/pull/2477 :< | ||
# ${{ steps.vars.outputs.platform-pair-un }}-digest: ${{ steps.build-and-push.outputs.digest }} | ||
|
||
merge: | ||
name: Merge images to multi-arch image | ||
runs-on: ubuntu-24.04 | ||
permissions: | ||
contents: read | ||
packages: write | ||
# This is used to complete the identity challenge | ||
# with sigstore/fulcio when running outside of PRs. | ||
id-token: write | ||
needs: | ||
- build | ||
steps: | ||
- name: Download digests | ||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | ||
with: | ||
path: ${{ runner.temp }}/digests | ||
pattern: digests-${{ inputs.title }}-* | ||
merge-multiple: true | ||
|
||
# Workaround: https://github.com/docker/build-push-action/issues/461 | ||
- name: Setup Docker buildx | ||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0 | ||
|
||
- name: Log into registry ${{ inputs.registry }} | ||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 | ||
with: | ||
registry: ${{ inputs.registry }} | ||
username: ${{ secrets.registry-username }} | ||
password: ${{ secrets.registry-password }} | ||
|
||
- name: Extract Docker metadata | ||
id: meta | ||
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1 | ||
with: | ||
images: ${{ inputs.registry }}/${{ inputs.image-name }} | ||
labels: | | ||
org.opencontainers.image.title=${{ inputs.title }} | ||
org.opencontainers.image.description=${{ inputs.description }} | ||
tags: | | ||
type=ref,event=branch,priority=1990 | ||
type=ref,event=pr,priority=2999 | ||
type=raw,value=latest,enable={{is_default_branch}} | ||
type=raw,enable={{is_default_branch}},value=${{ needs.vars.outputs.version }},priority=1999 | ||
type=raw,enable={{is_default_branch}},value=${{ inputs.app-version }},priority=1998 | ||
type=semver,enable={{is_default_branch}},value=${{ inputs.app-version }},pattern={{major}}.{{minor}},priority=1997 | ||
type=semver,enable={{is_default_branch}},value=${{ inputs.app-version }},pattern={{major}},priority=1996 | ||
- name: Create manifest list and push | ||
working-directory: ${{ runner.temp }}/digests | ||
run: | | ||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | ||
$(printf '${{ needs.build.outputs.image }}@sha256:%s ' *) |
This file contains 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