|
| 1 | +# HyperFrames distributed renderer — reference Dockerfile for non-Lambda runtimes. |
| 2 | +# |
| 3 | +# This image bakes Node 22, chrome-headless-shell, ffmpeg-static, and the |
| 4 | +# `@hyperframes/producer/distributed` primitives. One image runs the |
| 5 | +# Plan / RenderChunk / Assemble activities for any non-Lambda orchestrator: |
| 6 | +# |
| 7 | +# - Kubernetes Jobs (one Job per chunk, Argo Workflows on top) |
| 8 | +# - AWS ECS Fargate (one task per chunk) |
| 9 | +# - Google Cloud Run Jobs |
| 10 | +# - Azure Container Apps Jobs |
| 11 | +# - Plain `docker run` on a beefy VM |
| 12 | +# |
| 13 | +# We deliberately do NOT publish this image to a registry. The OSS contract |
| 14 | +# is that adopters build it themselves — that way the Chrome / ffmpeg / |
| 15 | +# producer versions are pinned to the source checkout they audited, not a |
| 16 | +# floating tag we'd have to keep in sync with every release. |
| 17 | +# |
| 18 | +# Build from the repo root: |
| 19 | +# |
| 20 | +# docker build -t hyperframes-chunk-runner:local -f examples/k8s-jobs/Dockerfile.example . |
| 21 | +# |
| 22 | +# Run a chunk worker (an orchestrator script wraps this entry point): |
| 23 | +# |
| 24 | +# docker run --rm \ |
| 25 | +# -e PRODUCER_HEADLESS_SHELL_PATH=/opt/chrome/chrome-headless-shell \ |
| 26 | +# -v /tmp/hyperframes:/tmp/hyperframes \ |
| 27 | +# hyperframes-chunk-runner:local \ |
| 28 | +# node -e 'import("@hyperframes/producer/distributed").then(({renderChunk})=>renderChunk(...))' |
| 29 | +# |
| 30 | +# Lambda adopters use `packages/aws-lambda/dist/handler.zip` instead; |
| 31 | +# this Dockerfile is the K8s / Cloud Run / ECS path. |
| 32 | + |
| 33 | +# ── Base ───────────────────────────────────────────────────────────────────── |
| 34 | +# Debian bookworm-slim because the chrome-headless-shell dynamic-library set |
| 35 | +# matches what we use in CI. Amazon Linux 2023 also works (Lambda's base |
| 36 | +# image) but is harder to debug locally. |
| 37 | +FROM node:22-bookworm-slim AS base |
| 38 | + |
| 39 | +# ── System deps ────────────────────────────────────────────────────────────── |
| 40 | +# - ffmpeg: the producer's encode + audio mix |
| 41 | +# - libfontconfig / libfreetype / fonts-liberation: Chrome text shaping |
| 42 | +# - chromium-style ABI deps (the minimum set chrome-headless-shell needs): |
| 43 | +# libnss3, libatk-bridge2.0, libdrm2, libgbm1, libxshmfence1, libxkbcommon0, |
| 44 | +# libxcomposite1, libxdamage1, libxfixes3, libxrandr2, libasound2, |
| 45 | +# libpangocairo-1.0-0 |
| 46 | +# - tini: clean PID 1 for container teardown signals (Cloud Run / Fargate |
| 47 | +# send SIGTERM at the 10-min grace boundary). |
| 48 | +RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 49 | + ffmpeg \ |
| 50 | + ca-certificates \ |
| 51 | + fonts-liberation \ |
| 52 | + libasound2 \ |
| 53 | + libatk-bridge2.0-0 \ |
| 54 | + libatk1.0-0 \ |
| 55 | + libc6 \ |
| 56 | + libcairo2 \ |
| 57 | + libcups2 \ |
| 58 | + libdbus-1-3 \ |
| 59 | + libdrm2 \ |
| 60 | + libfontconfig1 \ |
| 61 | + libfreetype6 \ |
| 62 | + libgbm1 \ |
| 63 | + libglib2.0-0 \ |
| 64 | + libnspr4 \ |
| 65 | + libnss3 \ |
| 66 | + libpango-1.0-0 \ |
| 67 | + libpangocairo-1.0-0 \ |
| 68 | + libxcomposite1 \ |
| 69 | + libxdamage1 \ |
| 70 | + libxfixes3 \ |
| 71 | + libxkbcommon0 \ |
| 72 | + libxrandr2 \ |
| 73 | + libxshmfence1 \ |
| 74 | + tini \ |
| 75 | + tzdata \ |
| 76 | + wget \ |
| 77 | + xz-utils \ |
| 78 | + && rm -rf /var/lib/apt/lists/* |
| 79 | + |
| 80 | +# ── Chrome ─────────────────────────────────────────────────────────────────── |
| 81 | +# Use `@puppeteer/browsers` to fetch the same chrome-headless-shell version |
| 82 | +# the producer pins. Keep the bun + chrome install in the build context so |
| 83 | +# the runtime image is reproducible. |
| 84 | +ENV CHROME_HEADLESS_SHELL_VERSION=131.0.6778.139 |
| 85 | +ENV CHROME_DIR=/opt/chrome |
| 86 | + |
| 87 | +RUN mkdir -p "$CHROME_DIR" && \ |
| 88 | + npm install --global @puppeteer/browsers@2.13.0 && \ |
| 89 | + npx @puppeteer/browsers install "chrome-headless-shell@${CHROME_HEADLESS_SHELL_VERSION}" \ |
| 90 | + --path "$CHROME_DIR" && \ |
| 91 | + npm uninstall --global @puppeteer/browsers && \ |
| 92 | + rm -rf /root/.npm |
| 93 | + |
| 94 | +ENV PRODUCER_HEADLESS_SHELL_PATH=${CHROME_DIR}/chrome-headless-shell/linux-${CHROME_HEADLESS_SHELL_VERSION}/chrome-headless-shell-linux64/chrome-headless-shell |
| 95 | + |
| 96 | +# ── HyperFrames ────────────────────────────────────────────────────────────── |
| 97 | +# Copy the workspace bun-locked package set. We use bun in the build |
| 98 | +# (matches the rest of the repo) but the runtime is plain Node — no bun |
| 99 | +# is needed at run time. |
| 100 | +WORKDIR /app |
| 101 | +COPY package.json bun.lock ./ |
| 102 | +COPY packages/aws-lambda/package.json packages/aws-lambda/ |
| 103 | +COPY packages/core/package.json packages/core/ |
| 104 | +COPY packages/engine/package.json packages/engine/ |
| 105 | +COPY packages/producer/package.json packages/producer/ |
| 106 | + |
| 107 | +RUN npm install --global bun && \ |
| 108 | + bun install --frozen-lockfile && \ |
| 109 | + npm uninstall --global bun |
| 110 | + |
| 111 | +# Bring in the source. We're not building the producer's dist/ here — bun's |
| 112 | +# workspace + tsx + esm resolution can run the producer straight from |
| 113 | +# `packages/producer/src/**`. Adopters who want a built distribution can |
| 114 | +# `bun run --cwd packages/producer build` against this image. |
| 115 | +COPY packages/core ./packages/core |
| 116 | +COPY packages/engine ./packages/engine |
| 117 | +COPY packages/producer ./packages/producer |
| 118 | + |
| 119 | +# ── Runtime ────────────────────────────────────────────────────────────────── |
| 120 | +ENTRYPOINT ["/usr/bin/tini", "--"] |
| 121 | +# Default CMD prints the producer version + Chrome path; orchestrators |
| 122 | +# typically override CMD with their per-chunk activity invocation. |
| 123 | +CMD ["node", "-e", "console.log(JSON.stringify({producerVersion: require('./packages/producer/package.json').version, chromePath: process.env.PRODUCER_HEADLESS_SHELL_PATH}))"] |
0 commit comments