docker github builder docs

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2026-03-13 16:46:23 +01:00
parent 8a7680ad86
commit e90615a4a1
5 changed files with 457 additions and 241 deletions

View File

@@ -0,0 +1,107 @@
---
title: Docker GitHub Builder
linkTitle: GitHub Builder
description: Use Docker-maintained reusable GitHub Actions workflows to build images and artifacts with BuildKit.
keywords: ci, github actions, gha, buildkit, buildx, bake, reusable workflows
params:
sidebar:
badge:
color: green
text: New
---
Docker GitHub Builder is a set of [reusable workflows](https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows)
in the [`docker/github-builder` repository](https://github.com/docker/github-builder)
for building container images and local artifacts with [BuildKit](../../../buildkit/_index.md).
This section explains what the workflows solve, how they differ from wiring
together individual GitHub Actions in each repository, and when to use
[`build.yml`](build.md) or [`bake.yml`](bake.md).
If you compose a build job from `docker/login-action`, `docker/setup-buildx-action`,
`docker/metadata-action`, and either `docker/build-push-action` or
`docker/bake-action`, your repository owns every detail of how the build runs.
That approach works, but it also means every repository has to maintain its own
runner selection, [cache setup](../cache.md), [Provenance settings](../attestations.md),
signing behavior, and [multi-platform manifest handling](../multi-platform.md).
Docker GitHub Builder moves that implementation into Docker-maintained reusable
workflows, so your workflow only decides when to build and which inputs to pass.
The difference is easiest to see in the job definition. A conventional workflow
spells out each action step:
```yaml
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Login to Docker Hub
uses: docker/login-action@{{% param "login_action_version" %}}
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
- name: Docker meta
uses: docker/metadata-action@{{% param "metadata_action_version" %}}
id: meta
with:
images: name/app
- name: Build and push
uses: docker/build-push-action@{{% param "build_push_action_version" %}}
with:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha
```
With Docker GitHub Builder, the same build is a reusable workflow call:
```yaml
jobs:
build:
uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: image
push: ${{ github.event_name != 'pull_request' }}
meta-images: name/app
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
```
This model gives you a build pipeline that is maintained in the Docker
organization, uses a pinned [BuildKit](../../../buildkit/_index.md) environment,
distributes [multi-platform builds](../../../building/multi-platform.md) across
runners when that helps, and emits signed [SLSA provenance](../../../metadata/attestations/slsa-provenance.md)
that records both the source commit and the builder identity.
That tradeoff is intentional. You keep control of when the build runs and which
inputs it uses, but the build implementation itself lives in the
Docker-maintained workflow rather than in per-repository job steps.
Use [`build.yml`](build.md) when your repository builds from a Dockerfile and
the familiar `build-push-action` inputs map cleanly to your workflow. Use
[`bake.yml`](bake.md) when your repository already describes builds in a
[Bake definition](../../../bake/_index.md), or when you want Bake targets,
overrides, and variables to stay as the source of truth.
Both workflows support image output, local output, cache export to the
[GitHub Actions cache backend](../../../cache/backends/gha.md),
[SBOM generation](../../../metadata/attestations/sbom.md), and signing. The
Bake workflow adds Bake definition validation and builds one target per workflow
call.
{{% sectionlinks %}}

View File

@@ -0,0 +1,146 @@
---
title: Bake with Docker GitHub Builder
linkTitle: Bake
description: Use the Docker GitHub Builder bake.yml reusable workflow to build images and local artifacts from a Bake definition.
keywords: ci, github actions, gha, buildkit, buildx, bake, reusable workflow
weight: 20
---
The [`bake.yml` reusable workflow](https://github.com/docker/github-builder?tab=readme-ov-file#bake-reusable-workflow)
builds from a [Bake definition](../../../bake/_index.md) instead of a Dockerfile
input set. This page shows how to call the workflow for a target, how to pass
Bake overrides and variables, and how to export local output when a Bake file
is already the source of truth for your build.
## Build and push a Bake target
The following workflow builds the `image` target from `docker-bake.hcl` and
publishes the result with tags generated from [metadata inputs](../manage-tags-labels.md):
```yaml
name: ci
on:
push:
branches:
- "main"
tags:
- "v*"
pull_request:
permissions:
contents: read
jobs:
bake:
uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: image
push: ${{ github.event_name != 'pull_request' }}
target: image
meta-images: name/app
meta-tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
```
Bake workflows build one target per workflow call. Groups and multi-target
builds aren't supported because [SLSA provenance](../attestations.md), digest
handling, and manifest creation are scoped to a single target.
The workflow validates the definition before the build starts and resolves
the target from the files you pass in `files`.
## Override target values and variables
Because the workflow delegates the build to Bake, you can keep using `set` and
`vars` for target-specific overrides:
```yaml
name: ci
on:
push:
branches:
- "main"
permissions:
contents: read
jobs:
bake:
uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: image
push: true
target: image
vars: |
IMAGE_TAG=${{ github.sha }}
set: |
*.args.BUILD_RUN_ID=${{ github.run_id }}
*.platform=linux/amd64,linux/arm64
cache: true
cache-scope: image
meta-images: name/app
meta-tags: |
type=sha
set-meta-annotations: true
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
```
This form fits repositories that already use Bake groups, target inheritance,
and variable expansion. The reusable workflow takes care of Buildx setup,
[GitHub Actions cache export](../../../cache/backends/gha.md),
[Provenance defaults](../../../metadata/attestations/slsa-provenance.md),
signing behavior, and the final multi-platform manifest. Metadata labels and
annotations can be merged into the Bake definition without adding a separate
metadata step to your workflow.
## Export local output from Bake
If the target should export files instead of publishing an image, switch the
workflow output to `local` and upload the artifact:
```yaml
name: ci
on:
pull_request:
permissions:
contents: read
jobs:
bake:
uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: local
target: binaries
artifact-upload: true
artifact-name: bake-output
```
With `output: local`, the workflow injects the matching local output override
into the Bake run and merges the uploaded artifacts after the per-platform
builds finish. If you need a manual Bake pattern that stays in a normal job,
see [Multi-platform image](../multi-platform.md). If your build does not need a
Bake definition, use [build.yml](build.md) instead.

View File

@@ -0,0 +1,150 @@
---
title: Build with Docker GitHub Builder
linkTitle: Build
description: Use the Docker GitHub Builder build.yml reusable workflow to build images and local artifacts from a Dockerfile.
keywords: ci, github actions, gha, buildkit, buildx, reusable workflow, dockerfile
weight: 10
---
The [`build.yml` reusable workflow](https://github.com/docker/github-builder?tab=readme-ov-file#build-reusable-workflow)
builds from a Dockerfile and packages the same core tasks that many repositories
wire together by hand. This page shows how to call the workflow, publish
[multi-platform images](../../../building/multi-platform.md), and export local
build artifacts without rebuilding the job structure in every repository.
## Build and push an image
The following workflow builds from the repository Dockerfile, pushes on branch
and tag events, and uses metadata inputs to generate tags:
```yaml
name: ci
on:
push:
branches:
- "main"
tags:
- "v*"
pull_request:
permissions:
contents: read
jobs:
build:
uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: image
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
meta-images: name/app
meta-tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
```
When you set `output: image`, `meta-images` is required because the workflow
creates image names and [manifest tags](../manage-tags-labels.md) from that
input. `runner: auto` and `distribute: true` are the defaults, so a
multi-platform build can fan out across native GitHub-hosted runners instead
of forcing the whole build onto one machine. `sign: auto` is also the default,
which means the workflow signs [attestation manifests](../attestations.md)
when the image is pushed.
## Export local output as an artifact
The same workflow can export files instead of publishing an image. This is
useful when you want compiled assets, an unpacked root filesystem, or another
local exporter result as part of CI:
```yaml
name: ci
on:
pull_request:
permissions:
contents: read
jobs:
build:
uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: local
artifact-upload: true
artifact-name: build-output
platforms: linux/amd64,linux/arm64
```
With `output: local`, the workflow exports files to the runner filesystem and
merges per-platform artifacts in the finalize phase. When
`artifact-upload: true` is set, the merged result is uploaded as a GitHub
artifact, and `sign: auto` signs the uploaded artifacts. `push` is ignored for
local output, so there is no registry requirement in this form.
## Add cache, Dockerfile inputs, and metadata labels
You can tune the Dockerfile build in the same job call. This example sets a
custom Dockerfile path, a target stage, GitHub Actions cache, and metadata
labels:
```yaml
name: ci
on:
push:
branches:
- "main"
permissions:
contents: read
jobs:
build:
uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
permissions:
contents: read # to fetch the repository content
id-token: write # for signing attestation(s) with GitHub OIDC Token
with:
output: image
push: true
context: .
file: ./docker/Dockerfile
target: runtime
build-args: |
NODE_ENV=production
VERSION=${{ github.sha }}
cache: true
cache-scope: myapp
meta-images: name/app
meta-tags: |
type=sha
set-meta-labels: true
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
```
This is a Dockerfile build, so the inputs map closely to
`docker/build-push-action`. The difference is that the reusable workflow owns
Buildx setup, [BuildKit](../../../buildkit/_index.md) configuration,
[SLSA provenance](../../../metadata/attestations/slsa-provenance.md) mode,
[GitHub Actions cache backend](../../../cache/backends/gha.md) wiring, signing,
and manifest creation. If you need more background on metadata or platform
distribution, see [Manage tags and labels](../manage-tags-labels.md) and
[Multi-platform image](../multi-platform.md).

View File

@@ -102,17 +102,14 @@ jobs:
Building multiple platforms on the same runner can significantly extend build
times, particularly when dealing with complex Dockerfiles or a high number of
target platforms. By distributing platform-specific builds across multiple
runners using a matrix strategy, you can drastically reduce build durations and
streamline your CI pipeline. These examples demonstrate how to allocate each
platform build to a dedicated runner, including ARM-native runners where
applicable, and create a unified manifest list using the
[`buildx imagetools create` command](/reference/cli/docker/buildx/imagetools/create/).
target platforms. If you want to split platform builds across multiple runners
without maintaining a custom matrix and merge job, use the
[Docker GitHub Builder](github-builder/_index.md). The reusable workflows
compute the per-platform matrix, run each platform on its own runner, and
create the final manifest for you.
The following workflow will build the image for each platform on a dedicated
runner using a matrix strategy and push by digest. Then, the `merge` job will
create manifest lists and push them to Docker Hub. The [`metadata` action](https://github.com/docker/metadata-action)
is used to set tags and labels.
The following workflow uses the [`build.yml` reusable workflow](github-builder/build.md)
to distribute a multi-platform Dockerfile build:
```yaml
name: ci
@@ -120,119 +117,43 @@ name: ci
on:
push:
env:
REGISTRY_IMAGE: user/app
permissions:
contents: read
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Docker meta
id: meta
uses: docker/metadata-action@{{% param "metadata_action_version" %}}
with:
images: ${{ env.REGISTRY_IMAGE }}
- name: Login to Docker Hub
uses: docker/login-action@{{% param "login_action_version" %}}
with:
uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
permissions:
contents: read
id-token: write
with:
output: image
push: true
platforms: linux/amd64,linux/arm64
meta-images: user/app
meta-tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
- name: Build and push by digest
id: build
uses: docker/build-push-action@{{% param "build_push_action_version" %}}
with:
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ env.REGISTRY_IMAGE }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to Docker Hub
uses: docker/login-action@{{% param "login_action_version" %}}
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
- name: Docker meta
id: meta
uses: docker/metadata-action@{{% param "metadata_action_version" %}}
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- 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 '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}
```
With `runner: auto` and `distribute: true`, which are the defaults, the
workflow splits the build into one platform per runner and assembles the final
multi-platform image in its finalize phase. If you need to control the Docker
build inputs directly, see [Build with Docker GitHub Builder build.yml](github-builder/build.md).
### With Bake
It's also possible to build on multiple runners using Bake, with the
[bake action](https://github.com/docker/bake-action).
You can find a live example [in this GitHub repository](https://github.com/crazy-max/docker-linguist).
The following example achieves the same results as described in
[the previous section](#distribute-build-across-multiple-runners).
You can use the [`bake.yml` reusable workflow](github-builder/bake.md) for the
same pattern when your build is defined in a Bake file. The workflow reads the
target platforms from the Bake definition, distributes the per-platform builds,
and publishes the final manifest without a separate prepare or merge job.
```hcl
variable "DEFAULT_TAG" {
@@ -275,135 +196,26 @@ name: ci
on:
push:
env:
REGISTRY_IMAGE: user/app
permissions:
contents: read
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.platforms.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create matrix
id: platforms
run: |
echo "matrix=$(docker buildx bake image-all --print | jq -cr '.target."image-all".platforms')" >>${GITHUB_OUTPUT}
- name: Show matrix
run: |
echo ${{ steps.platforms.outputs.matrix }}
- name: Docker meta
id: meta
uses: docker/metadata-action@{{% param "metadata_action_version" %}}
with:
images: ${{ env.REGISTRY_IMAGE }}
- name: Rename meta bake definition file
run: |
mv "${{ steps.meta.outputs.bake-file }}" "${{ runner.temp }}/bake-meta.json"
- name: Upload meta bake definition
uses: actions/upload-artifact@v4
with:
name: bake-meta
path: ${{ runner.temp }}/bake-meta.json
if-no-files-found: error
retention-days: 1
build:
needs:
- prepare
strategy:
fail-fast: false
matrix:
platform: ${{ fromJson(needs.prepare.outputs.matrix) }}
runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Download meta bake definition
uses: actions/download-artifact@v4
with:
name: bake-meta
path: ${{ runner.temp }}
- name: Login to Docker Hub
uses: docker/login-action@{{% param "login_action_version" %}}
with:
bake:
uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
permissions:
contents: read
id-token: write
with:
output: image
push: true
target: image-all
meta-images: user/app
meta-tags: |
type=ref,event=branch
type=sha
secrets:
registry-auths: |
- registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
- name: Build
id: bake
uses: docker/bake-action@{{% param "bake_action_version" %}}
with:
files: |
./docker-bake.hcl
cwd://${{ runner.temp }}/bake-meta.json
targets: image
set: |
*.tags=${{ env.REGISTRY_IMAGE }}
*.platform=${{ matrix.platform }}
*.output=type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ fromJSON(steps.bake.outputs.metadata).image['containerimage.digest'] }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Download meta bake definition
uses: actions/download-artifact@v4
with:
name: bake-meta
path: ${{ runner.temp }}
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to DockerHub
uses: docker/login-action@{{% param "login_action_version" %}}
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("${{ env.REGISTRY_IMAGE }}")) | "-t " + .) | join(" ")' ${{ runner.temp }}/bake-meta.json) \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:$(jq -r '.target."docker-metadata-action".args.DOCKER_META_VERSION' ${{ runner.temp }}/bake-meta.json)
```

View File

@@ -158,6 +158,7 @@ params:
setup_compose_action_version: "v2"
setup_docker_action_version: "v5"
setup_qemu_action_version: "v4"
github_builder_version: "v1"
# Example runtime/library/os versions
example_go_version: "1.25"