perf(build-check): replace login-action + setup-buildx-action with the CLI #84

Merged
ryangr0 merged 1 commit from perf/build-check-cli into main 2026-08-05 11:25:56 +00:00
Owner

The build step in build-check already drives docker buildx build directly. Only the two setup steps were actions — and act charges the full git history of an action repository on every job:

action mirror size cost per job what it does
docker/login-action@v3 134 MB 27.7s one docker login
docker/setup-buildx-action@v4 66 MB 15.9s one docker buildx create

Measured on run 224. Behaviour is unchanged, including the conditional skip when HARBOR_ROBOT_TOKEN is absent and the buildkit image pinned to the Harbor proxy (run 125's flake).

Two things the actions were doing that are now explicit

The builder gets a unique name per job. buildx keeps its builder registry in the client's ~/.docker/buildx — empty in a fresh pod — while the buildkit container lives on the shared per-node dind daemon and outlives it. A fixed name collides with a container the client has no record of. This is why setup-buildx-action generated a UUID name too.

The builder is now removed afterwards. setup-buildx-action did that in a post-step. Nothing here did, so every build-check job so far has left a buildkit container running on its node.

What's left

actions/checkout is the only third-party action remaining in this workflow. That one needs the mini-mirror work, not a rewrite.

⚠️ This PR does not exercise its own change

build-check only runs when a file under ops/docker/ changes, and this PR touches only .forgejo/. The ci-runner PR that follows will be the first to run it — merge this one first so that PR's build-check becomes the test.

Companion to workflows #42, which does the same to the shared fast composite.

The build step in `build-check` already drives `docker buildx build` directly. Only the two setup steps were actions — and act charges the **full git history of an action repository on every job**: | action | mirror size | cost per job | what it does | |---|---:|---:|---| | `docker/login-action@v3` | 134 MB | 27.7s | one `docker login` | | `docker/setup-buildx-action@v4` | 66 MB | 15.9s | one `docker buildx create` | Measured on run 224. Behaviour is unchanged, including the conditional skip when `HARBOR_ROBOT_TOKEN` is absent and the buildkit image pinned to the Harbor proxy (run 125's flake). ## Two things the actions were doing that are now explicit **The builder gets a unique name per job.** buildx keeps its builder registry in the *client's* `~/.docker/buildx` — empty in a fresh pod — while the buildkit *container* lives on the shared per-node dind daemon and outlives it. A fixed name collides with a container the client has no record of. This is why `setup-buildx-action` generated a UUID name too. **The builder is now removed afterwards.** `setup-buildx-action` did that in a post-step. Nothing here did, so **every build-check job so far has left a buildkit container running on its node.** ## What's left `actions/checkout` is the only third-party action remaining in this workflow. That one needs the mini-mirror work, not a rewrite. ## ⚠️ This PR does not exercise its own change `build-check` only runs when a file under `ops/docker/` changes, and this PR touches only `.forgejo/`. The ci-runner PR that follows will be the first to run it — merge this one first so that PR's `build-check` becomes the test. Companion to [workflows #42](https://forgejo.webgrip.dev/webgrip/workflows/pulls/42), which does the same to the shared fast composite.
perf(build-check): replace login-action + setup-buildx-action with the CLI
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 2s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 16s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
4d0aea0507
The build step in this job already drives `docker buildx build` directly. Only the two setup
steps were actions, and act charges the full git history of an action repository on every job:
docker/login-action is 134 MB / 27.7s and docker/setup-buildx-action is 66 MB / 15.9s (measured
run 224) to run one `docker login` and one `docker buildx create`.

Behaviour is unchanged, including the conditional skip when HARBOR_ROBOT_TOKEN is absent and the
buildkit image pinned to the Harbor proxy (run 125's flake).

Two things the actions were doing that are now explicit:

- The builder gets a unique name per job. buildx keeps its builder registry in the CLIENT's
  ~/.docker/buildx, which is empty in a fresh pod, while the buildkit CONTAINER lives on the
  shared per-node dind daemon and outlives it — a fixed name would collide with a container the
  client has no record of. This is why setup-buildx-action generated a UUID name too.
- The builder is removed afterwards. setup-buildx-action did that in a post-step; nothing here
  did, so every build-check job has been leaving a buildkit container on its node.

After this the only third-party action left in the workflow is actions/checkout, which needs the
mini-mirror work rather than a rewrite.

NOTE: this job only runs when a file under ops/docker/ changes, so this PR does not exercise its
own change. The ci-runner PR that follows will.
ryangr0 force-pushed perf/build-check-cli from 4d0aea0507
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 2s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 16s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
to 4f1f130ffc
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 3s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 27s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
2026-08-02 13:42:50 +00:00
Compare
ryangr0 force-pushed perf/build-check-cli from 4f1f130ffc
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 3s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 27s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
to bb22a82c4a
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 3s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 21s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
2026-08-02 20:48:01 +00:00
Compare
Author
Owner

Correction: I claimed above that the old path left buildkit containers on the node. That is wrong. act DOES run action post-steps; they are folded into 'Complete job' rather than shown as their own step, which is why I missed them. Run 226 ends with 'Post Set up Docker Buildx' calling docker buildx rm, and 'Post Log in to Harbor' calling docker logout. So the cleanup step is not new work, it is the cleanup that already existed made visible. My replacement was also missing the docker logout, which is a real behaviour regression I introduced; it is restored now. Nothing was leaking before this PR.

Correction: I claimed above that the old path left buildkit containers on the node. That is wrong. act DOES run action post-steps; they are folded into 'Complete job' rather than shown as their own step, which is why I missed them. Run 226 ends with 'Post Set up Docker Buildx' calling docker buildx rm, and 'Post Log in to Harbor' calling docker logout. So the cleanup step is not new work, it is the cleanup that already existed made visible. My replacement was also missing the docker logout, which is a real behaviour regression I introduced; it is restored now. Nothing was leaking before this PR.
ryangr0 force-pushed perf/build-check-cli from bb22a82c4a
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 3s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 21s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
to aed71dfdf1
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 19s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 59s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
2026-08-05 04:22:42 +00:00
Compare
Author
Owner

Rebased onto current main (picks up the #83 seccomp fix) and extended: the builder now prefers forgejo-buildkitd - the shared per-node daemon, confirmed live at 3/3 Ready with workers responding - and falls back to a throwaway docker-container builder when it does not answer. A throwaway builder's LOCAL cache dies with it, so build-check has always been locally cache-cold and leaning entirely on cache-from type=registry, a network round-trip per layer for what should be a disk read. That matters most in this job because it runs more often than any other. Teardown now runs only on the docker-container path, since the remote driver creates nothing remotely - that is the objection about having to remove the builder, answered. Verified before switching: no Dockerfile in ops/docker uses RUN --security=insecure or --network=host, so dropping the entitlement flags on the remote path changes nothing today, and if one ever does it fails loudly rather than silently building something different.

Rebased onto current main (picks up the #83 seccomp fix) and extended: the builder now prefers forgejo-buildkitd - the shared per-node daemon, confirmed live at 3/3 Ready with workers responding - and falls back to a throwaway docker-container builder when it does not answer. A throwaway builder's LOCAL cache dies with it, so build-check has always been locally cache-cold and leaning entirely on cache-from type=registry, a network round-trip per layer for what should be a disk read. That matters most in this job because it runs more often than any other. Teardown now runs only on the docker-container path, since the remote driver creates nothing remotely - that is the objection about having to remove the builder, answered. Verified before switching: no Dockerfile in ops/docker uses RUN --security=insecure or --network=host, so dropping the entitlement flags on the remote path changes nothing today, and if one ever does it fails loudly rather than silently building something different.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
webgrip/infrastructure!84
No description provided.