Skip to content

Commit 119ba54

Browse files
ostermanclaude
andcommitted
docs(fixes): add fix records for Docker build mirror and writer race
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 3339e02 commit 119ba54

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Fix: Release Docker build no longer pulls buildkit/binfmt images from AWS public ECR
2+
3+
**Date:** 2026-08-06
4+
5+
## Summary
6+
7+
The release `docker` job in `.github/workflows/build.yml` was rate-limited pulling its buildx
8+
builder (`moby/buildkit`) and QEMU binfmt images from `public.ecr.aws`. Bumped
9+
`cloudposse/github-action-docker-build-push` to v3.1.0 (Google-mirrored buildkit image by
10+
default) and explicitly overrode the action's `binfmt-image` input to the equivalent
11+
Google-mirrored `tonistiigi/binfmt` image, since that input still defaults to `public.ecr.aws`
12+
even at v3.1.0.
13+
14+
## Context
15+
16+
CI run for `cloudposse/atmos` release build (job at
17+
`https://github.com/cloudposse/atmos/actions/runs/31040133433/job/92444923915`) failed with
18+
`jq: error (at inspect.json:78): Cannot iterate over null (null)` in the action's post-build
19+
summary step, which turned out to be a separate, already-tracked upstream bug
20+
(`cloudposse/github-action-docker-build-push#102`, cosmetic — the image itself built and pushed
21+
fine) and not something fixable from this repo. On the next attempted run, the job failed again,
22+
this time on rate limiting while pulling the buildx builder image from `public.ecr.aws`.
23+
24+
## Changes
25+
26+
- `.github/workflows/build.yml`: bumped
27+
`uses: cloudposse/github-action-docker-build-push@...` from v3.0.0
28+
(`f06d0f4bd286898b613412d2fcc6622e5b68bbdc`) to v3.1.0
29+
(`02993d675b44dcc7082e6de7485c1ff8740bce9d`), which changes the action's `driver-opts` default
30+
from `image=public.ecr.aws/vend/moby/buildkit:buildx-stable-1` to
31+
`image=mirror.gcr.io/moby/buildkit:buildx-stable-1`.
32+
- `.github/workflows/build.yml`: added an explicit `binfmt-image:
33+
mirror.gcr.io/tonistiigi/binfmt:qemu-v7.0.0` input, since the action's `binfmt-image` default
34+
(`public.ecr.aws/eks-distro-build-tooling/binfmt-misc:qemu-v7.0.0`) still pulls from AWS public
35+
ECR and has no upstream fix yet. `binfmt-image` passes straight through to
36+
`docker/setup-qemu-action`'s `image` input, so it can be overridden directly without waiting on
37+
upstream.
38+
39+
## Validation
40+
41+
- Diffed `cloudposse/github-action-docker-build-push` v3.0.0...v3.1.0 upstream: only the
42+
`driver-opts` default change and an unrelated arm64 `jq` install fix; no input/output contract
43+
changes to any input this workflow uses (`registry`, `organization`, `repository`, `login`,
44+
`password`, `platforms`, `file`, `build-args`).
45+
- Confirmed `public.ecr.aws/eks-distro-build-tooling/binfmt-misc:qemu-v7.0.0` is an AWS rebuild of
46+
upstream `tonistiigi/binfmt`, which publishes the identical `qemu-v7.0.0` tag on Docker Hub.
47+
- Verified live against the registries: `docker buildx imagetools inspect
48+
mirror.gcr.io/tonistiigi/binfmt:qemu-v7.0.0` and the `docker.io/tonistiigi/binfmt:qemu-v7.0.0`
49+
equivalent both resolve to the same digest
50+
(`sha256:66e11bea77a5ea9d6f0fe79b57cd2b189b5d15b93a2bdb925be22949232e4e55`) across all 7
51+
published platforms, and `docker pull` of the mirrored tag succeeds.
52+
- This is a `release`-triggered workflow (`on.release.types: [published]`), so it cannot be
53+
exercised by a normal PR run; verification here is by inspection plus the live registry checks
54+
above. The next actual release's Docker build job should be watched once to confirm no more
55+
rate-limit failures.
56+
- `./custom-gcl run --new-from-rev=origin/main` — 0 issues.
57+
58+
## Follow-ups
59+
60+
None. The action's `binfmt-image` default itself is still AWS-ECR-backed upstream with no fix in
61+
flight; if it starts rate-limiting independently of this override, no further action is needed
62+
here since this repo already pins its own Google-mirrored value.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Fix: `LinePrefixWriter` held its shared output lock per line instead of per flush
2+
3+
**Date:** 2026-08-06
4+
5+
## Summary
6+
7+
`pkg/io/line_prefix_writer.go`'s `writeLine` acquired and released the shared `writeMu` once per
8+
line instead of once per flush. When a single `Write()` call produced multiple lines (e.g. a
9+
hook's buffered `"progress\r" + "complete\n"` update), the lock was released between those lines,
10+
letting a concurrently running node's writer interleave its own line in between and corrupt the
11+
expected per-node contiguous output block. `Write` and `Flush` now hold `writeMu` for their whole
12+
flush operation, and `writeLine` is a lock-free helper that callers must call while holding it.
13+
14+
## Context
15+
16+
The macOS "Acceptance Tests" CI job (job ID 92489708710) failed with:
17+
18+
```
19+
--- FAIL: TestExecuteTerraformConcurrentHooksUseNodeWriters (0.00s)
20+
terraform_test.go:510:
21+
Error: "[dev/app] hook progress\n[dev/db] hook progress\n[dev/db] hook complete\n[dev/app] hook complete\n" does not contain "[dev/app] hook progress\n[dev/app] hook complete\n"
22+
```
23+
24+
Both `pkg/io/line_prefix_writer.go` and this test landed together in a prior PR (#2860, "render
25+
concurrent carriage-return updates safely"), which correctly converts `\r` progress updates into
26+
discrete prefixed lines but left a lock-granularity gap that let two concurrent nodes' lines
27+
interleave mid-block. Locally the test only failed intermittently (timing-dependent), which is
28+
why it passed in earlier local runs before reproducing it under `-race -count=N`.
29+
30+
## Changes
31+
32+
- `pkg/io/line_prefix_writer.go`: `Write()` and `Flush()` now acquire `w.writeMu` once, covering
33+
the entire call to `flushCompleteLinesLocked()` (and, in `Flush()`, the trailing partial-line
34+
write too), instead of `writeLine()` acquiring/releasing `writeMu` on every individual line.
35+
`writeLine()` no longer touches `writeMu` itself; its doc comment now states callers must hold
36+
it. Lock ordering is unchanged (per-writer `w.mu` outer, shared `writeMu` inner), so this
37+
doesn't introduce new deadlock risk.
38+
39+
## Validation
40+
41+
- Reproduced the race before the fix: `go test ./pkg/scheduler/adapters/... -run
42+
TestExecuteTerraformConcurrentHooksUseNodeWriters -race -count=200` failed intermittently
43+
(multiple failures across 200 iterations, each showing the same interleaved-block pattern).
44+
- After the fix, the same command passed 200/200 under `-race`.
45+
- Full suites for touched/adjacent packages passed under `-race -count=1`: `pkg/io`,
46+
`pkg/scheduler`, `pkg/scheduler/adapters`, `pkg/component/container`, `pkg/workflow`.
47+
- `./custom-gcl run --new-from-rev=origin/main` — 0 issues.
48+
- `gofmt -l pkg/io/line_prefix_writer.go` — no output (already formatted).
49+
50+
## Follow-ups
51+
52+
None.

0 commit comments

Comments
 (0)