4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerを軽量化するマルチステージビルド(Next.jsとNest.jsのTypeScript開発)

Last updated at Posted at 2025-02-07

Dockerのマルチステージビルドとは

Dockerfile内で複数のビルドステージを定義し、軽量な本番用イメージを作成するやり方です。これのおかげで大きなイメージ(例えば1.2GBなど)から、運用に必要な最小限のファイルだけを含む軽量なイメージ(例:100MB)にまで縮小することが可能になります。
Dockerって構築すると容量などが取られるのでそこがネックでしたが、それを解決する手法になりそうです。

メリット

不要なファイルやツールの排除ができ、転送・デプロイが高速になり最終イメージも軽量化できます。

デメリット

Dockerfileの複雑化、中間ステージの内容が最終イメージに含まれずデバックが難しくなり、学習コストが増加します。

マルチステージビルドの仕組み

  • 複数のFROM
    Dockerfile内に複数のFROMを記述することで、複数のステージを作成します。
  • ビルドステージ
    コンパイルやトランスパイル、テストなどを実行し、最終成果物を作ります。
  • 本番ステージ
    ビルドステージから必要な成果物だけをCOPY --from=<ステージ名>で取り込み、実行環境のみを構築する。
  • 不要なファイル・ツールを含まない
    ビルド時に必要なツールは最終イメージには含めないため、イメージサイズを大幅に削減できます。

Next.jsとNest.jsで構築

Next.jsとNest.jsのTYpeScriptの開発で検証してみます。あくまで一例です。
至らない点はありますがご了承ください。
ファイル構成はこんな感じにします。

docker-multi-stage-build-next-nest-ts/
├── client/         # Next.js(フロントエンド)プロジェクト
│   ├── package.json
│   ├── tsconfig.json
│   ├── src/
│   │   └── pages/
│   │       └── index.tsx
│   └── Dockerfile
├── server/         # Nest.js(バックエンド)プロジェクト
│   ├── package.json
│   ├── tsconfig.json
│   ├── src/
│   │   ├── main.ts
│   │   ├── app.module.ts
│   │   └── todos/
│   │       ├── todos.controller.ts
│   │       ├── todos.module.ts
│   │       └── todos.service.ts
│   └── Dockerfile
└── docker-compose.yml

それぞれの中身を見ていきます。docker-compose.ymlはざっくりこんな感じです。

docker-compose.yml
version: '3'
services:
  client:
    build: ./client
    ports:
      - "3000:3000"
    depends_on:
      - server
  server:
    build: ./server
    ports:
      - "3001:3001"

ここからマルチステージビルドをやっていきます。
Next.jsのclient/Dockerfileです。

# --- Stage 1: ビルドステージ ---
    FROM node:18-alpine AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm install
    COPY . .
    RUN npm run build

    # --- Stage 2: 本番用ステージ ---
    FROM node:18-alpine
    WORKDIR /app
    COPY --from=builder /app/.next ./.next
    COPY --from=builder /app/public ./public
    COPY --from=builder /app/package.json ./
    RUN npm install --only=production
    EXPOSE 3000
    CMD ["npm", "start"]

Nest.jsのserver/Dockerfileです。

# --- Stage 1: ビルドステージ ---
    FROM node:16 AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm install
    COPY . .
    RUN npm run build

    # --- Stage 2: 本番用ステージ ---
    FROM node:16-alpine
    WORKDIR /app
    # ビルド済みの成果物だけをコピー
    COPY --from=builder /app/dist ./dist
    COPY --from=builder /app/package.json ./
    RUN npm install --only=production
    EXPOSE 3001
    CMD ["node", "dist/main.js"]

Docker

上の状態でdockerを起動します。

docker compose up --build -d

Dockerは普通に停止できます。

docker compose down

起動する時は以下のコマンドにします。

docker compose up -d

両者の比較

実際にこんだけ違いました。In useがマルチストレージUnusedがシングルストレージです。
マルチストレージが817MBシングルストレージが1.64GBほどです。
シングルストレージの半分の容量で構築ができています。

スクリーンショット 2025-02-07 0.58.10.png

参考動画、資料

Dockerイメージを100分の1の容量にする手法がまとめられている動画はこちら
1.2GBから10MBまで圧縮できるみたいで、
マルチステージビルドというやり方はdocker使う上では常識的に知っておくべき手法みたいです。

Docker Image BEST Practices - From 1.2GB to 10MB

  • ChatGPT参照

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?