a2c tech

Next.js用Dockerコンテナの作り方

Next.js create-next-app top page

はじめに

最近、Next.jsを触っています。Reactベースのアプリケーションフレームワークで、React単体では難しいServer Side Renderingや、事前にコンテンツを生成するStatic Site Generation機能を持っているため、SEOを考慮したSingle Page Applicationを構築しやすいのが特徴だと考えています。
加えてDeveloper Experienceも高い印象です。具体的には、TypeScriptサポートがほぼ完璧な状態で組み込まれており、ほぼ設定不要でそのまま使えます。TypeScriptに限らず、npm installするだけで残るはNext.jsが設定類をまるごと面倒見てくれるため、ツールキットの習得に時間がかからないのが良いですね。

そんなNext.jsで色々アプリを作ったあと、コンテナで動かしたくなったため、Dockerfileを書きました。参考までにアップしているのがこの記事です。

Next.jsコンテナ化への道のり

Next.jsのソースを作成

題材は、Next.jsを簡単にお試しできるcreate-next-appを使います。ローカル環境で、npx or yarnを使い、生成しましょう。

npx create-next-app
# or
yarn create-next-app

名前にデフォルトのmy-appとした場合、生成されたmy-appフォルダは下記のような構造になっています。このうち、コンテナで使うファイル・フォルダについては太字にしています。

~/d/my-app ❯❯❯ ls -al
drwxrwxr-x   22 a2c  staff     704  8  1 21:17 .
drwxr-xr-x   66 a2c  staff    2112  8  1 21:07 ..
-rw-r--r--    1 a2c  staff      32  6 30 07:25 .babelrc
-rw-r--r--    1 a2c  staff      38  6 30 07:25 .eslintignore
-rw-r--r--    1 a2c  staff    1138  6 30 07:25 .eslintrc.json
drwxr-xr-x   13 a2c  staff     416  8  1 21:29 .git
-rw-r--r--    1 a2c  staff     150  6 30 07:25 .gitignore
drwxr-xr-x    7 a2c  staff     224  8  1 21:08 .next
-rw-r--r--    1 a2c  staff      54  6 30 07:25 .prettierignore
-rw-r--r--    1 a2c  staff      43  6 30 07:25 .prettierrc
-rw-r--r--    1 a2c  staff    1715  6 30 07:25 README.md
-rw-r--r--    1 a2c  staff     554  6 30 07:25 jest.config.js
-rw-r--r--    1 a2c  staff      75  6 30 07:25 next-env.d.ts
drwxr-xr-x  800 a2c  staff   25600  6 30 10:34 node_modules
-rw-r--r--    1 a2c  staff  527892  6 30 10:34 package-lock.json
-rw-r--r--    1 a2c  staff    1344  6 30 07:25 package.json
drwxrwxr-x    4 a2c  staff     128  6 30 10:33 pages
drwxrwxr-x    4 a2c  staff     128  6 30 10:33 public
drwxrwxr-x    5 a2c  staff     160  6 30 10:33 test
-rw-r--r--    1 a2c  staff     512  6 30 07:25 tsconfig.json 

Dockerfile, .dockerignoreの作成

Dockerfile、.dockerignoreの内容はそれぞれ下記のようになります。コンテナの作成方針は下記のとおりです。

FROM node:lts

WORKDIR /opt/next
COPY ./pages ./pages
COPY ./public ./public
COPY ./next-env.d.ts ./next-env.d.ts
COPY ./package.json ./package.json
COPY ./package-lock.json ./package-lock.json
COPY ./tsconfig.json ./tsconfig.json

RUN npm ci && npm run build && 
    groupadd -r next && useradd -r -g next next && chown -R next:next .next

USER next
CMD ["npm", "run", "start"]
.next
node_modules

コンテナのビルド

my-app フォルダにて、下記のコマンドを実行してください。 -t next の部分は他のコンテナ名でも問題ありません。

docker build -t next . 

コンテナの実行

うまく動くか、コンテナを起動し、 http://localhost:3000 を表示します。Welcome to Next.js! が表示されればうまく動いています。Next.jsはデフォルトではポート番号3000で受け付けるので、同じポート番号を使ってコンテナにアクセスできるようにしています。

~/d/my-app ❯❯❯ docker run -d -p 3000:3000 next
8771f621851a962905e161c3d25416392cf0c117266aae7c36e0a2624d3a62b0 
http://localhost:3000/ へのアクセス結果

コンテナの内容確認

意図した作りになっているかも確認します。.nextは実行ユーザーが書き込めるようになっているし、それ以外のフォルダは書き込めないようになっています。

~/d/my-app ❯❯❯ docker exec -it 8771f621851a bash
next@8771f621851a:/opt/next$ ls -al
total 580
drwxr-xr-x   1 root root   4096 Aug  1 12:20 .
drwxr-xr-x   1 root root   4096 Aug  1 12:19 ..
drwxr-xr-x   5 next next   4096 Aug  1 12:20 .next
-rw-r--r--   1 root root     75 Jun 29 22:25 next-env.d.ts
drwxr-xr-x 800 root root  28672 Aug  1 12:20 node_modules
-rw-r--r--   1 root root 527892 Jun 30 01:34 package-lock.json
-rw-r--r--   1 root root   1344 Jun 29 22:25 package.json
drwxr-xr-x   3 root root   4096 Aug  1 12:19 pages
drwxr-xr-x   2 root root   4096 Aug  1 12:19 public
-rw-r--r--   1 root root    512 Jun 29 22:25 tsconfig.json 

next@8771f621851a:/opt/next$ ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
next         1  0.0  1.9 738712 39556 ?        Ssl  12:25   0:00 npm
next        17  0.0  0.0   4280   764 ?        S    12:25   0:00 sh -c next start
next        18  0.0  1.8 574348 38412 ?        Sl   12:25   0:00 node /opt/next/node_modules/.bin/next start
next        32  0.1  0.1  18188  3312 pts/0    Ss   13:01   0:00 bash
next        40  0.0  0.1  36632  2780 pts/0    R+   13:02   0:00 ps -aux

next@8771f621851a:/opt/next$ whoami
next 

まとめ

Next.jsのアプリをコンテナで起動する方法をまとめました。コンテナさえ作れれば、どの環境でもいい感じに使えるため、早い段階でコンテナ化しておくのがよいでしょう。
コンテナはエンジニアの基本的人権だと思います。

余談ですが、Next.js開発元のVercelを使うとどうなるか、コンテナとの比較もしてみたいところですね。