Publish the FRANKENPHP_MERCURE build — Docker Hub still serves the 2026-07-25 image #26

Closed
opened 2026-08-04 11:25:39 +00:00 by geusebio · 2 comments
Owner

The FRANKENPHP_MERCURE=On support is committed here, but the image serving it has not
reached Docker Hub — matthewbaggett/frankenphp:8.5 is still the 2026-07-25 build.

$ docker rmi -f matthewbaggett/frankenphp:8.5 && docker pull -q matthewbaggett/frankenphp:8.5
$ docker image inspect matthewbaggett/frankenphp:8.5 --format '{{index .RepoDigests 0}}'
matthewbaggett/frankenphp@sha256:793e376186016d74ee14c0cefc6c6908c3c6c1ead2b20305b92b4148b84b29f7

$ docker run --rm --entrypoint sh matthewbaggett/frankenphp:8.5 -c 'grep -in mercure /etc/services.d/frankenphp/run || echo "no match"'
no match
$ docker run --rm --entrypoint sh matthewbaggett/frankenphp:8.5 -c 'grep -n chpst /etc/services.d/frankenphp/run'
37:  chpst -u app frankenphp php-server -r /app/public

That digest matches what the registry currently serves for the 8.5 tag, and the only
build-stamped tags present are 8.2/8.3/8.4/8.5-build-2026-07-25:

$ curl -s -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/matthewbaggett/frankenphp/tags/list
{"name":"matthewbaggett/frankenphp","tags":["8.2","8.2-build-2026-07-25","8.3","8.3-build-2026-07-25","8.4","8.4-build-2026-07-25","8.5","8.5-build-2026-07-25","latest"]}

So the build/push either has not run or did not publish. Worth checking whether the
pipeline is green.

Note that shipping the flag also needs #24 — without an app-writable Caddy data dir the
hub refuses to start, so FRANKENPHP_MERCURE=On would fail on first boot.

The `FRANKENPHP_MERCURE=On` support is committed here, but the image serving it has not reached Docker Hub — `matthewbaggett/frankenphp:8.5` is still the 2026-07-25 build. ``` $ docker rmi -f matthewbaggett/frankenphp:8.5 && docker pull -q matthewbaggett/frankenphp:8.5 $ docker image inspect matthewbaggett/frankenphp:8.5 --format '{{index .RepoDigests 0}}' matthewbaggett/frankenphp@sha256:793e376186016d74ee14c0cefc6c6908c3c6c1ead2b20305b92b4148b84b29f7 $ docker run --rm --entrypoint sh matthewbaggett/frankenphp:8.5 -c 'grep -in mercure /etc/services.d/frankenphp/run || echo "no match"' no match $ docker run --rm --entrypoint sh matthewbaggett/frankenphp:8.5 -c 'grep -n chpst /etc/services.d/frankenphp/run' 37: chpst -u app frankenphp php-server -r /app/public ``` That digest matches what the registry currently serves for the `8.5` tag, and the only build-stamped tags present are `8.2/8.3/8.4/8.5-build-2026-07-25`: ``` $ curl -s -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/matthewbaggett/frankenphp/tags/list {"name":"matthewbaggett/frankenphp","tags":["8.2","8.2-build-2026-07-25","8.3","8.3-build-2026-07-25","8.4","8.4-build-2026-07-25","8.5","8.5-build-2026-07-25","latest"]} ``` So the build/push either has not run or did not publish. Worth checking whether the pipeline is green. Note that shipping the flag also needs #24 — without an `app`-writable Caddy data dir the hub refuses to start, so `FRANKENPHP_MERCURE=On` would fail on first boot.
Author
Owner

Reproduced, and the pipeline is not green. Nothing is wrong with the publish logic or the Docker Hub credentials — the build job never ran at all.

Confirmed independently

matthewbaggett/frankenphp:8.5 still resolves to sha256:793e376186016d74ee14c0cefc6c6908c3c6c1ead2b20305b92b4148b84b29f7, and grep -in mercure /etc/services.d/frankenphp/run inside it finds nothing. Exactly as reported.

Why

The merge of #16 (cd67a7eb) triggered run 257 on main. That run has exactly one task:

35618  257  main  cd67a7eb  failure  Run container tests  2026-08-04T09:56:48Z

There is no Build task for that SHA at all (/actions/runs/257/jobs/1/attempt/1/logs → 404). build declares needs: [test], so when the test job failed the publish job was never scheduled.

The test job failed on infrastructure, not on the diff:

#553 ERROR: target base-alpine-15-assertions: failed to solve:
     Internal: unknown blob sha256:cefb5887e12a5... in history
#531 ERROR: rpc error: code = Unavailable desc = error reading from server: EOF
   Failure!
Container build tests failed in 1563 seconds.

That is the same failure #21 already diagnoses by name ("runs 256, 257: Internal: unknown blob sha256:... in history") — leaked BuildKit builders fill the runner disk, buildkit's GC then evicts blobs an export still references. #21 is the fix for this issue; it should not be duplicated.

Things that are not the problem

  • The --push gate is correct. ${{ github.ref == 'refs/heads/main' && '--push' || '' }} — no ACT/secrets guard on the publish path.
  • Docker Hub credentials are valid. Run 253 built the identical code (25aba96) on the PR branch, and its build job logged Login Succeeded! and completed. It correctly omitted --push because it was not on main ("No output specified for … To push result image into registry use --push").
  • The 8.x-build-2026-07-25 tags come from run 238, whose Build task also failed but had pushed some targets before dying. main has not had a clean green Build since the test gate landed in #9.

