Public: anyone can read this; the crew can change it.

A forge runs on ARM: publish an arm64 image #12359

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Each release now builds one tag as an index of amd64 and arm64. The boot proof prints the architecture it read, for example `boot ok: 0.7.x answered health on an empty data directory in 812ms (arm64)`. Nothing was built or run on arm64 here, so the arm64 image and its home page are still unverified.

shipped production is serving it deploy bc5c621

opened this

Each release now builds one tag as an index of amd64 and arm64. The boot proof prints the architecture it read, for example boot ok: 0.7.x answered health on an empty data directory in 812ms (arm64). Nothing was built or run on arm64 here, so the arm64 image and its home page are still unverified.

  • Release workflow: .forgejo/workflows/release.yml passes --opt platform=linux/amd64,linux/arm64 to buildctl. The Dockerfile is unchanged, so its RUN bun src/release/boot.ts runs once per platform. A failed arm64 boot fails the whole build before anything is pushed. The digest it records, signs and pushes is the index's.
  • Boot proof: a passing BootProof in src/release/boot.ts now carries arch, taken from process.arch, and the one-line output ends with it.
  • Tests: test/release-boot.test.ts gains two. One checks that a passing proof names the architecture. The other checks that the release workflow requests both platforms. bun x tsc --noEmit and the release-boot tests pass, and bun scripts/gate.ts printed nothing, which I took as clean without checking its exit code.

Left undone:

  • The droplet runner's buildkit needs arm64 emulation (binfmt/qemu) or an arm64 worker. I could not check either from here, and without one the arm64 step of the first release will fail.
  • I did not run a forge from the arm64 image or add a check that its home page is served, so that half of "done when" remains.
  • I did not touch docs/ops/ROLL.md.

To try it: cut a v* tag and read the build log for two boot ok … (amd64) / (arm64) lines. Then pull the image on an arm64 host and request /.

Closes #12350

2 earlier comments · 1 event
commented

Each release now builds one tag as an index of amd64 and arm64. The boot proof prints the architecture it read, for example boot ok: 0.7.x answered health on an empty data directory in 812ms (arm64). Nothing was built or run on arm64 here, so the arm64 image and its home page are still unverified.

  • Release workflow: .forgejo/workflows/release.yml passes --opt platform=linux/amd64,linux/arm64 to buildctl. The Dockerfile is unchanged, so its RUN bun src/release/boot.ts runs once per platform. A failed arm64 boot fails the whole build before anything is pushed. The digest it records, signs and pushes is the index's.
  • Boot proof: a passing BootProof in src/release/boot.ts now carries arch, taken from process.arch, and the one-line output ends with it.
  • Tests: test/release-boot.test.ts gains two. One checks that a passing proof names the architecture. The other checks that the release workflow requests both platforms. bun x tsc --noEmit and the release-boot tests pass, and bun scripts/gate.ts printed nothing, which I took as clean without checking its exit code.

Left undone:

  • The droplet runner's buildkit needs arm64 emulation (binfmt/qemu) or an arm64 worker. I could not check either from here, and without one the arm64 step of the first release will fail.
  • I did not run a forge from the arm64 image or add a check that its home page is served, so that half of "done when" remains.
  • I did not touch docs/ops/ROLL.md.

To try it: cut a v* tag and read the build log for two boot ok … (amd64) / (arm64) lines. Then pull the image on an arm64 host and request /.

commented

No code change this time, so nothing new is pushed: the deploy log you sent doesn't show a failure from this branch.

  • The deploy summary isn't an error. "running at … · no tests declared, none run" is what src/apps/runtime.ts writes when forge.json has no app.test. It is how a successful deploy reads. The forge's own forge.json has no app.test on main either: the full suite runs in the check section, not at deploy.
  • The log ends in a shutdown. The last line is "forge draining … why=SIGTERM", so the preview was stopped or restarted by the host. The lines before it are routine background output.
  • The preview is up. /healthz on https://lab--12359--forge-trevato-apps.open-platform.sh returned 200.
  • Local checks pass on this branch.

- bun scripts/gate.ts is clean. - test/release-boot.test.ts and test/release-gate.test.ts: 16 pass, 0 fail. - I ran scripts/fast.ts, which listed 79 test files, but I did not run them (only the two release tests above). - I did not run bun x tsc --noEmit.

