Skip to content

Delegate sticky BuildKit to setup-buildx#45

Open
crohr wants to merge 10 commits into
feature/stickyfrom
auto/buildkit-setup-action
Open

Delegate sticky BuildKit to setup-buildx#45
crohr wants to merge 10 commits into
feature/stickyfrom
auto/buildkit-setup-action

Conversation

@crohr

@crohr crohr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • replace the action-managed BuildKit daemon with a bind-backed Docker volume prepared for docker/setup-buildx-action
  • replace the legacy cache, path, wait_timeout, and fail_on_missing inputs with structured sticky_cache records and sticky_wait_timeout
  • make every declared sticky cache strict: the action fails when the disk is absent or does not become ready before the timeout
  • support repeated custom,path=... records, aliases, strict validation, and complete cache-hit accounting
  • always output the stable builder name and ECR Docker Hub mirror TOML
  • verify the official Buildx container mounted the sticky volume before stopping it for snapshot consistency
  • add pinned/latest Buildx cold-to-warm coverage for BuildKit and a custom relative path, plus a missing-disk failure job
  • rename the required runner label from snap= to sticky= with no compatibility alias
  • rebuild all bundled platform binaries and document the breaking API

Why

The original sticky BuildKit mode downloaded and managed a separate buildkitd, so setup-buildx configuration and the RunsOn ECR pull-through mirror did not carry over. Letting Docker's official action own the builder preserves its normal configuration surface while RunsOn owns only persistent storage and final snapshot-safe cleanup.

Buildx does not expose a public state-volume override for the docker-container driver. This implementation deliberately follows the pinned single-node volume contract (buildx_buildkit_runs-on0_state) and verifies the actual container mount during the post step so an upstream naming change fails visibly instead of silently using ephemeral storage.

Disk availability is global to all caches on a sticky volume, so the API does not expose a per-cache missing-disk policy. Declaring sticky_cache is itself the persistence contract:

with:
  sticky_cache: |
    buildkit
    custom,path=vendor/custom-cache
  sticky_wait_timeout: 5m

Impact

This is intentionally breaking: the old input names and comma/slash parsing are removed without aliases. Sticky BuildKit users must run runs-on/action before docker/setup-buildx-action, use the emitted builder name and inline config, select the docker-container driver, and set cleanup: false. Non-sticky users can consume the inline config to make ordinary BuildKit builders honor the RunsOn ECR Docker Hub pull-through mirror.

This is a stacked follow-up to #43 and targets feature/sticky.

Validation

  • mise exec -- go test ./...
  • targeted go vet for the root, config, and sticky-disk packages
  • mise exec -- make build
  • parsed action.yml and the workflow as YAML
  • real dev Fleet cold-to-warm E2E restores both the custom marker (cache-hit=true) and the BuildKit layer; all setup and post-job hooks pass
  • PR push check verifies that declaring sticky_cache without sticky fails as expected; positive sticky jobs are deploy-time/manual because the runs-on org is not attached to the dev Fleet enterprise
  • real Docker validation confirmed the pre-created local bind volume was mounted at /var/lib/buildkit and received BuildKit state
  • repository-wide go vet ./... still reports the pre-existing unreachable statement in internal/monitoring/agent.go:186

@crohr
crohr marked this pull request as ready for review July 10, 2026 14:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d246a920c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +186 to +190
container, err := inspectBuildkitContainer()
if err != nil {
return err
}
deadline := time.Now().Add(buildkitStopWait)
for time.Now().Before(deadline) {
if exec.Command("pgrep", "-x", "buildkitd").Run() != nil {
action.Infof("buildkitd stopped.")
return nil
if !containerUsesBuildkitVolume(container) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject appended Buildx nodes explicitly

For workflows that pass append: to docker/setup-buildx-action, the primary buildx_buildkit_runs-on0 container still exists and mounts the sticky volume, so this single-container check succeeds even though additional BuildKit nodes are part of the same builder and use non-sticky state. That contradicts the documented contract that an appended node causes a clear failure and lets multi-platform builds silently run on uncached nodes; inspect the builder/node list and fail unless it contains exactly the one sticky node.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f763d0ca1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +120 to +121
if !dockerVolumeMatches(volume, stateRoot) {
return fmt.Errorf("Docker volume %s already exists but is not backed by %s; run runs-on/action before docker/setup-buildx-action", buildkitStateVolumeName, stateRoot)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Recreate stale sticky BuildKit volumes

On reused runners, if a previous sticky BuildKit job is cancelled or otherwise misses this action's post cleanup, the labelled Docker volume can be left behind pointing at that job's old sticky-disk path. The next job gets a different stateRoot, so this unconditional mismatch error prevents all sticky BuildKit setup even though the stale volume was created by this action and could be safely removed/recreated; use the runs-on.stickydisk=buildkit label (or a missing device path) to distinguish stale owned volumes from a real reversed setup-buildx ordering problem.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 515da5fa39

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +82 to +84
if parsed.Scheme != "https" || parsed.Host == "" || parsed.User != nil || (parsed.Path != "" && parsed.Path != "/") || parsed.RawQuery != "" || parsed.Fragment != "" {
return "", fmt.Errorf("invalid ECR registry %q: expected an HTTPS registry host without credentials, path, query, or fragment", value)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve ECR pull-through prefixes

When RUNS_ON_ECR_PULL_THROUGH_CACHE includes the Docker Hub pull-through namespace that ECR uses (for example <registry>/docker-hub), this validation rejects the value and SetBuildkitOutputs clears buildkit-inline-config. In that RunsOn ecr-pull-through environment the new setup-buildx path silently loses the promised Docker Hub mirror and builds fall back to Docker Hub; handle the repository prefix (or route through a proxy/rewrite that can) instead of rejecting it as an invalid registry.

Useful? React with 👍 / 👎.

Comment thread internal/config/config.go
pathInput := action.GetInput("path")
if pathInput != "" {
for _, entry := range strings.Split(pathInput, "\n") {
stickyCacheInput := action.GetInput("sticky_cache")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep legacy cache inputs wired

For workflows still using the existing v2 cache:/path: inputs, this now leaves cfg.StickyCache empty, so HasStickyDiskCache returns false and the action succeeds without setting up any sticky mounts. Since the README/examples still target runs-on/action@v2, users upgrading within v2 will silently lose all sticky caching; either map the legacy inputs to the new record format or fail loudly.

Useful? React with 👍 / 👎.

// volume, then owns final shutdown because the sticky disk must not be
// snapshotted while BuildKit is still writing to it.
func cleanupBuildkit(action *githubactions.Action) error {
stateRootBytes, err := os.ReadFile(buildkitPreparedStateFile)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Drop stale BuildKit markers when setup is skipped

On reused runners, if a previous job was cancelled after setupBuildkit wrote /tmp/runs-on-buildkit-volume but before setup-buildx created the container, a later job with optional sticky_cache: buildkit and no sticky disk returns from Configure without rewriting this marker. The post step then reads the stale marker here, tries to inspect a container from the old job, and fails even though missing optional sticky cache is supposed to warn and continue; clear the marker whenever BuildKit setup is skipped or namespace it to the current job.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant