Compare commits

..

2 Commits

Author SHA1 Message Date
CrazyMax
05596d50d0
Merge 7bccc1380a400cd5c5c6295391b93cf89cd2a75a into ca877d9245402d1537745e0e356eab47c3520991 2025-02-16 10:37:15 +00:00
CrazyMax
7bccc1380a
reusable workflow to distribute multi-platform builds
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-16 11:37:08 +01:00
2 changed files with 32 additions and 91 deletions

View File

@ -1541,7 +1541,7 @@ jobs:
fi
distribute:
uses: ./.github/workflows/reusable-distribute.yml
uses: ./.github/workflows/distribute.yml
with:
push: false
meta-image: user/app

View File

@ -1,6 +1,4 @@
# Reusable workflow to distribute multi-platform builds efficiently
# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
name: reusable-distribute
name: distribute
on:
workflow_call:
@ -16,16 +14,6 @@ on:
description: "Push image to registry"
required: false
default: false
set-meta-annotations:
type: boolean
description: "Set metadata-action annotations"
required: false
default: false
set-meta-labels:
type: boolean
description: "Set metadata-action labels"
required: false
default: false
setup-qemu:
type: boolean
description: "Install QEMU static binaries"
@ -71,7 +59,7 @@ on:
type: string
description: 'QEMU static binaries Docker image (e.g. tonistiigi/binfmt:latest)'
required: false
# same as docker/build-push-action inputs (minus builder, call, load, outputs, platforms, push, tags)
# same as docker/build-push-action inputs (minus builder, call, context, load, outputs, platforms, push, tags)
build-add-hosts:
type: string
description: "List of a customs host-to-IP mapping (e.g., docker:10.180.0.1)"
@ -178,19 +166,6 @@ on:
type: string
description: "Ulimit options (e.g., nofile=1024:1024)"
required: false
secrets:
login-username:
description: 'Username used to log against the Docker registry'
required: false
login-password:
description: "Password or personal access token used to log against the Docker registry"
required: false
github-token:
description: "GitHub Token used to authenticate against a repository for Git context"
required: false
env:
ACTIONS_TOOLKIT_VERSION: "0.54.0"
jobs:
prepare:
@ -199,42 +174,33 @@ jobs:
includes: ${{ steps.set.outputs.includes }}
steps:
-
name: Install npm dependencies
name: Validate
uses: actions/github-script@v7
with:
script: |
await exec.exec('npm', ['install',
'@docker/actions-toolkit@${{ env.ACTIONS_TOOLKIT_VERSION }}'
]);
const metaImage = `${{ inputs.meta-image }}` ? `${{ inputs.meta-image }}`.split(/[\r?\n,]+/).filter(Boolean) : [];
if (metaImage.length > 1) {
throw new Error('Only one meta-image is allowed');
}
const platforms = `${{ inputs.build-platforms }}` ? `${{ inputs.build-platforms }}`.split(/[\r?\n,]+/).filter(Boolean) : [];
if (platforms.length > 100) {
throw new Error('Too many platforms');
} else if (platforms.length <= 1) {
throw new Error('At least 2 platforms are required');
}
core.exportVariable('BUILD_PLATFORMS', platforms.join(','));
-
name: Set includes
id: set
uses: actions/github-script@v7
env:
INPUT_RUNNER: ${{ inputs.runner }}
INPUT_META-IMAGE: ${{ inputs.meta-image }}
INPUT_BUILD-PLATFORMS: ${{ inputs.build-platforms }}
GITHUB_TOKEN: ${{ secrets.github-token || github.token }}
with:
script: |
const { Util } = require('@docker/actions-toolkit/lib/util');
if (Util.getInputList('meta-image').length > 1) {
throw new Error('Only one meta-image is allowed');
}
const inpRunner = core.getInput('runner');
const inpBuildPlatforms = Util.getInputList('build-platforms');
if (inpBuildPlatforms.length > 100) {
throw new Error('Too many platforms');
} else if (inpBuildPlatforms.length <= 1) {
throw new Error('At least 2 platforms are required');
}
await core.group(`Set includes`, async () => {
const platforms = `${{ env.BUILD_PLATFORMS }}`.split(',');
let includes = [];
inpBuildPlatforms.forEach((platform, index) => {
let runner = inpRunner;
platforms.forEach((platform, index) => {
let runner = `${{ inputs.runner }}`;
if (runner === 'auto') {
runner = platform.startsWith('linux/arm') ? 'ubuntu-24.04-arm' : 'ubuntu-latest';
}
@ -376,7 +342,7 @@ jobs:
if: ${{ inputs.push }}
with:
registry: ${{ inputs.login-registry }}
username: ${{ inputs.login-username || secrets.login-username }}
username: ${{ inputs.login-username }}
password: ${{ secrets.login-password }}
-
name: Set up QEMU
@ -387,31 +353,6 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Set build inputs
id: build-inputs
uses: actions/github-script@v7
env:
INPUT_SET-META-ANNOTATIONS: ${{ inputs.set-meta-annotations }}
INPUT_SET-META-LABELS: ${{ inputs.set-meta-labels }}
INPUT_BUILD-ANNOTATIONS: ${{ inputs.build-annotations }}
INPUT_BUILD-LABELS: ${{ inputs.build-labels }}
with:
script: |
const inpSetMetaAnnotations = core.getBooleanInput('set-meta-annotations');
const inpSetMetaLabels = core.getBooleanInput('set-meta-labels');
let inpBuildAnnotations = core.getInput('build-annotations');
if (inpSetMetaAnnotations) {
inpBuildAnnotations += `\n${{ steps.meta.outputs.annotations }}`;
}
let inpBuildLabels = core.getInput('build-labels');
if (inpSetMetaLabels) {
inpBuildLabels += `\n${{ steps.meta.outputs.labels }}`;
}
core.setOutput('annotations', inpBuildAnnotations);
core.setOutput('labels', inpBuildLabels);
-
name: Build
id: build
@ -419,7 +360,9 @@ jobs:
with:
add-hosts: ${{ inputs.build-add-hosts }}
allow: ${{ inputs.build-allow }}
annotations: ${{ steps.build-inputs.outputs.annotations }}
annotations: |
${{ steps.meta.outputs.annotations }}
${{ inputs.build-annotations }}
attests: ${{ inputs.build-attests }}
build-args: ${{ inputs.build-build-args }}
build-contexts: ${{ inputs.build-contexts }}
@ -428,7 +371,9 @@ jobs:
cgroup-parent: ${{ inputs.build-cgroup-parent }}
context: ${{ inputs.build-context }}
file: ${{ inputs.build-file }}
labels: ${{ steps.build-inputs.outputs.labels }}
labels: |
${{ steps.meta.outputs.labels }}
${{ inputs.build-labels }}
network: ${{ inputs.build-network }}
no-cache: ${{ inputs.build-no-cache }}
no-cache-filters: ${{ inputs.build-no-cache-filters }}
@ -470,13 +415,15 @@ jobs:
images: ${{ inputs.meta-image }}
tags: ${{ inputs.meta-tags }}
flavor: ${{ inputs.meta-flavor }}
labels: ${{ inputs.meta-labels }}
annotations: ${{ inputs.meta-annotations }}
-
name: Login to registry
uses: docker/login-action@v3
if: ${{ inputs.push }}
with:
registry: ${{ inputs.login-registry }}
username: ${{ inputs.login-username || secrets.login-username }}
username: ${{ inputs.login-username }}
password: ${{ secrets.login-password }}
-
name: Set up Docker Buildx
@ -485,14 +432,8 @@ jobs:
-
name: Create manifest list
uses: actions/github-script@v7
env:
INPUT_PUSH: ${{ inputs.push }}
INPUT_META-IMAGE: ${{ inputs.meta-image }}
with:
script: |
const inpPush = core.getBooleanInput('push');
const inpMetaImage = core.getInput('meta-image');
let digests = [];
await core.group(`Digests`, async () => {
digests = Object.values(JSON.parse(`${{ toJSON(needs.build.outputs) }}`));
@ -510,10 +451,10 @@ jobs:
createArgs.push(`-t`, tag);
}
for (const digest of digests) {
createArgs.push(`${inpMetaImage}@${digest}`);
createArgs.push(`${{ inputs.meta-image }}@${digest}`);
}
if (inpPush) {
if (${{ inputs.push }}) {
if (tags.length === 0) {
throw new Error('No tags to create manifest list');
}
@ -525,7 +466,7 @@ jobs:
}
});
await core.group(`Inspect image`, async () => {
await exec.getExecOutput('docker', ['buildx', 'imagetools', 'inspect', `${inpMetaImage}:${tags[0]}`], {
await exec.getExecOutput('docker', ['buildx', 'imagetools', 'inspect', `${{ inputs.meta-image }}:${tags[0]}`], {
ignoreReturnCode: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {