From 0e0ce4156946199e0f9c57f9fcb0783b5ac55f84 Mon Sep 17 00:00:00 2001 From: Todd Schiller Date: Thu, 9 Jul 2026 14:20:42 -0400 Subject: [PATCH] Slim image: drop unused firefox/webkit/chrome to cut CI pull time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CI E2E job's "Initialize containers" step spends ~10 min pulling this image (pixiebrix-source#9209) — the whole overrun, and far longer than the tests themselves. The batteries-included mcr.microsoft.com/playwright base bakes firefox + webkit into its layers, so they're pulled on every shard even though neither E2E suite uses them: - webext-e2e launches the `chromium` and `msedge` channels - web-app-e2e uses bundled `chromium` - the `chrome` channel is disabled (pixiebrix-source#2797) Build on the official Node base (pinned to the monorepo's Node) and install only chromium + msedge + msedge-beta with --with-deps. Set PLAYWRIGHT_BROWSERS_PATH=/ms-playwright and recreate uid-1001 pwuser to match the official image layout so the browsers resolve at runtime (no re-download) and `--user 1001` keeps working. Update release.yml to derive the image tag from the @playwright/test pin instead of the (now removed) mcr FROM line. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 10 +++++++-- Dockerfile | 39 ++++++++++++++++++++++++++++------- README.md | 13 ++++++++++-- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5eb3d74..1876a7c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,11 +39,17 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # ADDED: Match base container version + # ADDED: Tag the image with the pinned Playwright version so it matches the + # monorepo's @playwright/test. Derived from the `install` line since the base + # image is now plain Node (no mcr.microsoft.com/playwright FROM to grep). - name: Extract Playwright version id: dockerfile run: | - VERSION=$(grep -oP 'mcr\.microsoft\.com/playwright:v\K[0-9]+\.[0-9]+\.[0-9]+' Dockerfile) + VERSION=$(grep -oP '@playwright/test@\K[0-9]+\.[0-9]+\.[0-9]+' Dockerfile) + if [ -z "$VERSION" ]; then + echo "Could not extract Playwright version from Dockerfile" >&2 + exit 1 + fi echo "version=$VERSION" >> $GITHUB_OUTPUT # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. diff --git a/Dockerfile b/Dockerfile index 04970f5..5a20458 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,37 @@ -# Keep the image up to date with https://playwright.dev/docs/docker#pull-the-image -# Once updated here, also use the correct tag in the monorepo's workflow -FROM mcr.microsoft.com/playwright:v1.57.0-noble +# PixieBrix container image for GitHub Actions E2E (webext-e2e + web-app-e2e). +# +# Slimmed to only the browsers our suites actually launch: +# - webext-e2e: the `chromium` and `msedge` channels +# - web-app-e2e: bundled `chromium` +# The `chrome` channel is disabled (pixiebrix-source#2797) and firefox/webkit are +# unused by both suites. We therefore build on a plain Node base and install just +# those browsers, instead of the batteries-included mcr.microsoft.com/playwright +# image, which bakes firefox + webkit into its base layers and roughly doubles the +# image pull time on CI (see pixiebrix-source#9209). +# +# Node is pinned to the monorepo's version (package.json engines / .nvmrc). Node's +# official images are Debian-based (there is no Ubuntu `-noble` variant); Playwright +# supports Debian 12 (bookworm). +FROM node:24.18.0-bookworm -# List all the browsers including those that are included by default -RUN npx @playwright/test@1.57.0 install --with-deps chrome chromium msedge msedge-beta +# Match the official Playwright image layout so Playwright resolves the browsers at +# runtime without re-downloading them. The monorepo workflow runs the container as +# `--user 1001`, so the installed browsers must be readable/executable by that uid. +ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright -# Keep 3 commands in one RUN to save space in the image. rm -rf also cleans up the cache -# Re-set root around apt-get -USER root +# Keep the Playwright version in sync with the monorepo's @playwright/test pin. +# The release workflow derives the published image tag from this version string. +RUN npx --yes @playwright/test@1.57.0 install --with-deps chromium msedge msedge-beta && \ + chmod -R a+rX /ms-playwright && \ + rm -rf /var/lib/apt/lists/* + +# Extra native deps used elsewhere in CI (xmlsec, etc.). RUN apt-get update && \ apt-get install -y libxmlsec1 libxmlsec1-dev libxml2 pkg-config lsb-release python3-pip && \ rm -rf /var/lib/apt/lists/* + +# The monorepo runs this container as `--user 1001`; create that user (mirrors the +# official image's `pwuser`) so $HOME and npm caches resolve to a writable path. +RUN groupadd --gid 1001 pwuser && \ + useradd --uid 1001 --gid 1001 --create-home --shell /bin/bash pwuser USER 1001 diff --git a/README.md b/README.md index cbd6268..fed26d7 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,21 @@ jobs: options: --user 1001 ``` +## Browsers + +The image installs only the browsers the monorepo's E2E suites launch: bundled +`chromium` plus the `msedge`/`msedge-beta` channels. Firefox and WebKit are +deliberately omitted (unused), and the `chrome` channel is disabled in the +monorepo (pixiebrix-source#2797). It is built on the official Node image rather +than `mcr.microsoft.com/playwright` to avoid pulling the firefox/webkit layers on +every CI job (see pixiebrix-source#9209). + ## Updates The browsers are automatically updated every 3 days. Playwright must be updated manually because the version must match: -1. This repo: Update the version anywhere it appears in the Dockerfile - - a new tag will be created, the old one will continue working but it won't receive browser updates +1. This repo: Update the `@playwright/test@` pin in the Dockerfile + - the published image tag is derived from that version; a new tag will be created, and the old one keeps working but won't receive browser updates 3. Monorepo: Update the version both in package.json and in the workflow ## Documentation