Contents
はじめに
最近、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の内容はそれぞれ下記のようになります。コンテナの作成方針は下記のとおりです。
- すぐにコンテナが動くように、コンテナのビルド時にNext.jsアプリのビルドも行う
- ソース類のownerはrootとする
- 実行ユーザーとグループはnext:nextとし、ソース書き換えから保護する
- 生成するフォルダのみ、実行ユーザーが書き込めるようにnext:nextとする
- その他生成される系はマウント
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
コンテナの内容確認
意図した作りになっているかも確認します。.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を使うとどうなるか、コンテナとの比較もしてみたいところですね。