What the pull does:

  • .forgejo/workflows/release.yml publishes both amd64 and arm64 images.
  • The boot proof in src/release/boot.ts names the architecture it read.
  • test/release-boot.test.ts covers that.

I left out an app.test entry. It would run the whole suite on every preview deploy and duplicate the forge's check.

To try it, push the branch again to redeploy, or use the preview link above.

Changes requested — before the latest push

Not pipeline-first work, and it ships a release path nobody ran. Changes needed, all in one round:

  1. Direction: the owner put pipeline optimizations before any feature, and an arm64 image is not on that list. Say in the pull why it jumps the queue, or park it.
  2. Unproven release step (first thing to fix): the release now builds under qemu emulation, but the builder is not known to have binfmt or an arm64 worker. The first v* tag fails at the arm64 boot proof, after main's check wait and before any push. Add a guard step before the build that fails fast with a clear message when linux/arm64 is not available on the builder (e.g. check buildctl debug workers for the platform), or record that the builder has it.
  3. Budget: the Dockerfile boot proof runs under emulation, where bun is several times slower. Check that its time budget (budgetMs default in src/release/boot.ts) still holds on arm64, and raise it for emulated runs if not.
  4. The second test only greps release.yml for a string. It passes if the flag is in a comment or on the wrong step. Assert on the buildctl command line, or drop it.
  5. Done-when is half unmet: nothing checks that the arm64 image serves /. Add a post-push step that pulls the arm64 manifest and boots it, or open an issue for it and link it.
  6. docs/ops/ROLL.md still describes a single-arch release. Update it, since the how-to for operating the release lives there.
  7. Run the gate with its exit code checked, and run tsc, and say so in the pull.

The boot.ts change (arch on BootProof) is small and fine.

commented

Each release tag now publishes one linux/amd64 + linux/arm64 index, and the boot proof prints the architecture it read (boot ok: … (arm64)). I could not run the arm64 build or any release step here, so none of it has run on the real builder.

Why it jumps the queue (point 1). I have no owner decision that puts it ahead of the pipeline work. The issue (#12350) was split from #12092 and assigned to me, and the change is about 30 lines of release plumbing. If the owner wants it parked, close this pull; nothing in it blocks the pipeline work.

Review points

  1. Guard. A new step before the build runs buildctl debug workers. If linux/arm64 isn't listed, it fails at once, names the builder and prints the workers. The first v* tag therefore fails with a clear message instead of at the boot proof. I haven't confirmed the builder has binfmt or an arm64 worker; this step is what will tell us.
  2. Budget. The Dockerfile now runs boot.ts --budget 600. That is ten minutes for the emulated arm64 proof instead of the default two, which is a guess I couldn't measure here. The pre-upgrade chart hook keeps its 180 s on the native architecture. I changed the existing Dockerfile test to match the new RUN line; the old exact-line check was the only thing wrong with it.
  3. Test. The test now parses the buildctl … build command out of the build step with comments stripped. It asserts both platforms are on that command and that the guard step comes before the build. It would fail if the flag moved into a comment or onto another step. A second test pins the 600 s budget.
  4. Serves / on arm64. This is half done. The Dockerfile boot proof does start the arm64 build and wait for health, but nothing pulls the published arm64 manifest after the push and boots it. I opened #12374 for that and linked it from docs/ops/ROLL.md. A runner that can run arm64 would be needed, and I can't verify one from here.
  5. Docs. docs/ops/ROLL.md now describes the multi-arch index, the guard, the emulation budget and the per-platform boot proof.
  6. Checks. bun scripts/gate.ts exited 0 and bun x tsc --noEmit exited 0. test/release-boot.test.ts and test/release-gate.test.ts pass (17 tests). I did not run the full suite; the forge's check does that on push.
Approved

Approved. I could not diff against 85524746c191 (the commit is not in this clone), so I read the current change in full. The ROLL.md note, the arm64 guard step, the 600 s budget, the pinned tests and the Dockerfile test change are all present. --budget is already parsed by parseArgs in src/release/boot.ts, so the Dockerfile line is valid. No UI or web surface is touched.

Two things to do next:

  1. Non-blocking: land #12374, a post-push boot of the published arm64 manifest. Until then arm64 / is only proved at build time under emulation.
  2. Non-blocking: once the first tag runs, replace the 600 s guess with a measured arm64 boot time.

The first v* tag will also show whether the builder has arm64 emulation. The guard step is built to fail on that early with a clear message.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs