chore(runner-image): bake Playwright browsers into the ephemeral runner image #349

Öppen
öppnade 2026-08-02 16:06:38 +00:00 av supernaut · 0 kommentarer
Ägare

bitborg-web is adopting Playwright for end-to-end tests and needs browsers on the CI runner. The
runner image currently carries no browser and no browser shared libraries.

A default playwright install on Debian 13 x64 downloads roughly 503 MB — Chromium 178.6 MB and
Chrome Headless Shell 117.4 MB from Google's Chrome-for-Testing bucket, Firefox 108.1 MB and WebKit
96.9 MB from the Playwright CDN, plus ffmpeg — and install-deps then apt-installs 100-plus shared
library packages. On an M - Medium VM that is roughly 2.5 to 4 minutes added to every job, on an
image that boots cold every time because min_idle is 0.

Bake them instead, using the pattern scripts/bake-runner-image.sh already uses for
RUNNER_VERSION, TOFU_VERSION, NODE_VERSION and GITLEAKS_VERSION.

Scope

  • Add a PLAYWRIGHT_VERSION env pin to scripts/bake-runner-image.sh, next to the existing pins,
    with the same "single source of truth for the CI pin" comment.
  • In the remote install block, run
    PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright npx --yes playwright@"${PLAYWRIGHT_VERSION}" install --with-deps
    and export PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright system-wide so every job sees it.
  • Add the sanity check to the bake script's existing verify pass.
  • Add a row to the toolchain table in roles/runner-controller/files/README-runner-image.md,
    naming the version pin and where it lives.
  • Re-bake with --replace.

Cost

About 1.5 GB of image growth, which at 0.54 SEK per GB-month of Glance storage is roughly
0.8 SEK/month. The 40 GB boot volume is unchanged. Against that: about 2.5 to 4 minutes saved on
every bitborg-web CI job.

Measure during the bake

Whether a larger image lengthens boot-volume creation. The ephemeral VMs boot from a Cinder volume
created from the image on every job and min_idle is 0, so if the platform does a full copy rather
than a Ceph clone this shows up as cold-start latency on every job. If it does, that changes the
recommendation and we should reconsider a slimmer bake (headless shell plus WebKit only, roughly
215 MB).

Version coupling, and why the workflow still calls playwright install

Playwright refuses to run against a browser revision that does not match its package version, so
the baked image is coupled to the @playwright/test pin in bitborg-web. The workflow therefore
keeps an idempotent playwright install --with-deps step: when the revisions match it prints
"browsers are already installed" and downloads nothing, and when a Renovate bump outruns the image
it self-heals slowly rather than failing. Add playwright to a Renovate group whose description
says to re-bake.

Follow-on

This unblocks the standing TODO in opentofu/ephemeral-runners.tofu to tighten runner egress from
"443 to 0.0.0.0/0" toward Forgejo and the registry only — impossible while every job must reach two
third-party CDNs. It also removes a per-pull-request runtime dependency on two US-operated CDNs,
in the same spirit as pointing DEFAULT_ACTIONS_URL at data.forgejo.org.

Acceptance

  • A fresh ephemeral VM has the browsers under /opt/ms-playwright and
    PLAYWRIGHT_BROWSERS_PATH set for job shells
  • pnpm exec playwright install --with-deps in a real job completes in about a second
  • Boot-to-runner-ready latency measured before and after, and recorded on this issue
`bitborg-web` is adopting Playwright for end-to-end tests and needs browsers on the CI runner. The runner image currently carries no browser and no browser shared libraries. A default `playwright install` on Debian 13 x64 downloads roughly 503 MB — Chromium 178.6 MB and Chrome Headless Shell 117.4 MB from Google's Chrome-for-Testing bucket, Firefox 108.1 MB and WebKit 96.9 MB from the Playwright CDN, plus ffmpeg — and `install-deps` then apt-installs 100-plus shared library packages. On an M - Medium VM that is roughly 2.5 to 4 minutes added to every job, on an image that boots cold every time because `min_idle` is 0. Bake them instead, using the pattern `scripts/bake-runner-image.sh` already uses for `RUNNER_VERSION`, `TOFU_VERSION`, `NODE_VERSION` and `GITLEAKS_VERSION`. ### Scope - Add a `PLAYWRIGHT_VERSION` env pin to `scripts/bake-runner-image.sh`, next to the existing pins, with the same "single source of truth for the CI pin" comment. - In the remote install block, run `PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright npx --yes playwright@"${PLAYWRIGHT_VERSION}" install --with-deps` and export `PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright` system-wide so every job sees it. - Add the sanity check to the bake script's existing verify pass. - Add a row to the toolchain table in `roles/runner-controller/files/README-runner-image.md`, naming the version pin and where it lives. - Re-bake with `--replace`. ### Cost About 1.5 GB of image growth, which at 0.54 SEK per GB-month of Glance storage is roughly 0.8 SEK/month. The 40 GB boot volume is unchanged. Against that: about 2.5 to 4 minutes saved on every bitborg-web CI job. ### Measure during the bake Whether a larger image lengthens boot-volume creation. The ephemeral VMs boot from a Cinder volume created from the image on every job and `min_idle` is 0, so if the platform does a full copy rather than a Ceph clone this shows up as cold-start latency on every job. If it does, that changes the recommendation and we should reconsider a slimmer bake (headless shell plus WebKit only, roughly 215 MB). ### Version coupling, and why the workflow still calls `playwright install` Playwright refuses to run against a browser revision that does not match its package version, so the baked image is coupled to the `@playwright/test` pin in bitborg-web. The workflow therefore keeps an idempotent `playwright install --with-deps` step: when the revisions match it prints "browsers are already installed" and downloads nothing, and when a Renovate bump outruns the image it self-heals slowly rather than failing. Add `playwright` to a Renovate group whose description says to re-bake. ### Follow-on This unblocks the standing TODO in `opentofu/ephemeral-runners.tofu` to tighten runner egress from "443 to 0.0.0.0/0" toward Forgejo and the registry only — impossible while every job must reach two third-party CDNs. It also removes a per-pull-request runtime dependency on two US-operated CDNs, in the same spirit as pointing `DEFAULT_ACTIONS_URL` at data.forgejo.org. ### Acceptance - [ ] A fresh ephemeral VM has the browsers under `/opt/ms-playwright` and `PLAYWRIGHT_BROWSERS_PATH` set for job shells - [ ] `pnpm exec playwright install --with-deps` in a real job completes in about a second - [ ] Boot-to-runner-ready latency measured before and after, and recorded on this issue
Logga in för att delta i denna konversation.
Ingen milstolpe
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra#349
Ingen beskrivning angiven.