k8s 環境に Next.js プロジェクトをデプロイすることになったので、いろいろ書いてみた。
今回は npm ではなく、yarn を使用している。
環境
- ubuntu 20.04.1
- Docker 19.03.13
- Next.js 9.5.4
また、npm スクリプトはこんな感じ。
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
Docker 上で開発を行う
Docker 内の Node で開発を行う場合。ローカルの Node のバージョンを気にせず開発は行えるが、ローカルのエディタでは型定義などを読み込めず面倒ではある。
- Dockerfile
開発用なので、ベースイメージは通常のものにした。
FROM node:12.18.4
WORKDIR /app
# npmパッケージのインストールに必要なファイルをコピー
COPY package.json yarn.lock ./
# npmを使用している場合は、以下のようにする
# COPY package*.json ./
RUN yarn install
EXPOSE 3000
CMD ["yarn", "dev"]
- Docker build
docker build --rm -t next_dev:latest -f path/to/Dockerfile
- Docker run
プロジェクトのフォルダで実行する。(-v の引数にプロジェクトフォルダを絶対パスで指定すれば OK)
docker run -p 3000:3000 -v $PWD:/app -it next_dev:latest
Production 向けにビルドする
ここからは、本番向けにイメージを作成する。
とりあえず作ってみる
いつも通り作ってみる。本番向けなので alpine イメージを使う。
ビルドコンテキスト(Docker build 時に Docker デーモンへ送信されるファイルの場所)はプロジェクトフォルダ。
FROM node:12.18.4-alpine
WORKDIR /app
# ローカルのソースを全てコピー
COPY . /app
# npmパッケージのインストール、production向けにビルド
RUN yarn install && NODE_ENV=production yarn build
EXPOSE 3000
CMD ["yarn", "start"]
- ビルド&実行
ビルドにはプロジェクトフォルダで以下のコマンドを実行。
$ docker build --rm -t next_prod:latest -f path/to/Dockerfile
デーモンとして動かすには以下のコマンドを実行。
$ docker run -d -p 3000:3000 next_prod:latest
これでサーバー自体は動くが、このままでは Docker イメージのサイズが 900MB あるので、もう少しスリムにしたいところ。
(もちろん、イメージのサイズは Next.js プロジェクトの中身による)
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
next_prod latest d211c6246173 6 minutes ago 899MB
multi stage build する
multi stage build により、Docker イメージの容量を削減する。
- Dockerfile
FROM node:12.18.4-alpine AS base
# パッケージのインストールを行う
WORKDIR /base
COPY . .
RUN yarn install
# Production向けビルドを行う
FROM base AS build
WORKDIR /build
COPY --from=base /base ./
RUN NODE_ENV=production yarn build
# ビルド成果物をコピーし、サーバーを起動
FROM node:12.18.4-alpine AS production
ENV NODE_ENV=production
WORKDIR /app
# ビルド成果物のみをコピーしてやる
COPY --from=build /build/package.json /build/yarn.lock ./
COPY --from=build /build/.next ./.next
COPY --from=build /build/public ./public
# node_modules以下がこのイメージにないので、next.jsのサーバーを動かすために必要
RUN yarn add next
EXPOSE 3000
CMD ["yarn", "start"]
- ビルド&実行
$ docker build --rm -t next_prod:msb -f path/to/Dockerfile
$ docker run -d -p 3000:3000 next_prod:mdb
これにより、イメージはかなりスリムになった。各イメージの容量はこんな感じ。
$ docker images
REPOSITORY TAG SIZE
next_prod msb 574MB # production multi stage build
next_prod latest 899MB # production build
next_dev latest 1.44GB # dev
おわりに
DockernizeなのかDockerizeなのかよくわからない。