From 8b0e0caef3177c7dffb7fe03fb7f0712b95118e5 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Wed, 21 Aug 2024 14:27:51 +0300 Subject: [PATCH 1/3] Update Docker and pnpm fetch to be more aligned and link to each other --- docs/cli/fetch.md | 25 ++++++++++++++++--------- docs/docker.md | 2 ++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/cli/fetch.md b/docs/cli/fetch.md index db0235d3dc8e..52a02da4b493 100644 --- a/docs/cli/fetch.md +++ b/docs/cli/fetch.md @@ -12,23 +12,28 @@ This command is specifically designed to improve building a docker image. You may have read the [official guide] to writing a Dockerfile for a Node.js app, if you haven't read it yet, you may want to read it first. +Also see [Working wirh Docker](../docker.md), for examples of multi-stage +builds, and `pnpm deploy` that can be combined with this command for a smaller +final image. + From that guide, we learn to write an optimized Dockerfile for projects using pnpm, which looks like ```Dockerfile FROM node:20 +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable pnpm && corepack install -g pnpm@latest-9 WORKDIR /path/to/somewhere -RUN corepack enable pnpm && corepack install -g pnpm@latest-9 - # Files required by pnpm install COPY .npmrc package.json pnpm-lock.yaml .pnpmfile.cjs ./ # If you patched any package, include patches before install too COPY patches patches -RUN pnpm install --frozen-lockfile --prod +RUN pnpm --mount=type=cache,id=pnpm,target=/pnpm/store install --frozen-lockfile --prod # Bundle app source COPY . . @@ -52,11 +57,12 @@ look like ```Dockerfile FROM node:20 +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable pnpm && corepack install -g pnpm@latest-9 WORKDIR /path/to/somewhere -RUN corepack enable pnpm && corepack install -g pnpm@latest-9 - # Files required by pnpm install COPY .npmrc package.json pnpm-lock.yaml .pnpmfile.cjs ./ @@ -69,7 +75,7 @@ COPY patches patches COPY packages/foo/package.json packages/foo/ COPY packages/bar/package.json packages/bar/ -RUN pnpm install --frozen-lockfile --prod +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --prod # Bundle app source COPY . . @@ -86,18 +92,19 @@ to load packages into the virtual store using only information from a lockfile. ```Dockerfile FROM node:20 +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable pnpm && corepack install -g pnpm@latest-9 WORKDIR /path/to/somewhere -RUN corepack enable pnpm && corepack install -g pnpm@latest-9 - # pnpm fetch does require only lockfile COPY pnpm-lock.yaml ./ # If you patched any package, include patches before running pnpm fetch COPY patches patches -RUN pnpm fetch --prod +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm fetch --prod ADD . ./ diff --git a/docs/docker.md b/docs/docker.md index 408722b45fa9..7b9b6ccb7c7c 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -3,6 +3,8 @@ id: docker title: Working with Docker --- +Also see [pnpm fetch](./cli/fetch.md) for a command that can be used to speed up consecutive builds. + :::note It is impossible to create reflinks or hardlinks between a Docker container and the host filesystem during build time. From 33d5d9ef74083078ec6fbccdc38e31f560281b1d Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sun, 3 Aug 2025 21:34:39 +0300 Subject: [PATCH 2/3] Add complex Dockerfile example --- docs/docker.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/docker.md b/docs/docker.md index c7b31bbee562..e52dbd9f1e45 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -167,3 +167,55 @@ COPY --from=prod /app/dist /app/dist EXPOSE 8000 CMD [ "pnpm", "start" ] ``` + +### Example 4: All techniques in one + +A verstaile option is to just use both fetch, deploy, cache mounts, newer Docker +features like `--link` all in one Docker file, and benefit from the build +performance and image size reducation at the cost of a more complex Dockerfile. + +This also includes running as a normal user instead of root, and properly +caching pnpm with corepack so the image won't need to download it on startup. + +```dockerfile title="Dockerfile" +# syntax=docker/dockerfile:1 +FROM node:22 AS build +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +ENV COREPACK_HOME="/corepack" +# Package to be built and deployed from the workspace +ARG PACKAGE=example + +WORKDIR /workspace +# The package.json is for corepack, pnpm fetch needs only the lockfile and workspace configuration +COPY --link package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +# If you have patches: +# COPY --link patches patches +RUN corepack enable && corepack install +RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ + pnpm fetch + +COPY --link . . + +RUN pnpm install --offline --frozen-lockfile + +RUN pnpm --filter $PACKAGE... build + +RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ + pnpm --filter $PACKAGE deploy --prod deploy + +FROM node:22-slim AS runtime +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +ENV COREPACK_HOME="/corepack" +RUN corepack enable + +WORKDIR /app +COPY --link --from=build /workspace/deploy . + +RUN corepack install +ENV COREPACK_DEFAULT_TO_LATEST=0 COREPACK_ENABLE_NETWORK=0 + +USER 1000 +CMD ["pnpm", "--silent", "start"] +``` From 5388e00bbcf08c5257a8fa12b24d5cced31512fa Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Tue, 5 Aug 2025 16:41:47 +0300 Subject: [PATCH 3/3] Simplify --- docs/docker.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/docker.md b/docs/docker.md index e52dbd9f1e45..7bead2db2bae 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -208,12 +208,11 @@ FROM node:22-slim AS runtime ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" ENV COREPACK_HOME="/corepack" -RUN corepack enable WORKDIR /app COPY --link --from=build /workspace/deploy . -RUN corepack install +RUN corepack enable && corepack install ENV COREPACK_DEFAULT_TO_LATEST=0 COREPACK_ENABLE_NETWORK=0 USER 1000