Slim the image, publish on version tags, drop deployment specifics
The first publish failed partway through the push with 413 Payload Too Large: one layer was bigger than the proxy in front of the registry would accept. Three changes, only one of which is that fix. Keep deployment out of a public repo. The registry, image name and credentials now come from repository variables and secrets rather than being written down here, and the docs describe how to run the thing rather than where one particular instance runs. PUBLIC_ORIGIN defaults to localhost. The 413 is a proxy limit, so the fix is pointing REGISTRY at a host the runner reaches directly; the workflow explains itself if that host is plain HTTP and the builder's daemon has not been told to allow it. Publish on version tags. A tag like 1.2.3 publishes :1.2.3, :1.2, :1 and :latest; a prerelease publishes only its exact version and leaves :latest alone. Pushes to main publish :main and :sha-<short> and no longer move :latest, so what is deployed moves when a release says so. Shrink the image from over 1.2GB to 353MB. The Playwright base image carries Firefox and WebKit, which this never launches. Installing just the browser it does launch onto a slim Node base drops two thirds of the weight, which is worth having on a Raspberry Pi even though it does not get any single layer under a proxy limit. That last change surfaced something worth naming: a headless launch resolves to Playwright's headless shell, not the full browser, so that is what every test so far has actually been running. The image now installs exactly that binary and pool.ts names the channel, so the two cannot drift apart. Verified in the container: Bluesky, Instagram, X and Threads all resolve identically on the slim image. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BGkRmLfiWuJHx6tQ12EELY
This commit is contained in:
+31
-18
@@ -1,20 +1,18 @@
|
||||
# antisocial — reads social posts back to you without the app.
|
||||
# antisocial
|
||||
#
|
||||
# Both stages sit on the Playwright image so the Node that compiles the code
|
||||
# is the Node that runs it, and so the Chromium build matches the Playwright
|
||||
# package exactly. The image is large because a browser is large; the
|
||||
# alternative, apt Chromium on a slim Node base, saves a few hundred MB and
|
||||
# is where arm64 browser builds usually go wrong.
|
||||
# Only headless Chromium is ever launched, so the image installs just that
|
||||
# browser onto a slim Node base rather than using the Playwright image, which
|
||||
# also carries Firefox and WebKit — roughly two thirds of its size, for
|
||||
# browsers this never opens.
|
||||
#
|
||||
# Pinned in lockstep with the `playwright` dependency in package.json.
|
||||
ARG PLAYWRIGHT_VERSION=1.62.1
|
||||
# Built natively; the tag carries the architecture of the machine that built
|
||||
# it. Multi-arch would need buildx and a manifest list.
|
||||
|
||||
FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble AS build
|
||||
FROM node:22-bookworm-slim AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Browsers are already in the base image; downloading them again during
|
||||
# `npm ci` would double the build for nothing.
|
||||
# The browser is installed in the runtime stage, not here.
|
||||
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
@@ -25,26 +23,41 @@ COPY src ./src
|
||||
RUN npm run build && npm prune --omit=dev
|
||||
|
||||
|
||||
FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble AS runtime
|
||||
FROM node:22-bookworm-slim AS runtime
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
|
||||
HOST=0.0.0.0 \
|
||||
PORT=8080 \
|
||||
PROFILE_DIR=/data/profile
|
||||
PROFILE_DIR=/data/profile \
|
||||
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
|
||||
|
||||
# `chromium-headless-shell` and not `chromium`: a headless launch resolves to
|
||||
# the shell either way, so installing the full browser alongside it would ship
|
||||
# a binary nothing ever executes. `src/browser/pool.ts` names the same channel
|
||||
# so the two cannot drift apart.
|
||||
#
|
||||
# Fonts matter more than they look: without them any rendered text — including
|
||||
# a verification puzzle we have to show a person — comes out as empty boxes.
|
||||
RUN npx --yes [email protected] install --with-deps chromium-headless-shell \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends fonts-liberation fonts-noto-color-emoji \
|
||||
&& rm -rf /var/lib/apt/lists/* /root/.npm
|
||||
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/dist ./dist
|
||||
COPY package.json ./
|
||||
COPY public ./public
|
||||
|
||||
# The profile directory is normally a mounted volume; create it anyway so
|
||||
# the image runs standalone.
|
||||
RUN mkdir -p /data/profile && chown -R pwuser:pwuser /data /app
|
||||
# Chromium will not start as root without its sandbox disabled outright, and
|
||||
# there is no reason to run as root anyway.
|
||||
RUN useradd --create-home --uid 10001 antisocial \
|
||||
&& mkdir -p /data/profile \
|
||||
&& chown -R antisocial:antisocial /data /app \
|
||||
&& chmod -R a+rx /ms-playwright
|
||||
|
||||
USER pwuser
|
||||
USER antisocial
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
|
||||
Reference in New Issue
Block a user