Trabalhando com Docker
É impossível criar reflinks ou hardlinks entre um contêiner Docker e o sistema de arquivos host durante o tempo de compilação. A próxima melhor coisa que você pode fazer é usar a montagem de cache do BuildKit para compartilhar o cache entre compilações. Alternatively, you may use podman because it can mount Btrfs volumes during build time.
Minimizando o tamanho da imagem Docker e o tempo de compilação
- Use a small image, e.g.
node:XX-slim
. - Aproveite os vários estágios, se possível e fizer sentido.
- Aproveite as montagens de cache do BuildKit.
Exemplo 1: Construa um pacote em um contêiner 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.
node_modules
.git
.gitignore
*.md
dist
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" ]
Exemplo 2: Construa várias imagens Docker em um monorepo
Supondo que você tenha um monorepo com 3 pacotes: app1, app2 e common; app1 e app2 dependem do common, mas não um do outro.
You want to save only necessary dependencies for each package, pnpm deploy
should help you with copying only necessary files and packages.
./
├── 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
packages:
- 'packages/*'
node_modules
.git
.gitignore
*.md
dist
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" ]
Execute os seguintes comandos para criar imagens para app1 e 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.
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" ]