-
-
Notifications
You must be signed in to change notification settings - Fork 71
Add reusable actions for native BuildKit build in GHA #273
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
base: master
Are you sure you want to change the base?
Changes from 3 commits
24bbd9f
75583a2
677f4d3
7a7fab5
f1b88d0
89b3247
2335ceb
28a77db
433b20d
78b43ea
e93d246
88a0820
ea75d5e
8d2380f
a5d42ec
52b5620
e5d272b
c711632
48c5edc
4a7d1db
69243fc
eee43c8
2426beb
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 |
|---|---|---|
| @@ -0,0 +1,238 @@ | ||
| name: Reusable builder | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| architectures: | ||
| description: Architectures to build (JSON array, e.g., '["amd64", "aarch64"]') | ||
| required: true | ||
| type: string | ||
| multi-arch: | ||
| description: Prefix per-arch image names with architecture (required for multiple architectures) | ||
| required: false | ||
| default: true | ||
| type: boolean | ||
| registry-prefix: | ||
| description: Registry and namespace prefix (e.g., "ghcr.io/owner") | ||
| required: true | ||
| type: string | ||
| image-name: | ||
| description: Image name without a tag (e.g., "base-python") | ||
| required: true | ||
| type: string | ||
| image-tag: | ||
| description: Base image tag (e.g., "3.23") | ||
| required: true | ||
| type: string | ||
| image-extra-tags: | ||
| description: Additional tags, one per line | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| context: | ||
| description: Build context (usually the directory with Dockerfile) | ||
| required: true | ||
| type: string | ||
| file: | ||
| description: Dockerfile path (defaults to "Dockerfile" in the context directory) | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| version: | ||
| description: Image version label | ||
| required: true | ||
| type: string | ||
| build-args: | ||
| description: Additional build arguments (key=value format, one per line) | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| push: | ||
| description: Whether to push images to registry | ||
| required: false | ||
| default: false | ||
| type: boolean | ||
| cache-scope: | ||
| description: Scope for build cache sharing (defaults to architecture, set if building multiple images from a single repo) | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| cache-image-tag: | ||
| description: Tag of the image containing BuildKit inline cache metadata | ||
| required: false | ||
| default: "latest" | ||
| type: string | ||
| cosign: | ||
| description: Whether to sign images with Cosign | ||
| required: false | ||
| default: true | ||
| type: boolean | ||
| cosign-identity: | ||
| description: Certificate identity regexp for verifying cache images (defaults to current repo pattern) | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| cosign-issuer: | ||
| description: Certificate OIDC issuer regexp for all cosign verification | ||
| required: false | ||
| default: "https://token.actions.githubusercontent.com" | ||
| type: string | ||
| verify-base: | ||
| description: Base image reference to verify with cosign before building | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| cosign-base-identity: | ||
| description: Certificate identity regexp for verifying the base (FROM) image | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| cosign-base-issuer: | ||
| description: Certificate OIDC issuer regexp for base image verification (defaults to cosign-issuer) | ||
| required: false | ||
| default: "" | ||
| type: string | ||
|
|
||
| jobs: | ||
| prepare: | ||
| name: Prepare build matrix | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| matrix: ${{ steps.set-matrix.outputs.matrix }} | ||
| steps: | ||
| - name: Build matrix from architectures | ||
| id: set-matrix | ||
| shell: bash | ||
| env: | ||
| ARCHITECTURES: ${{ inputs.architectures }} | ||
| MULTI_ARCH: ${{ inputs.multi-arch }} | ||
| run: | | ||
| arch_count=$(jq 'length' <<< "${ARCHITECTURES}") | ||
| if [[ "${MULTI_ARCH}" != "true" ]] && (( arch_count > 1 )); then | ||
| echo "::error::multi_arch is false but ${arch_count} architectures were specified; use multi_arch: true or pass a single architecture" | ||
| exit 1 | ||
| fi | ||
|
|
||
| matrix=$(jq -c '{include: [.[] | | ||
| if . == "amd64" then {arch: "amd64", os: "ubuntu-24.04", platform: "linux/amd64"} | ||
| elif . == "aarch64" then {arch: "aarch64", os: "ubuntu-24.04-arm", platform: "linux/arm64"} | ||
| else empty end | ||
| ]}' <<< "${ARCHITECTURES}") | ||
| echo "matrix=${matrix}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| build: | ||
| name: Build ${{ matrix.arch }} image | ||
| needs: prepare | ||
| runs-on: ${{ matrix.os }} | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| packages: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }} | ||
| steps: | ||
| - name: Checkout the repository | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Compute image name | ||
| id: image | ||
| shell: bash | ||
| env: | ||
| REGISTRY_PREFIX: ${{ inputs.registry-prefix }} | ||
| IMAGE_NAME: ${{ inputs.image-name }} | ||
| ARCH: ${{ matrix.arch }} | ||
| MULTI_ARCH: ${{ inputs.multi-arch }} | ||
| run: | | ||
| if [[ "${MULTI_ARCH}" == "true" ]]; then | ||
| image="${REGISTRY_PREFIX}/${ARCH}-${IMAGE_NAME}" | ||
| else | ||
| image="${REGISTRY_PREFIX}/${IMAGE_NAME}" | ||
| fi | ||
| echo "name=${image}" >> "$GITHUB_OUTPUT" | ||
agners marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: Build image | ||
| id: build | ||
| uses: home-assistant/builder/actions/build-image@gha-builder | ||
|
||
| with: | ||
| image: ${{ steps.image.outputs.name }} | ||
| image-tag: ${{ inputs.image-tag }} | ||
| image-extra-tags: ${{ inputs.image-extra-tags }} | ||
| arch: ${{ matrix.arch }} | ||
| platform: ${{ matrix.platform }} | ||
| push: ${{ inputs.push }} | ||
| cache-scope: ${{ inputs.cache-scope }} | ||
| cache-image-tag: ${{ inputs.cache-image-tag }} | ||
| docker-password: ${{ secrets.GITHUB_TOKEN }} | ||
| context: ${{ inputs.context }} | ||
| file: ${{ inputs.file }} | ||
| version: ${{ inputs.version }} | ||
| build-args: ${{ inputs.build-args }} | ||
| cosign: ${{ inputs.cosign }} | ||
| cosign-identity: ${{ inputs.cosign-identity }} | ||
| cosign-base-identity: ${{ inputs.cosign-base-identity }} | ||
| cosign-issuer: ${{ inputs.cosign-issuer }} | ||
| cosign-base-issuer: ${{ inputs.cosign-base-issuer }} | ||
| verify-base: ${{ inputs.verify-base }} | ||
agners marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| manifest: | ||
| name: Publish multi-arch manifest | ||
| if: inputs.push && inputs.multi-arch | ||
| needs: [prepare, build] | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| packages: write | ||
| steps: | ||
| - name: Login to GitHub Container Registry | ||
| uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.repository_owner }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 | ||
|
|
||
| - name: Install Cosign | ||
| uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 | ||
| if: inputs.cosign | ||
| with: | ||
| cosign-release: "v2.5.3" | ||
|
|
||
| - name: Create multi-arch manifest and sign it | ||
| shell: bash | ||
| env: | ||
| ARCHITECTURES: ${{ inputs.architectures }} | ||
| REGISTRY_PREFIX: ${{ inputs.registry-prefix }} | ||
| IMAGE_NAME: ${{ inputs.image-name }} | ||
| IMAGE_TAG: ${{ inputs.image-tag }} | ||
| IMAGE_EXTRA_TAGS: ${{ inputs.image-extra-tags }} | ||
| COSIGN: ${{ inputs.cosign }} | ||
| run: | | ||
| source_images=() | ||
| for arch in $(jq -r '.[]' <<< "${ARCHITECTURES}"); do | ||
| source_images+=("${REGISTRY_PREFIX}/${arch}-${IMAGE_NAME}:${IMAGE_TAG}") | ||
| done | ||
|
|
||
| tags=("${REGISTRY_PREFIX}/${IMAGE_NAME}:${IMAGE_TAG}") | ||
| while IFS= read -r tag; do | ||
| [[ -n "$tag" ]] && tags+=("${REGISTRY_PREFIX}/${IMAGE_NAME}:${tag}") | ||
| done <<< "${IMAGE_EXTRA_TAGS}" | ||
|
|
||
| tag_args=() | ||
| for tag in "${tags[@]}"; do | ||
| tag_args+=("--tag" "${tag}") | ||
| done | ||
|
|
||
| docker buildx imagetools create "${tag_args[@]}" "${source_images[@]}" | ||
|
|
||
| if [[ "${COSIGN}" == "true" ]]; then | ||
| # All tags for the manifest point to the same digest, get digest from the first tag | ||
| digest=$(skopeo inspect --raw --no-tags "docker://${tags[0]}" | skopeo manifest-digest /dev/stdin) | ||
| cosign sign --yes "${REGISTRY_PREFIX}/${IMAGE_NAME}@${digest}" | ||
| fi | ||
|
|
||
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.
Can we combine these two arguments into one like the builder action does?
Two ways to specify tags: