99#
1010# Once the commands have been run, you can build the image using `yarn build-image`
1111
12- # ---- Builder ----
13- FROM node:22-bookworm-slim AS build
12+ # From mise.toml
13+ FROM node:22-bookworm-slim
1414
15+ # Set Python interpreter for `node-gyp` to use
1516ENV PYTHON=/usr/bin/python3
16- ENV NODE_ENV=production
17- ENV NODE_OPTIONS="--no-node-snapshot"
17+
18+ RUN groupmod -g 150 node && usermod -u 150 -g 150 node
19+ RUN corepack enable
20+ # Set the owner of the cache directory to node so we can use corepack
21+ RUN mkdir -p /home/node/.cache && chown -R node:node /home/node/.cache
1822
1923# Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend.
2024# If sqlite3 is not needed anymore, remove libsqlite3-dev and better-sqlite3.
@@ -24,17 +28,30 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
2428 apt-get install -y --no-install-recommends python3 g++ build-essential libsqlite3-dev && \
2529 rm -rf /var/lib/apt/lists/*
2630
27- # Use the least-privileged user even during build
28- RUN groupmod -g 150 node && usermod -u 150 -g 150 node
29- RUN corepack enable
30- RUN mkdir -p /home/node/.cache && chown -R node:node /home/node/.cache
31+
32+ # From here on we use the least-privileged `node` user to run the backend.
3133USER node
34+
35+ # This should create the app dir as `node`.
36+ # If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`.
37+ # If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`.
3238WORKDIR /app
3339
3440# Copy files needed by Yarn
3541COPY --chown=node:node .yarn ./.yarn
36- COPY --chown=node:node .yarnrc.yml .
37- COPY --chown=node:node backstage.json .
42+ COPY --chown=node:node .yarnrc.yml ./
43+ COPY --chown=node:node backstage.json ./
44+
45+ # This switches many Node.js dependencies to production mode.
46+ ENV NODE_ENV=production
47+
48+ # This disables node snapshot for Node 20 to work with the Scaffolder
49+ # Not sure if needed for Node 22.
50+ ENV NODE_OPTIONS="--no-node-snapshot"
51+
52+ # Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
53+ # The skeleton contains the package.json of each package in the monorepo,
54+ # and along with yarn.lock and the root package.json, that's enough to run yarn install.
3855COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
3956RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
4057
@@ -45,13 +62,7 @@ RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid
4562COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
4663RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
4764
48- # ---- Runtime ----
49- FROM gcr.io/distroless/nodejs22-debian12
50-
51- WORKDIR /app
52- COPY --from=build --chown=nonroot:nonroot /app /app
53-
54- ENV NODE_ENV=production
55- ENV NODE_OPTIONS="--no-node-snapshot"
65+ RUN mv packages packages_tmp
66+ RUN mkdir packages
5667
57- CMD ["packages/backend " , "--config " , "app-config.yaml" , " --config" , " app-config.production.yaml" , " --config" , " app-config.runtime.yaml" ]
68+ CMD ["sh " , "-c " , "cp -r packages_tmp/* packages/ && node packages/backend --config app-config.yaml --config app-config.production.yaml --config app-config.runtime.yaml" ]
0 commit comments