Commit 840b7f7
build(docker): Switch to Docker Hardened Images (DHI) (#212)
* build: Switch to Docker Hardened Images (DHI)
Replace node:24.14.0 and node:24.14.0-slim base images with Sentry's
DHI equivalents (us-docker.pkg.dev/sentryio/dhi/node:24-debian13-dev
and node:24-debian13).
Move canvas native compilation (yarn install + build deps) entirely into
the builder stage so the runtime image no longer needs build-essential
or -dev headers. The runtime stage only installs the minimal shared
libraries that canvas needs at runtime (libcairo2, libpango-1.0-0,
libjpeg62-turbo, libgif7, librsvg2-2), eliminating ~1,400 Trivy findings
that were rooted in the Debian system package footprint.
Co-Authored-By: Claude <noreply@anthropic.com>
* build: Fix platform selection for DHI images
The DHI manifest entries for amd64 have an unexpected variant field
("v8"), which is normally an ARM designator. Docker BuildKit fails to
match linux/amd64 against these entries.
Add --platform=linux/amd64 to both FROM lines so BuildKit selects by
architecture directly rather than relying on variant matching.
Co-Authored-By: Claude <noreply@anthropic.com>
* build: Fix DHI platform specifier to linux/amd64/v8
The DHI manifest non-standardly labels the amd64 image with variant
"v8" (an ARM designator), making its platform string linux/amd64/v8
rather than the expected linux/amd64. Cloud Build's BuildKit fails to
match linux/amd64 against linux/amd64/v8.
Specify the exact platform string from the manifest so BuildKit resolves
the correct image layer.
Co-Authored-By: Claude <noreply@anthropic.com>
* build: Use standard node image for builder, DHI for runtime
The DHI dev image has libexpat1=2.7.4 (arch:all) pre-installed as a
security patch, which conflicts with the entire canvas build dep chain
(libcairo2-dev → libfontconfig-dev → libexpat1-dev requires libexpat1
= 2.7.1-2 arch-specific). Both APT solver 3.0 and the classic solver
fail to resolve this.
Use standard node:24.14.0 for the builder stage (compiles canvas native
module and TypeScript without package conflicts). The runtime stage uses
DHI node:24-debian13-dev since the fully minimal node:24-debian13 image
has no shell or package manager — canvas needs runtime shared libraries
(libcairo2, libpango-1.0-0, libjpeg62-turbo, libgif7, librsvg2-2) which
apt-get install correctly on Debian 13 in the -dev image.
The --platform=linux/amd64/v8 flag is scoped to only the DHI FROM line
because the DHI manifest incorrectly labels the amd64 entry with variant
"v8" (an ARM designator). Standard node:24.14.0 uses linux/amd64 without
a variant, so the platform flag must not apply to that stage.
Compiled node_modules (including canvas.node native binary) is copied
from the builder so the runtime stage never needs build tools.
Co-Authored-By: Claude <noreply@anthropic.com>
* build: Remove unnecessary canvas runtime library installs
canvas 3.x bundles its own copies of libcairo, libpango, libjpeg,
libgif, librsvg, harfbuzz, glib, etc. inside
node_modules/canvas/build/Release/. No system-level canvas libraries
need to be installed in the runtime image.
The -dev variant is still required over the minimal node:24-debian13
image because canvas's bundled dependencies (librsvg, glib) need base
system libs (libz, libexpat, libuuid, liblzma) that are present in the
dev image but absent from the stripped-down minimal image.
Co-Authored-By: Claude <noreply@anthropic.com>
* build(docker): Switch builder stage to DHI image
canvas 3.x downloads pre-built binaries via node-pre-gyp, so the
build stage no longer needs system canvas libraries (libcairo2-dev,
libpango1.0-dev, etc.). This removes the conflict with DHI's
pre-installed libexpat1 2.7.4 package that previously blocked using
the hardened image in the builder stage.
Also removes the --platform=linux/amd64/v8 workaround now that the
DHI image manifests have correct platform variant labels.
Co-Authored-By: Claude <noreply@anthropic.com>
* build(docker): Use minimal DHI runtime image with targeted lib copy
Switch the runtime stage from node:24-debian13-dev to node:24-debian13
(the minimal/distroless image) to reduce the attack surface.
canvas 3.x bundles its graphics libs (libcairo, libpango, etc.) so no
system canvas libraries are needed. However, canvas's bundled librsvg
and glib still require four basic system libs absent from the minimal
image (libz, libexpat, libuuid, liblzma). These are collected in the
builder stage and copied into the runtime, rather than pulling in the
full -dev image.
The smoke-test RUN uses exec form since the minimal image has no shell.
Co-Authored-By: Claude <noreply@anthropic.com>
* build(docker): Exclude devDependencies from production image
Add a separate deps stage that runs yarn install --production so that
jest, typescript, eslint, ts-jest, supertest, and their transitive
deps are not copied into the runtime image. The builder stage keeps
the full install for TypeScript compilation.
node_modules layer in the runtime image shrinks from ~94 MB to ~46 MB.
Co-Authored-By: Claude <noreply@anthropic.com>
* build(docker): Reduce build stages from 3 to 2
Merge the separate deps and builder stages into a single builder stage.
Install all dependencies, compile TypeScript, then prune to
production-only deps in place before copying into the runtime image.
Runtime image contents remain identical.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 3ad3fda commit 840b7f7
1 file changed
Lines changed: 25 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
4 | 6 | | |
5 | 7 | | |
6 | 8 | | |
7 | 9 | | |
8 | 10 | | |
9 | 11 | | |
10 | | - | |
| 12 | + | |
| 13 | + | |
11 | 14 | | |
12 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
13 | 26 | | |
14 | | - | |
15 | | - | |
16 | 27 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
| 28 | + | |
25 | 29 | | |
26 | | - | |
| 30 | + | |
27 | 31 | | |
28 | | - | |
29 | | - | |
30 | | - | |
| 32 | + | |
31 | 33 | | |
| 34 | + | |
32 | 35 | | |
33 | | - | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
34 | 39 | | |
35 | | - | |
| 40 | + | |
36 | 41 | | |
37 | 42 | | |
38 | 43 | | |
0 commit comments