跳至主要內容
版本:10.x

使用 Docker

注意事項

在建置時期,您無法在Docker容器與主機檔案系統間建立參照連結 (reflink) 或硬連結 (hard link)。 但您仍可透過 BuildKit 的 cache mount 功能,在不同組建間共享快取。 Alternatively, you may use podman because it can mount Btrfs volumes during build time.

最小化 Docker 映像尺寸及建置時間

  • Use a small image, e.g. node:XX-slim.
  • 盡可能利用多階段建置。
  • 利用 BuildKit 快取掛載區功能。

例一:在 Docker 容器中建置軟體包

Since devDependencies is only necessary for building the bundle, pnpm install --prod will be a separate stage from pnpm install and pnpm run build, allowing the final stage to copy only necessary files from the earlier stages, minimizing the size of the final image.

.dockerignore
node_modules
.git
.gitignore
*.md
dist
Dockerfile
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app

FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile

FROM base AS build
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build

FROM base
COPY --from=prod-deps /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
EXPOSE 8000
CMD [ "pnpm", "start" ]

例二:在 monorepo 中建置多個 Docker 映像

假設您的 monorepo 含有三個套件:app1、app2 及 common,app1 及 app2 依賴於 common,但不互相依賴。

You want to save only necessary dependencies for each package, pnpm deploy should help you with copying only necessary files and packages.

Structure of the monorepo
./
├── Dockerfile
├── .dockerignore
├── .gitignore
├── packages/
│   ├── app1/
│   │   ├── dist/
│   │   ├── package.json
│   │   ├── src/
│   │   └── tsconfig.json
│   ├── app2/
│   │   ├── dist/
│   │   ├── package.json
│   │   ├── src/
│   │   └── tsconfig.json
│   └── common/
│   ├── dist/
│   ├── package.json
│   ├── src/
│   └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── tsconfig.json
pnpm-workspace.yaml
packages:
- 'packages/*'
.dockerignore
node_modules
.git
.gitignore
*.md
dist
Dockerfile
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

FROM base AS build
COPY . /usr/src/app
WORKDIR /usr/src/app
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run -r build
RUN pnpm deploy --filter=app1 --prod /prod/app1
RUN pnpm deploy --filter=app2 --prod /prod/app2

FROM base AS app1
COPY --from=build /prod/app1 /prod/app1
WORKDIR /prod/app1
EXPOSE 8000
CMD [ "pnpm", "start" ]

FROM base AS app2
COPY --from=build /prod/app2 /prod/app2
WORKDIR /prod/app2
EXPOSE 8001
CMD [ "pnpm", "start" ]

執行下列命令來建置 app1 和 app2 的映像:

docker build . --target app1 --tag app1:latest
docker build . --target app2 --tag app2:latest

Example 3: Build on CI/CD

On CI or CD environments, the BuildKit cache mounts might not be available, because the VM or container is ephemeral and only normal docker cache will work.

So an alternative is to use a typical Dockerfile with layers that are built incrementally, for this scenario, pnpm fetch is the best option, as it only needs the pnpm-lock.yaml file and the layer cache will only be lost when you change the dependencies.

Dockerfile
FROM node:20-slim AS base

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

FROM base AS prod

COPY pnpm-lock.yaml /app
WORKDIR /app
RUN pnpm fetch --prod

COPY . /app
RUN pnpm run build

FROM base
COPY --from=prod /app/node_modules /app/node_modules
COPY --from=prod /app/dist /app/dist
EXPOSE 8000
CMD [ "pnpm", "start" ]