The combined pip install layer was already over Cloudflare's single-blob/layer payload-size limit (~113MB unpacked) before any recent change -- the last two build-and-push CI runs were failing on it. Isolate the three largest packages (sqlalchemy, pillow, pypdfium2) into their own layers, same fix already applied to render-service's npm installs below for the same limit.
84 lines
4.4 KiB
Docker
84 lines
4.4 KiB
Docker
FROM python:3.12-slim
|
|
|
|
WORKDIR /app
|
|
|
|
# tzdata/fonts/Node.js all from Debian's own repo in one layer -- no
|
|
# external curl/gnupg dance needed (see below for why that changed).
|
|
# tzdata: python:3.12-slim doesn't include it by default, so the
|
|
# zoneinfo database backing the web UI's "Timezone" setting (used by
|
|
# "Quiet hours") would have no named zones to resolve without this --
|
|
# ZoneInfo() would raise for anything other than "UTC".
|
|
# fontconfig/fonts-dejavu-core: whiteboard mode's render-service/ (own
|
|
# README there) needs something to render whiteboard text with.
|
|
#
|
|
# Node.js: whiteboard frame mode's render-service/ runs as a second
|
|
# process in this same container rather than a separate compose service
|
|
# -- it's a lightweight, stateless, localhost-only sidecar with nothing
|
|
# worth independently scaling or restarting. Used to be installed via
|
|
# NodeSource's setup script (Debian's own nodejs package was too old for
|
|
# jsdom's minimum back when this base image tracked Debian bookworm) --
|
|
# switched to Debian's own `nodejs`/`npm` packages after NodeSource's
|
|
# deb.nodesource.com started intermittently 403ing on both its setup_*.x
|
|
# scripts *and* its GPG key (a live NodeSource-side S3/CDN issue,
|
|
# confirmed 2026-07-27 by hitting deb.nodesource.com directly -- some
|
|
# setup_NN.x paths 403, others 200, no consistent pattern, so no
|
|
# NodeSource-hosted install path could be trusted not to silently break
|
|
# again). This base image now tracks Debian trixie, whose own `nodejs`
|
|
# package is 20.19.2 -- inside jsdom 29's stated engines range
|
|
# (`^20.19.0 || ^22.13.0 || >=24.0.0`) and well above express/resvg-js's
|
|
# much lower floors -- so there's no longer a version gap to route
|
|
# around NodeSource for. One less external dependency, and no more
|
|
# curl-piped-into-bash (that pattern is also what let the NodeSource
|
|
# failure go undetected here in the first place: `curl -f ... | bash -`
|
|
# on a 403 hands bash an empty, "successful" script instead of failing
|
|
# the RUN outright).
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
tzdata fontconfig fonts-dejavu-core nodejs npm \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
COPY requirements.txt .
|
|
# Split across several layers rather than one `pip install -r
|
|
# requirements.txt` -- same Cloudflare single-blob/layer payload-size
|
|
# limit as render-service's npm installs below. The single combined
|
|
# layer was measured at ~113MB unpacked, over the limit on its own.
|
|
# Isolating the three largest packages gets every layer's unpacked size
|
|
# well clear of 100MB (sqlalchemy ~15MB, pillow ~19MB, pypdfium2 ~8MB,
|
|
# the remaining `-r requirements.txt` layer ~71MB). Each package
|
|
# version here still comes from requirements.txt (`pip install -r` for
|
|
# everything that doesn't need its own layer skips these three, since
|
|
# pip sees them already satisfied); the explicit versions below just
|
|
# control *when* each installs -- same "single source of truth, just
|
|
# splitting *when* it installs" tradeoff as the npm section's --no-save
|
|
# comment below.
|
|
RUN pip install --no-cache-dir sqlalchemy==2.0.51
|
|
RUN pip install --no-cache-dir pillow==12.3.0
|
|
RUN pip install --no-cache-dir pypdfium2==5.12.1
|
|
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
# render-service/'s dependencies installed as several separate layers
|
|
# rather than one `npm install` covering all of them -- a from-scratch
|
|
# push of this image once hit Cloudflare's payload-size limit on a
|
|
# single blob/layer upload (the registry sits behind it), and splitting
|
|
# a big layer into several smaller ones is the direct fix for exactly
|
|
# that failure mode, independent of anything about the registry itself.
|
|
# --no-save: package.json already fully declares these (with the exact
|
|
# same version pins used here) as the single source of truth for what
|
|
# this service depends on -- these calls are just about *when* each one
|
|
# gets installed for layer-size reasons, not re-deciding what's needed.
|
|
COPY render-service/package.json ./render-service/package.json
|
|
WORKDIR /app/render-service
|
|
RUN npm install --omit=dev --no-save express@^5.2.1 && npm cache clean --force
|
|
RUN npm install --omit=dev --no-save jsdom@^29.1.1 && npm cache clean --force
|
|
RUN npm install --omit=dev --no-save @excalidraw/[email protected] && npm cache clean --force
|
|
RUN npm install --omit=dev --no-save @resvg/[email protected] && npm cache clean --force
|
|
WORKDIR /app
|
|
|
|
COPY render-service/server.js ./render-service/server.js
|
|
COPY app ./app
|
|
COPY start.sh .
|
|
RUN chmod +x start.sh
|
|
|
|
EXPOSE 8420
|
|
|
|
CMD ["./start.sh"]
|