Working with Docker
メモ
コンテナビルド時、reflinkやハードリンクをDockerコンテナとホストファイルシステムの間で作ることはできません。 次善の策は、BuildKit キャッシュ マウントを使用してビルド間でキャッシュを共有することです。 あるいは、 podman を使用することもできます。これは、ビルド時に Btrfs ボリュームをマウントできるためです。
Docker のイメージ・サイズとビルド時間の最小化
- 小さいイメージを使用します。例えば、
node:XX-slim
- 可能で合理的であれば、マルチステージを活用します。
- BuildKit キャッシュ・マウントを利用します。
Example 1: Build a bundle in a Docker container
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" ]
Example 2: Build multiple Docker images in a monorepo
Assuming you have a monorepo with 3 packages: app1, app2, and common; app1 and app2 depend on common but not each other.
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
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 -r build
FROM base AS common
COPY --from=prod-deps /app/packages/common/node_modules/ /app/packages/common/node_modules
COPY --from=build /app/packages/common/dist /app/packages/common/dist
FROM common AS app1
COPY --from=prod-deps /app/packages/app1/node_modules/ /app/packages/app1/node_modules
COPY --from=build /app/packages/app1/dist /app/packages/app1/dist
WORKDIR /app/packages/app1
EXPOSE 8000
CMD [ "pnpm", "start" ]
FROM common AS app2
COPY --from=prod-deps /app/packages/app2/node_modules/ /app/packages/app2/node_modules
COPY --from=build /app/packages/app2/dist /app/packages/app2/dist
WORKDIR /app/packages/app2
EXPOSE 8001
CMD [ "pnpm", "start" ]
Run the following commands to build images for app1 and app2:
docker build . --target app1 --tag app1:latest
docker build . --target app2 --tag app2:latest