Structural note (not filed as a fix — #18/#20/#21 all touch build.yml already)

build is wrapped in nick-fields/retry with max_attempts: 5; test has no retry. So any flaky infra failure in the gate blocks all publishing, while the same flake in the build itself is retried away. Once #21 lands that matters less, but it is why one bad run cost ten days of releases.

The #24 dependency is already satisfied on main

Good news — #24 is stale, filed against the 2026-07-25 image. The fix shipped in the same commit as the Mercure support (25aba96):

  • FrankenPHP.Dockerfile:55install -d -o app -g app /var/cache/frankenphp
  • fs/php-frankenphp/etc/services.d/frankenphp/run:130XDG_DATA_HOME=/var/cache/frankenphp

Verified by building frankenphp-85-base from main locally and booting it with FRANKENPHP_MERCURE=On:

Mercure is enabled, serving a hub at /.well-known/mercure
status: running  health: healthy
$ wget -S -O- http://localhost/.well-known/mercure?topic=test
  HTTP/1.1 401 Unauthorized          # correct: anonymous subscribers rejected
$ ls -la /var/cache/frankenphp/caddy
  -rw------- 1 app app 16384 mercure.db     # bolt transport, app-owned

No mkdir /root/.local: permission denied. The hub starts. One residual, non-fatal: XDG_CONFIG_HOME is still unset, so Caddy logs unable to create folder for config autosave "/root/.config/caddy" — cosmetic, does not block startup, worth a one-line follow-up.

What actually needs to happen

  1. Land #21 so the runner disk stops eating builds.
  2. That merge is itself a push to main, which triggers Build → --push → the Mercure image reaches Docker Hub. This issue closes as a side effect. If #21 is landed some other way, a workflow_dispatch on main does the same job.

No code change is warranted here.

Reproduced, and the pipeline is not green. **Nothing is wrong with the publish logic or the Docker Hub credentials — the build job never ran at all.** ## Confirmed independently `matthewbaggett/frankenphp:8.5` still resolves to `sha256:793e376186016d74ee14c0cefc6c6908c3c6c1ead2b20305b92b4148b84b29f7`, and `grep -in mercure /etc/services.d/frankenphp/run` inside it finds nothing. Exactly as reported. ## Why The merge of #16 (`cd67a7eb`) triggered **run 257** on `main`. That run has exactly **one** task: ``` 35618 257 main cd67a7eb failure Run container tests 2026-08-04T09:56:48Z ``` There is no `Build` task for that SHA at all (`/actions/runs/257/jobs/1/attempt/1/logs` → 404). `build` declares `needs: [test]`, so when the test job failed the publish job was never scheduled. The test job failed on infrastructure, not on the diff: ``` #553 ERROR: target base-alpine-15-assertions: failed to solve: Internal: unknown blob sha256:cefb5887e12a5... in history #531 ERROR: rpc error: code = Unavailable desc = error reading from server: EOF Failure! Container build tests failed in 1563 seconds. ``` That is the same failure #21 already diagnoses by name ("runs 256, 257: `Internal: unknown blob sha256:... in history`") — leaked BuildKit builders fill the runner disk, buildkit's GC then evicts blobs an export still references. **#21 is the fix for this issue; it should not be duplicated.** ## Things that are *not* the problem - **The `--push` gate is correct.** `${{ github.ref == 'refs/heads/main' && '--push' || '' }}` — no `ACT`/`secrets` guard on the publish path. - **Docker Hub credentials are valid.** Run 253 built the identical code (`25aba96`) on the PR branch, and its build job logged `Login Succeeded!` and completed. It correctly omitted `--push` because it was not on `main` ("No output specified for … To push result image into registry use `--push`"). - The `8.x-build-2026-07-25` tags come from run 238, whose Build task also failed but had pushed some targets before dying. `main` has not had a clean green Build since the test gate landed in #9. ## Structural note (not filed as a fix — #18/#20/#21 all touch build.yml already) `build` is wrapped in `nick-fields/retry` with `max_attempts: 5`; `test` has no retry. So any flaky infra failure in the gate blocks all publishing, while the same flake in the build itself is retried away. Once #21 lands that matters less, but it is why one bad run cost ten days of releases. ## The #24 dependency is already satisfied on main Good news — #24 is **stale**, filed against the 2026-07-25 image. The fix shipped in the same commit as the Mercure support (`25aba96`): - `FrankenPHP.Dockerfile:55` — `install -d -o app -g app /var/cache/frankenphp` - `fs/php-frankenphp/etc/services.d/frankenphp/run:130` — `XDG_DATA_HOME=/var/cache/frankenphp` Verified by building `frankenphp-85-base` from `main` locally and booting it with `FRANKENPHP_MERCURE=On`: ``` Mercure is enabled, serving a hub at /.well-known/mercure status: running health: healthy $ wget -S -O- http://localhost/.well-known/mercure?topic=test HTTP/1.1 401 Unauthorized # correct: anonymous subscribers rejected $ ls -la /var/cache/frankenphp/caddy -rw------- 1 app app 16384 mercure.db # bolt transport, app-owned ``` No `mkdir /root/.local: permission denied`. The hub starts. One residual, non-fatal: `XDG_CONFIG_HOME` is still unset, so Caddy logs `unable to create folder for config autosave "/root/.config/caddy"` — cosmetic, does not block startup, worth a one-line follow-up. ## What actually needs to happen 1. Land #21 so the runner disk stops eating builds. 2. That merge is itself a push to `main`, which triggers Build → `--push` → the Mercure image reaches Docker Hub. This issue closes as a side effect. If #21 is landed some other way, a `workflow_dispatch` on `main` does the same job. No code change is warranted here.
Author
Owner

Verified against the registry rather than the merge — the image is out and it works.

The artifact

$ docker rmi -f matthewbaggett/frankenphp:8.5 && docker pull -q matthewbaggett/frankenphp:8.5
$ docker image inspect matthewbaggett/frankenphp:8.5 --format '{{index . "RepoDigests" 0}}'
matthewbaggett/frankenphp@sha256:4fbbfeca47d6bf7fc2bd29e2bc272ccabd67da861812f9a1cbe3d8cd2826bcd0

Was sha256:793e376186016d74ee14c0cefc6c6908c3c6c1ead2b20305b92b4148b84b29f7. Build-stamped tags now present for every version:

8.2-build-2026-08-04  8.3-build-2026-08-04  8.4-build-2026-08-04  8.5-build-2026-08-04

Mercure is in the run script, where the reporter found nothing before:

$ docker run --rm --entrypoint sh matthewbaggett/frankenphp:8.5 -c 'grep -in mercure /etc/services.d/frankenphp/run'
 95:  # Mercure is a Caddy module bundled with FrankenPHP. Turning it on drops a
 99:  rm -f /etc/frankenphp/conf.d/mercure.caddy
100:  if [ "${FRANKENPHP_MERCURE,,}" = "on" ]; then

It actually starts

The #24 dependency mattered, so this is the published image booted with the flag on, not a local build:

$ docker run -d -e FRANKENPHP_MERCURE=On -v ./app:/app matthewbaggett/frankenphp:8.5
status=running  health=healthy
errors matching 'permission denied|invalid transport|level":"error':  (none)

$ wget -S -O- 'http://localhost/.well-known/mercure?topic=t'
  HTTP/1.1 401 Unauthorized        # correct — anonymous subscribers rejected

$ ls -l /var/cache/frankenphp/caddy/mercure.db
-rw-------  1 app app 16384 mercure.db

No mkdir /root/.local: permission denied, and the bolt transport has its data directory. The /root/.config/caddy autosave warning I saw on an earlier local build is also gone, courtesy of #31.

What was actually wrong

Two stacked pipeline faults, no defect in the Mercure code itself:

  1. Leaked BuildKit builders exhausted the runner disk, so the test gate failed and needs: [test] meant the publish job was never scheduled — fixed by #21.
  2. The concurrency group cancelled main's build on every merge. Run 265 died 7s after the next merge landed, partway through pushing layers to Docker Hub. That is also the likely origin of the incomplete 2026-07-25 tag set: a publish cancelled mid-push updates some targets and not others.

#33 addresses the second by keying main's group on the commit sha.

Caveat worth recording: the publish that finally succeeded (run 286) was the last main push in a burst of three, and runs 284 and 285 were cancelled despite both already carrying #33's fix. So this issue is resolved, but #33 is not yet proven to work — see my note there. It is possible main simply got a quiet 30 minutes rather than being protected.

Verified against the registry rather than the merge — the image is out and it works. ## The artifact ``` $ docker rmi -f matthewbaggett/frankenphp:8.5 && docker pull -q matthewbaggett/frankenphp:8.5 $ docker image inspect matthewbaggett/frankenphp:8.5 --format '{{index . "RepoDigests" 0}}' matthewbaggett/frankenphp@sha256:4fbbfeca47d6bf7fc2bd29e2bc272ccabd67da861812f9a1cbe3d8cd2826bcd0 ``` Was `sha256:793e376186016d74ee14c0cefc6c6908c3c6c1ead2b20305b92b4148b84b29f7`. Build-stamped tags now present for every version: ``` 8.2-build-2026-08-04 8.3-build-2026-08-04 8.4-build-2026-08-04 8.5-build-2026-08-04 ``` Mercure is in the run script, where the reporter found nothing before: ``` $ docker run --rm --entrypoint sh matthewbaggett/frankenphp:8.5 -c 'grep -in mercure /etc/services.d/frankenphp/run' 95: # Mercure is a Caddy module bundled with FrankenPHP. Turning it on drops a 99: rm -f /etc/frankenphp/conf.d/mercure.caddy 100: if [ "${FRANKENPHP_MERCURE,,}" = "on" ]; then ``` ## It actually starts The #24 dependency mattered, so this is the published image booted with the flag on, not a local build: ``` $ docker run -d -e FRANKENPHP_MERCURE=On -v ./app:/app matthewbaggett/frankenphp:8.5 status=running health=healthy errors matching 'permission denied|invalid transport|level":"error': (none) $ wget -S -O- 'http://localhost/.well-known/mercure?topic=t' HTTP/1.1 401 Unauthorized # correct — anonymous subscribers rejected $ ls -l /var/cache/frankenphp/caddy/mercure.db -rw------- 1 app app 16384 mercure.db ``` No `mkdir /root/.local: permission denied`, and the bolt transport has its data directory. The `/root/.config/caddy` autosave warning I saw on an earlier local build is also gone, courtesy of #31. ## What was actually wrong Two stacked pipeline faults, no defect in the Mercure code itself: 1. **Leaked BuildKit builders** exhausted the runner disk, so the test gate failed and `needs: [test]` meant the publish job was never scheduled — fixed by #21. 2. **The concurrency group cancelled main's build on every merge.** Run 265 died 7s after the next merge landed, partway through `pushing layers` to Docker Hub. That is also the likely origin of the incomplete 2026-07-25 tag set: a publish cancelled mid-push updates some targets and not others. #33 addresses the second by keying main's group on the commit sha. **Caveat worth recording:** the publish that finally succeeded (run 286) was the *last* main push in a burst of three, and runs 284 and 285 were cancelled despite both already carrying #33's fix. So this issue is resolved, but #33 is not yet proven to work — see my note there. It is possible main simply got a quiet 30 minutes rather than being protected.
Sign in to join this conversation.
No labels
No milestone
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
Grey.ooo/docker#26
No description provided.