diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index d5d625f9..031a21d6 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -9,12 +9,16 @@ # # Once the commands have been run, you can build the image using `yarn build-image` -# ---- Builder ---- -FROM node:22-bookworm-slim AS build +# From mise.toml +FROM node:22-bookworm-slim +# Set Python interpreter for `node-gyp` to use ENV PYTHON=/usr/bin/python3 -ENV NODE_ENV=production -ENV NODE_OPTIONS="--no-node-snapshot" + +RUN groupmod -g 150 node && usermod -u 150 -g 150 node +RUN corepack enable +# Set the owner of the cache directory to node so we can use corepack +RUN mkdir -p /home/node/.cache && chown -R node:node /home/node/.cache # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. # 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 \ apt-get install -y --no-install-recommends python3 g++ build-essential libsqlite3-dev && \ rm -rf /var/lib/apt/lists/* -# Use the least-privileged user even during build -RUN groupmod -g 150 node && usermod -u 150 -g 150 node -RUN corepack enable -RUN mkdir -p /home/node/.cache && chown -R node:node /home/node/.cache + +# From here on we use the least-privileged `node` user to run the backend. USER node + +# This should create the app dir as `node`. +# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`. +# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`. WORKDIR /app # Copy files needed by Yarn COPY --chown=node:node .yarn ./.yarn -COPY --chown=node:node .yarnrc.yml . -COPY --chown=node:node backstage.json . +COPY --chown=node:node .yarnrc.yml ./ +COPY --chown=node:node backstage.json ./ + +# This switches many Node.js dependencies to production mode. +ENV NODE_ENV=production + +# This disables node snapshot for Node 20 to work with the Scaffolder +# Not sure if needed for Node 22. +ENV NODE_OPTIONS="--no-node-snapshot" + +# Copy repo skeleton first, to avoid unnecessary docker cache invalidation. +# The skeleton contains the package.json of each package in the monorepo, +# and along with yarn.lock and the root package.json, that's enough to run yarn install. COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz @@ -45,13 +62,7 @@ RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ RUN tar xzf bundle.tar.gz && rm bundle.tar.gz -# ---- Runtime ---- -FROM gcr.io/distroless/nodejs22-debian12 - -WORKDIR /app -COPY --from=build --chown=nonroot:nonroot /app /app - -ENV NODE_ENV=production -ENV NODE_OPTIONS="--no-node-snapshot" +RUN mv packages packages_tmp +RUN mkdir packages -CMD ["packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml", "--config", "app-config.runtime.yaml"] \ No newline at end of file +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"]