1+ # Stage 1 - Create yarn install skeleton layer
2+ FROM node:20-bookworm-slim AS packages
3+
4+ WORKDIR /app
5+ COPY backstage.json package.json yarn.lock ./
6+ COPY .yarn ./.yarn
7+ COPY .yarnrc.yml ./
8+
9+ COPY packages packages
10+
11+ # Comment this out if you don't have any internal plugins
12+ COPY plugins plugins
13+
14+ RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -exec rm -rf {} \+
15+
16+ # Stage 2 - Install dependencies and build packages
17+ FROM node:20-bookworm-slim AS build
18+
19+ # Set Python interpreter for `node-gyp` to use
20+ ENV PYTHON=/usr/bin/python3
21+
22+ # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend.
23+ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
24+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
25+ apt-get update && \
26+ apt-get install -y --no-install-recommends python3 g++ build-essential && \
27+ rm -rf /var/lib/apt/lists/*
28+
29+ # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
30+ # in which case you should also move better-sqlite3 to "devDependencies" in package.json.
31+ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
32+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
33+ apt-get update && \
34+ apt-get install -y --no-install-recommends libsqlite3-dev && \
35+ rm -rf /var/lib/apt/lists/*
36+
37+ USER node
38+ WORKDIR /app
39+
40+ COPY --from=packages --chown=node:node /app .
41+
42+ RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
43+ yarn install --immutable
44+
45+ COPY --chown=node:node . .
46+
47+ RUN yarn tsc
48+ RUN yarn --cwd packages/backend build
49+
50+ RUN mkdir packages/backend/dist/skeleton packages/backend/dist/bundle \
51+ && tar xzf packages/backend/dist/skeleton.tar.gz -C packages/backend/dist/skeleton \
52+ && tar xzf packages/backend/dist/bundle.tar.gz -C packages/backend/dist/bundle
53+
54+ # Stage 3 - Build the actual backend image and install production dependencies
55+ FROM node:20-bookworm-slim
56+
57+ # Set Python interpreter for `node-gyp` to use
58+ ENV PYTHON=/usr/bin/python3
59+
60+ # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend.
61+ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
62+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
63+ apt-get update && \
64+ apt-get install -y --no-install-recommends python3 g++ build-essential && \
65+ rm -rf /var/lib/apt/lists/*
66+
67+ # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
68+ # in which case you should also move better-sqlite3 to "devDependencies" in package.json.
69+ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
70+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
71+ apt-get update && \
72+ apt-get install -y --no-install-recommends libsqlite3-dev && \
73+ rm -rf /var/lib/apt/lists/*
74+
75+ # From here on we use the least-privileged `node` user to run the backend.
76+ USER node
77+
78+ # This should create the app dir as `node`.
79+ # If it is instead created as `root` then the `tar` command below will
80+ # fail: `can't create directory 'packages/': Permission denied`.
81+ # If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`)
82+ # so the app dir is correctly created as `node`.
83+ WORKDIR /app
84+
85+ # Copy the install dependencies from the build stage and context
86+ COPY --from=build --chown=node:node /app/.yarn ./.yarn
87+ COPY --from=build --chown=node:node /app/.yarnrc.yml ./
88+ COPY --from=build --chown=node:node /app/backstage.json ./
89+ COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton/ ./
90+
91+ # Note: The skeleton bundle only includes package.json files -- if your app has
92+ # plugins that define a `bin` export, the bin files need to be copied as well to
93+ # be linked in node_modules/.bin during yarn install.
94+
95+ RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
96+ yarn workspaces focus --all --production && rm -rf "$(yarn cache clean)"
97+
98+ # Copy the built packages from the build stage
99+ COPY --from=build --chown=node:node /app/packages/backend/dist/bundle/ ./
100+
101+ # Copy any other files that we need at runtime
102+ COPY --chown=node:node app-config*.yaml ./
103+
104+ # This will include the examples, if you don't need these simply remove this line
105+ COPY --chown=node:node examples ./examples
106+
107+ # This switches many Node.js dependencies to production mode.
108+ ENV NODE_ENV=production
109+
110+ # This disables node snapshot for Node 20 to work with the Scaffolder
111+ ENV NODE_OPTIONS="--no-node-snapshot"
112+
113+ CMD ["node" , "packages/backend" , "--config" , "app-config.yaml" , "--config" , "app-config.production.yaml" ]
0 commit comments