12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.jsのstandaloneでDockerのイメージサイズを大幅削減

Last updated at Posted at 2023-07-22

Next.jsのstandaloneのビルドとDockerのマルチステージビルドを試してみたら良い感じだったので書いてみました!

Next.jsのstandaloneのビルドとは?

アプリケーションをビルドするために必要なファイル(node_modulesも含め)を特定してビルドしてくれます。
→ ビルドのサイズを大幅に削減することができる!

使い方は簡単で、next.config.js の下記の部分に output: 'standalone' を追加するだけです。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
/* ↓↓↓追加した部分↓↓↓ */
  output: 'standalone',
/* ↑↑↑追加した部分↑↑↑ */
}

module.exports = nextConfig

以前は、next start を実行するためにパッケージの依存関係からすべてのファイルをインストールする必要があったみたいです。

内部では @vercel/nft を使用して、import、require、およびfsの使用状況を静的に分析して、ページが読み込む可能性のあるファイルを決定しているみたいです。

↓より詳しく知りたい方は覗いてみてください!

マルチステージビルドについて

1つのDockerfile内で複数のステージを定義して、効率的なイメージを作成することができます!
→ 最終的なイメージには必要なファイルのみ含まれて、イメージサイズが小さくなる!

マルチステージビルドが出る前は Dockerfile を複数作り、シェルスクリプトと組み合わせたりして、同じようなことをやっていたみたいです。

実際に書いてみる

実際にDockerfileを書いてみました。create-next-appで作ったものに追加しています。

シンプルなDockerfileを作ってビルド

まず、特に工夫せずに書いたシンプルなDockerfileがこんな感じだと思います。

npmの場合

Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm install

COPY . .

RUN npm run build

CMD [ "npm", "start" ] 

yarnの場合

Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package.json yarn.lock ./ 

RUN yarn install

COPY . .

RUN yarn build

CMD [ "yarn", "start" ] 

ビルド

以下のコマンドでビルドします。

docker build -t before .

standaloneやマルチステージビルドを使ったDockerfileを作ってビルド

次に、standaloneやマルチステージビルドを使ったDockerfileです。
next.config.js に output: 'standalone' を追記するのを忘れずに

npmの場合

Dockerfile
# 外部イメージをbaseステージとして扱う
FROM node:18-alpine AS base

# baseステージをもとにbuilderステージを開始
FROM base AS builder

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm install

COPY . .

RUN npm run build

# baseステージをもとにrunnerステージを開始
FROM base AS runner

WORKDIR /app

# public と .next/static は nextjs の standalone を使う場合に含まれないため、コピーする必要がある
# https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files
# builderから必要なファイルだけコピーする
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static

COPY --from=builder /app/.next/standalone ./

# `next start` の代わりに `node server.js` を使用
# https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files
CMD ["node", "server.js"]

yarnの場合

Dockerfile
# 外部イメージをbaseステージとして扱う
FROM node:18-alpine AS base

# baseステージをもとにbuilderステージを開始
FROM base AS builder

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

COPY . .

RUN yarn build

# baseステージをもとにrunnerステージを開始
FROM base AS runner

WORKDIR /app

# public と .next/static は nextjs の standalone を使う場合に含まれないため、コピーする必要がある
# https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files
# builderから必要なファイルだけコピーする
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static

COPY --from=builder /app/.next/standalone ./

# `next start` の代わりに `node server.js` を使用
# https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files
CMD ["node", "server.js"]

ビルド

以下のコマンドでビルドします

docker build -t after .

結果

イメージサイズの結果はそれぞれ以下のようになりました!
※create-next-appで作ったもので比較しています🙇

docker images --format "{{.Repository}} {{.Size}}"
# after 204MB
# before 966MB

約1/5になった、すごい!!!
実際のプロジェクトでは正常に動作することを確認することをお勧めします🙇
(実際のプロジェクトだとどれくらい効果あるんだろう)

最後に

ここまで読んでくださりありがとうございます!
読んでくださった方の何かしらの役に立てれば嬉しいです!感想などいただけますと励みになります!

ちなみに Next.js の examples も standalone とマルチステージビルドを使って書かれてました!
npx create-next-app --example with-docker <ディレクトリ名> みたいな感じで簡単に使えますね!

参考にしたもの

12
5
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
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?