mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
The arm64 render image had no pinned browser: chrome-for-testing publishes no linux-arm64 build, so Dockerfile.render fell back to Debian bookworm's rolling `chromium` package. Its current arm64 build (150.0.7871.46) SIGTRAPs at startup (exit 133), breaking `render --docker` 100% on Apple Silicon. Install a pinned, non-Debian chrome-headless-shell from Playwright on arm64 (Google's build, not Debian's repackage). The wrapper wires whichever binary landed into PRODUCER_HEADLESS_SHELL_PATH and now fails the build loudly if neither is present, instead of silently using the broken Debian chromium. Bonus: arm64 gains BeginFrame deterministic capture it previously lacked. amd64 path is unchanged. Verified on Apple Silicon: same arm64 image, Debian chromium 150 -> exit 133, Playwright arm64 headless-shell (Chromium 149) -> exit 0.
This commit is contained in:
@@ -1191,8 +1191,8 @@ function ensureDockerImage(version: string, platform: string, quiet: boolean): s
|
|||||||
|
|
||||||
// Platform is now derived from the host arch (see resolveDockerPlatform).
|
// Platform is now derived from the host arch (see resolveDockerPlatform).
|
||||||
// Apple Silicon and other arm64 hosts get a native linux/arm64 build; the
|
// Apple Silicon and other arm64 hosts get a native linux/arm64 build; the
|
||||||
// Dockerfile skips chrome-headless-shell on arm64 and falls back to system
|
// Dockerfile installs a pinned arm64 chrome-headless-shell from Playwright
|
||||||
// chromium because chrome-headless-shell ships linux64 only.
|
// (chrome-for-testing publishes no linux-arm64 build).
|
||||||
//
|
//
|
||||||
// TARGETARCH is passed explicitly rather than relying on BuildKit's
|
// TARGETARCH is passed explicitly rather than relying on BuildKit's
|
||||||
// automatic platform args because the legacy builder (and some BuildKit
|
// automatic platform args because the legacy builder (and some BuildKit
|
||||||
@@ -1250,17 +1250,17 @@ function resolveDockerHostPlatform(options: RenderOptions): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!options.quiet && platform === "linux/arm64") {
|
if (!options.quiet && platform === "linux/arm64") {
|
||||||
// chrome-headless-shell doesn't publish a linux-arm64 build, so the arm64
|
// The arm64 image uses Playwright's pinned linux-arm64 chrome-headless-shell
|
||||||
// image falls back to system chromium. That loses byte-for-byte parity
|
// (chrome-for-testing has no arm64 build). It's a different Chromium build
|
||||||
// with amd64 renders — fine for end-user output, not fine if you're
|
// than amd64's chrome-for-testing binary, so output isn't byte-identical to
|
||||||
// comparing against an amd64 golden baseline. Set
|
// an amd64 golden baseline — fine for end-user output. Set
|
||||||
// HYPERFRAMES_DOCKER_PLATFORM=linux/amd64 to keep parity (qemu-emulated,
|
// HYPERFRAMES_DOCKER_PLATFORM=linux/amd64 to force parity (qemu-emulated,
|
||||||
// slower).
|
// slower).
|
||||||
console.log(
|
console.log(
|
||||||
c.dim(
|
c.dim(
|
||||||
" Host is arm64 — using linux/arm64 image with system chromium " +
|
" Host is arm64 — using linux/arm64 image with Playwright's " +
|
||||||
"(output won't be byte-identical to amd64 renders; " +
|
"chrome-headless-shell (output won't be byte-identical to amd64 " +
|
||||||
"set HYPERFRAMES_DOCKER_PLATFORM=linux/amd64 to force parity).",
|
"renders; set HYPERFRAMES_DOCKER_PLATFORM=linux/amd64 to force parity).",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
FROM node:22-bookworm-slim
|
FROM node:22-bookworm-slim
|
||||||
|
|
||||||
ARG HYPERFRAMES_VERSION=latest
|
ARG HYPERFRAMES_VERSION=latest
|
||||||
# Set automatically by `docker build --platform` (BuildKit); we use it to
|
# Set automatically by `docker build --platform` (BuildKit); selects the
|
||||||
# decide whether to install chrome-headless-shell, which only ships for
|
# chrome-headless-shell source below (chrome-for-testing ships linux64 only,
|
||||||
# linux64 (see https://googlechromelabs.github.io/chrome-for-testing/).
|
# see https://googlechromelabs.github.io/chrome-for-testing/).
|
||||||
ARG TARGETARCH=amd64
|
ARG TARGETARCH=amd64
|
||||||
|
# Pinned Playwright release used to fetch a known-good, arch-native
|
||||||
|
# chrome-headless-shell on arm64. chrome-for-testing publishes no linux-arm64
|
||||||
|
# build, so arm64 used to fall back to Debian's *unpinned, rolling* `chromium`
|
||||||
|
# package — whose bookworm arm64 build SIGTRAPs at startup (exit 133), breaking
|
||||||
|
# every containerized render (issue #2039). Playwright ships a pinned
|
||||||
|
# linux-arm64 headless-shell (Google's build, not Debian's). Bump deliberately.
|
||||||
|
ARG PLAYWRIGHT_VERSION=1.61.1
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
ca-certificates curl unzip ffmpeg chromium \
|
ca-certificates curl unzip ffmpeg chromium \
|
||||||
@@ -20,37 +27,36 @@ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
|||||||
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||||
ENV CONTAINER=true
|
ENV CONTAINER=true
|
||||||
|
|
||||||
# chrome-headless-shell unlocks BeginFrame-based deterministic capture but the
|
# chrome-headless-shell unlocks BeginFrame-based deterministic capture. Install
|
||||||
# project only publishes a linux64 binary. On arm64 we skip the install and
|
# it on both arches from a pinned source so a build can never silently pick up a
|
||||||
# let the engine fall back to system chromium (set via
|
# broken browser update:
|
||||||
# PUPPETEER_EXECUTABLE_PATH above). The wrapper script below only sets
|
# amd64 -> chrome-for-testing (linux64) via @puppeteer/browsers
|
||||||
# PRODUCER_HEADLESS_SHELL_PATH when the binary is actually present.
|
# arm64 -> Playwright's pinned linux-arm64 headless-shell (chrome-for-testing
|
||||||
|
# has no arm64 build; Debian's rolling `chromium` SIGTRAPs — #2039)
|
||||||
|
# The wrapper script below wires whichever binary landed into
|
||||||
|
# PRODUCER_HEADLESS_SHELL_PATH, or fails the build loudly if neither did.
|
||||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||||
npx --yes @puppeteer/browsers install chrome-headless-shell@stable \
|
npx --yes @puppeteer/browsers install chrome-headless-shell@stable \
|
||||||
--path /root/.cache/puppeteer; \
|
--path /root/.cache/puppeteer; \
|
||||||
else \
|
else \
|
||||||
echo "Skipping chrome-headless-shell install on ${TARGETARCH} (linux64-only); using system chromium."; \
|
npx --yes playwright-core@${PLAYWRIGHT_VERSION} install chromium-headless-shell; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RUN npm install -g hyperframes@${HYPERFRAMES_VERSION}
|
RUN npm install -g hyperframes@${HYPERFRAMES_VERSION}
|
||||||
|
|
||||||
# Wrapper script: resolves chrome-headless-shell path at build time when
|
# Wrapper script: resolves the chrome-headless-shell path installed above and
|
||||||
# available so the engine uses BeginFrame rendering. On arm64 (no
|
# exports it as PRODUCER_HEADLESS_SHELL_PATH so the engine uses BeginFrame
|
||||||
# chrome-headless-shell) it leaves PRODUCER_HEADLESS_SHELL_PATH unset, so the
|
# rendering. @puppeteer/browsers names the binary `chrome-headless-shell`;
|
||||||
# engine falls back to PUPPETEER_EXECUTABLE_PATH (system chromium).
|
# Playwright names it `headless_shell` — match either, in either cache dir.
|
||||||
#
|
# If neither is present the browser install step failed: fail the build loudly
|
||||||
# If TARGETARCH=amd64 and the binary is missing, fail the build loudly — the
|
# rather than silently downgrading to the (arm64-broken) Debian chromium.
|
||||||
# previous (pre-PR) wrapper used an `&&` chain that crashed `docker build` in
|
RUN SHELL_PATH=$(find /root/.cache/puppeteer /root/.cache/ms-playwright \
|
||||||
# this case, and silently downgrading to system chromium on amd64 would mask
|
\( -name "chrome-headless-shell" -o -name "headless_shell" \) -type f 2>/dev/null | head -1); \
|
||||||
# golden-baseline regressions.
|
|
||||||
RUN SHELL_PATH=$(find /root/.cache/puppeteer/chrome-headless-shell -name "chrome-headless-shell" -type f 2>/dev/null | head -1); \
|
|
||||||
if [ -n "$SHELL_PATH" ]; then \
|
if [ -n "$SHELL_PATH" ]; then \
|
||||||
printf '#!/bin/sh\nexport PRODUCER_HEADLESS_SHELL_PATH=%s\nexec hyperframes render "$@"\n' "$SHELL_PATH" > /usr/local/bin/hf-render; \
|
printf '#!/bin/sh\nexport PRODUCER_HEADLESS_SHELL_PATH=%s\nexec hyperframes render "$@"\n' "$SHELL_PATH" > /usr/local/bin/hf-render; \
|
||||||
elif [ "$TARGETARCH" = "amd64" ]; then \
|
|
||||||
echo "ERROR: chrome-headless-shell binary not found on amd64 — @puppeteer/browsers install must have failed or moved its cache layout." >&2; \
|
|
||||||
exit 1; \
|
|
||||||
else \
|
else \
|
||||||
printf '#!/bin/sh\nexec hyperframes render "$@"\n' > /usr/local/bin/hf-render; \
|
echo "ERROR: chrome-headless-shell binary not found for ${TARGETARCH} — the browser install step above must have failed." >&2; \
|
||||||
|
exit 1; \
|
||||||
fi \
|
fi \
|
||||||
&& chmod +x /usr/local/bin/hf-render
|
&& chmod +x /usr/local/bin/hf-render
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ export interface DockerRunArgsInput {
|
|||||||
* resolves to the host architecture via `resolveDockerPlatform()`. Pinning
|
* resolves to the host architecture via `resolveDockerPlatform()`. Pinning
|
||||||
* to `linux/amd64` on an arm64 host (the legacy default) forces qemu
|
* to `linux/amd64` on an arm64 host (the legacy default) forces qemu
|
||||||
* emulation of chrome-headless-shell, which segfaults or stalls on Apple
|
* emulation of chrome-headless-shell, which segfaults or stalls on Apple
|
||||||
* Silicon — see issue #1193. Native `linux/arm64` falls back to the
|
* Silicon — see issue #1193. Native `linux/arm64` uses Playwright's pinned
|
||||||
* system chromium baked into the image at the cost of byte-for-byte
|
* arm64 chrome-headless-shell baked into the image at the cost of
|
||||||
* parity with amd64 renders.
|
* byte-for-byte parity with amd64 renders.
|
||||||
*/
|
*/
|
||||||
platform?: string;
|
platform?: string;
|
||||||
options: DockerRenderOptions;
|
options: DockerRenderOptions;
|
||||||
|
|||||||
Reference in New Issue
Block a user