Skip to content

Add reusable actions for native BuildKit build in GHA#273

Merged
sairon merged 25 commits intomasterfrom
gha-builder
Mar 16, 2026
Merged

Add reusable actions for native BuildKit build in GHA#273
sairon merged 25 commits intomasterfrom
gha-builder

Conversation

@sairon
Copy link
Member

@sairon sairon commented Mar 4, 2026

This PR provides a set of reusable composite actions that replace the Builder container with "native" BuildKit builds using docker/build-push-action.

actions/build-image builds and optionally pushes and signs a single-architecture image. Build metadata (BUILD_ARCH, BUILD_VERSION) is passed to the Dockerfile via --build-arg, while OCI and Home Assistant labels (io.hass.arch, io.hass.version, org.opencontainers.image.*) are applied directly by the action through docker/build-push-action's label support. Additional build args and labels can be passed through the build-args and labels inputs. Images are compressed with zstd (level 9) instead of gzip, reducing image size and improving pull times on registries and runtimes that support it. Build caching uses GitHub Actions cache as the primary backend, with inline cache metadata embedded in pushed images as a fallback for cache reuse across git refs (since GHA cache is scoped per branch/tag). Pushed images are signed with Cosign, with retry and exponential backoff. Base and cache images can optionally be verified before the build starts.

actions/cosign-verify verifies the Cosign signature of a container image against a certificate identity and OIDC issuer, with retry logic and an optional allow-failure mode.

actions/prepare-multi-arch-matrix validates the requested architectures (amd64, aarch64) and outputs a JSON matrix mapping each to a native runner (ubuntu-24.04, ubuntu-24.04-arm) and a registry image name, ready to be consumed by a build matrix job.

actions/publish-multi-arch-manifest combines per-architecture images into a single manifest list using docker buildx imagetools create, applies all requested tags, and signs the resulting manifest with Cosign.

Together, these actions support a workflow where per-architecture images are built in parallel on native runners, then combined into a multi-arch manifest. Thanks to the caching, the build can also run on push to the master branch to keep the GHA cache warm for release builds without adding significant CI cost.

A reference implementation is in home-assistant/docker-base#347.

sairon added 2 commits March 4, 2026 09:40
This PR fundamentally changes how our images are built. The usage of the
Builder container is dropped in favor of "native" build using BuildKit with
docker/build-push-action.

Dockerfiles are now the single source of truth for all labels and build
arguments - the build metadata (version, date, architecture, repository) is
passed via --build-arg and consumed directly in the Dockerfile's LABEL
instruction, removing the need for external label injection.

Build caching uses GitHub Actions cache as the primary backend, with inline
cache metadata embedded in pushed images as a fallback for cache reuse across
git refs (since GHA cache is scoped per branch/tag). Registry images are
verified with cosign before being used as cache sources.

Images are compressed with zstd (level 9) instead of gzip, reducing image size
and improving pull times on registries and runtimes that support it.

Multi-arch support is handled by building per-architecture images in parallel
on native runners (amd64 on ubuntu-24.04, aarch64 on ubuntu-24.04-arm), then
combining them into a single manifest list using docker buildx imagetools.

Thanks to the caching, the builder workflow now also runs on push to the master
branch, keeping the GHA cache warm for release builds without adding
significant CI cost.

A reference implementation is in home-assistant/docker-base#347.
The common convention are dashes, stick with that.
sairon added a commit to home-assistant/core that referenced this pull request Mar 4, 2026
This PR completely drops usage of the builder action in favor of new actions
introduced in home-assistant/builder#273. This results in faster builds with
better caching options and simple local builds using Docker BuildKit.

The image dependency chain currently still uses per-arch builds but once
docker-base and docker repositories start publishing multi-arch images, we can
simplify the action a bit further.

The idea to use composite actions comes from #162245 and this PR fully predates
it. There is minor difference that the files generated twice in per-arch builds
are now generated and archived by the init job.
@sairon sairon requested a review from edenhaus March 4, 2026 17:37
Copy link
Member

@agners agners left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the re-use of cosign-verify. Also that we sign the actual image digest now, it's what cosign recommends 👍 Looks quite good to me 💪. Some minor nits/comments.

@home-assistant
Copy link

home-assistant bot commented Mar 5, 2026

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@home-assistant home-assistant bot marked this pull request as draft March 5, 2026 09:33
Comment on lines +170 to +173
build_args+=("BUILD_VERSION=${VERSION}")
build_args+=("BUILD_ARCH=${ARCH}")
build_args+=("BUILD_DATE=${build_date}")
build_args+=("BUILD_REPOSITORY=https://github.com/${GITHUB_REPOSITORY}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking this over, I suggest that we don't set any build args by default and that the user should specify them. This makes it clearer which one will be used.
Also, for example, the input arg version is only used to set a build arg, which I think is better if the caller specifies it directly. If the caller is specifying it, it has the advantage that he can also control the name and does not need to go through the builder to find out which ones are set automatically.

Also, in case of the input arg version, it is required, and so the caller cannot use it without. For example, if he uses it somewhere, where he doesn't want to specify the version (Intermediate version or version just used in build pipelines)

Copy link
Member Author

@sairon sairon Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit lost, what exactly you want to remove from defaults? These in the action?

I meant to use sane defaults for all arguments, so it will be easy to reuse the action/workflow it without unnecessary boilerplate. If you want to remove it from the action, I'd at least prefer to keep it in the workflow to make reuse in plugin/apps build easy. And e.g. in the case of BUILD_DATE I think there's no benefit at all in requiring the user to fill it out. The action is meant to abstract common patterns of building our images which share common structure - otherwise we'd make it just a generic "docker/build-push-and-cosign" action which will require boilerplate in every repo.

Edit: Turns out that calling reusable workflow from another repo causes issues with Cosign signing, so this is not the way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been largely refactored after the discussion in the Core PR. The only build args passed now are BUILD_ARCH and BUILD_VERSION. The first one is used even in some of HA containers to handle different architectures, the other one is rather to keep the contract given previously: https://developers.home-assistant.io/docs/apps/configuration?_highlight=build_version#build-args

The BUILD_FROM will be removed here (the source of it was build.yaml), while Supervisor will likely keep passing it from the build.yaml for a while until we drop the support for it there too.

@home-assistant home-assistant bot marked this pull request as draft March 16, 2026 14:03
@sairon sairon marked this pull request as ready for review March 16, 2026 15:32
@home-assistant home-assistant bot requested review from agners and edenhaus March 16, 2026 15:32
@sairon sairon merged commit 18f748b into master Mar 16, 2026
7 checks passed
@sairon sairon deleted the gha-builder branch March 16, 2026 15:45
sairon added a commit that referenced this pull request Mar 16, 2026
With the new actions added in #273, the old action and build container will no
longer be maintained. To make the landing softer, especially for those repos
that still use the discouraged `@master` action pinning, only print warnings
until they migrate or pin the action to the old release.

The references to the old action and builder usage are now removed from the
README and a high-level description of the new workflow added.
sairon added a commit that referenced this pull request Mar 17, 2026
* Deprecate usage of `home-assistant/builder`, update README

With the new actions added in #273, the old action and build container will no
longer be maintained. To make the landing softer, especially for those repos
that still use the discouraged `@master` action pinning, only print warnings
until they migrate or pin the action to the old release.

The references to the old action and builder usage are now removed from the
README and a high-level description of the new workflow added.

* Elaborate on legacy action deprecation

Co-authored-by: Stefan Agner <stefan@agner.ch>

---------

Co-authored-by: Stefan Agner <stefan@agner.ch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants