🐱
Next.jsのスリムなコンテナイメージを作成するDockerfile
Next.jsをAWS ECSで運用する機会があり、その為のコンテナイメージを作成する為のDockerfileを整備したので、その備忘になります。
なるべくイメージサイズを小さくしようと整備した内容になります。
前提
- Next.js v15系
- Next.jsのビルドはスタンドアロンモードを利用する
- Dockerのマルチステージビルドを利用する
- とりあえずECSで動くように
Next.jsをスタンドアロンモードでビルドできるように設定
next.config.ts
const nextConfig: NextConfig = {
output: 'standalone'
}
export default nextConfig
これだけです。
スタンドアロンモードでビルドを行うと、.next/standalone
ディレクトリが作成され、実行に必要な最小限のファイルのみがそこにコピーされるようになります。
node_modules
もコピーされますが、中身はかなりスリムになっているはずです。
ちなみにスタンドアロンモードでビルドを行った場合の起動方法は、next start
ではなく、node server.js
のようになります。
マルチステージビルドのDockerfileを用意する
Dockerfile
FROM node:20.19.0-alpine AS base
# ---
# ビルド環境
# ---
FROM base AS builder
WORKDIR /app
# ソースをコピー
COPY . .
# ビルド
RUN yarn install && yarn cache clean
RUN yarn build
# ---
# 実行環境
# ---
FROM base AS runner
WORKDIR /app
# curlコマンドをインストール(ヘルスチェック用)
RUN apk add --no-cache curl
# 実行に必要なファイルをビルド環境からコピー
COPY /app/public ./public
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
EXPOSE 3000
ENV PORT=3000
CMD ["node", "server.js"]
こんな感じです。
基本的にコメントで記載している通りですが、
- baseのイメージを定義。(FROMは環境用に変更してください
- ビルド用のステージ(builder)でビルド
- 実行用のステージ(runner)に実行に必要なファイルのみをbuilderからコピー
- alpineにはcurlコマンドが含まれていないので追加
-
node server.js
で実行
こうすることで、実行用のコンテナイメージには実行に必要な最低限のファイルのみが含まれるようになり、イメージサイズを小さくすることができます。
自分の例だと、1.8GB → 250MB にできました。
curlコマンドをインストールしている理由
ECSのタスク定義でヘルスチェック用のパスを変更する場合、
CMD-SHELL,curl -f http://localhost/health || exit 1
のように設定するのですが、ここでcurlを利用する為です。
最初自分はなぜヘルスチェックが失敗するのか分からず詰まりました。(まさかcurlが使えないとは思わず。。。
wgetを利用するような記事もありましたが、自分はcurlぐらいは入れておこうかなと。
HOSTNAME=0.0.0.0
を設定
コンテナ実行時の環境変数にコンテナを実行する環境変数にHOSTNAME=0.0.0.0
を設定します。
ECSだとタスク定義の環境変数。
node server.js
で起動する際にはHOSTNAME
を参照してしまうようで、設定しないと下記のように起動してしまう為になります。
▲ Next.js 15.2.2
- Local: http://ip-xx-xx-xx-xx.ap-northxxx:80
- Network: http://ip-xx-xx-xx-xx.ap-northxxx:80
本来は下記のように起動して欲しい。
▲ Next.js 15.2.2
- Local: http://localhost:80
- Network: http://0.0.0.0:80
Discussion