DockerでNext.jsのアプリケーションを起動させる

# はじめに
DockerでWebサーバーとして、Next.jsのアプリケーションを起動させるために学習したこと、Dockerfileの内容について記載します。

# Dockerfileとdocker-compose
```dockerfile.
FROM node:16-alpine AS builder

#node:alpineで不足しがちな共有ライブラリを追加
RUN apk add --no-cache libc6-compat 
WORKDIR /nextapp
#匿名での情報収集を拒否する設定
ENV NEXT_TELEMETRY_DISABLED 1

COPY package.json ./package.json
COPY package-lock.json ./package-lock.json

COPY tsconfig.json ./tsconfig.json
COPY next.config.js ./next.config.js
COPY next-env.d.ts ./next-env.d.ts

COPY public/ ./public/
COPY src/ ./src/

#package-lock.json から依存関係をインストール
RUN npm ci 

FROM node:16-alpine as runner

#ENV NODE_ENV production
#ENV NODE_ENV dev
ENV NEXT_TELEMETRY_DISABLED 1

COPY --from=builder /nextapp/next.config.js next.config.js 
COPY --from=builder /nextapp/tsconfig.json tsconfig.json
COPY --from=builder /nextapp/public/ public/
COPY --from=builder /nextapp/src src/
COPY --from=builder /nextapp/node_modules/ node_modules/

COPY --from=builder /nextapp/package.json package.json
COPY --from=builder /nextapp/package-lock.json package-lock.json


#RUN npm run build #JSファイルやCSSファイルをマージする、やる必要あるのか？
# CMD sh -c "npm run dev"　
```

[Next.jsにて環境変数を用いて、APIのURLを変更する方法](https://qiita.com/YukiOnishi/items/2fcda5a350bd3655e676)


```docker-compose.
version: '3'
services:
  nextapp:
    image: nextapp
    container_name: nextapp
    build:
      context: ./nextapp
      dockerfile: ../dockerfile/nextapp/Dockerfile
    ports:
      - "127.0.0.1:3000:3000"
    tty: true
    volumes:
     - .:/nextapp #ホスト:コンテナ
    environment:
     - WATCHPACK_POLLING=true
    command: sh -c "npm run dev"
```
[NODE_ENV ってなんだ？](https://qiita.com/domodomodomo/items/11852a656750733eecc7)


### メモ
docker-compose buildはイメージの作成。
docker-compose upはイメージ＆コンテナ作成＆起動。-dオプションを付けてバックグランドで実行出来。
DockerfileのrunコマンドはDockerfileからImageを作成するとき、CMD命令はDockerイメージからDockerコンテナを作成するときに実行される。
docker-composeで指定するcommandは、DockerfileのCMDよりも優先される。

※｢Create Next App｣で新しい Next.js アプリケーションの構築ができる。

# 補足
### Node.jsとは
>Node.jsとJavaScriptの違い
JavaScriptはプログラミング言語です。プログラミング言語は決められた法則に則って、処理を表すための言語のことです。一方でNode.jsは実行環境を指します。プログラミング言語で書かれたソースを読み取り、処理を行うためのものです。JavaScriptなどの言語はそれ単体では動作せず、必ず実行環境が必要です。 
TypeScriptの実行環境としても使えます。
[Node.jsとは？JavaScriptとの違いや使い所を解説](https://and-engineer.com/articles/YUMHrxAAACUAtw4C#heading3-1)

今回のアプリ開発では、node.jsはWebサーバーとしての役割をはたしている。
Next.jsのコードをnode.jsで実行して、Webサーバーとする。

### Webサーバーとは
>Webサーバは、クライアントと直接やりとりするサーバ。リクエストを受けると、リクエストに対応した結果をクライアントに返却します。静的ファイル（HTMLや画像など）は、そのまま送る。動的な処理が含まれる場合は、APサーバへリクエストを依頼して、返却された結果をクライアントに返却。
[サーバとは？アプリケーション構成やWeb、AP、DBの違いを簡単解説！](https://teech-lab.com/server-application-db/775/)

Web３層構成…Webサーバー・アプリケーションサーバー・データベースサーバーで構築されるサーバーの仕組み

### 考えたこと


### 参考
[DockerでNext.jsの環境構築をする](https://zenn.dev/temple_c_tech/articles/setup-next-on-docker)
[【初心者向け】docker-compose run, up, build, createの違い。](https://prograshi.com/platform/docker/difference-among-docker-compose-run-up-build-and-create/)
[docker-compose `up` とか `build` とか `start` とかの違いを理解できていなかったのでまとめてみた](https://qiita.com/tegnike/items/bcdcee0320e11a928d46)
[DockerfileのRUN命令とCMD命令の違い【Docker】](https://rara-world.com/dockerfile-run-cmd/#:~:text=RUN%E5%91%BD%E4%BB%A4%E3%81%AFDockerfile%E3%81%8B%E3%82%89,%E3%81%A8%E3%81%8D%E3%81%AB%E5%AE%9F%E8%A1%8C%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82)
[docker-composeで指定するcommandはDockerfileよりも優先される](https://qiita.com/ganyariya/items/3594ec682a3ccf917477)
[Next.js公式リファレンス](https://nextjs-ja-translation-docs.vercel.app/docs/api-reference/create-next-app)


## 参考フォルダ
[Next.jsをDockerコンテナでデプロイする](https://de-milestones.com/next-js-docker-deploy/)
[DockerでNode.jsを動かすときのベストプラクティス](https://blog.shinonome.io/nodejs-docker/)
[DockerでNext.jsの環境構築をする](https://zenn.dev/temple_c_tech/articles/setup-next-on-docker)
[【docker】docker-compose.ymlのvolumesって何してるの？【304日目】](https://www.nyamucoro.com/entry/2018/08/13/222617)

## エラーの解決
Docker起動時,以下のエラーが出たため以下の記事を参考にして処理を実施したが、自分の力では解決することができなかった。

```
warn  - Attempted to load @next/swc-linux-x64-gnu, but it was not installed
warn  - Attempted to load @next/swc-linux-x64-gnux32, but it was not installed
warn  - Attempted to load @next/swc-linux-x64-musl, but it was not installed
```

[【Next.js】Failed to load SWC binary for linux/arm64の解消法【Docker】](https://qiita.com/P-man_Brown/items/db1996bdee33ee667741)

有識者に質問したところ、docker-compose.ymlのnextappの設定のうち

    volumes:
     - ./nextapp:/nextapp

という箇所の指定によって./nextapp/node_modulesもマウントされてしまうので、ホスト側(Macbook側)の./nextapp/node_modulesディレクトリがコンテナのnode_modulesディレクトリを上書きしてしまっている、ことが原因であったことが判明。

それを回避するために、

この現象を回避するには、docker-compose.ymlの上記の箇所を


    volumes:
     - ./nextapp:/nextapp
     - /nextapp/node_modules

と変更。

上記の問題は解決した。


# 改良したDockerfileとdocker-compose
```
FROM node:16-alpine

#node:alpineで不足しがちな共有ライブラリを追加
RUN apk add --no-cache libc6-compat 
WORKDIR /nextapp
#匿名での情報収集を拒否する設定
ENV NEXT_TELEMETRY_DISABLED 1

COPY package.json yarn.lock ./

#package-lock.json から依存関係をインストール
#y--frozen-lockfileをつけることでyarn.lockを更新しない
RUN yarn install --frozen-lockfile && yarn cache clean

COPY tsconfig.json next.config.js next-env.d.ts ./
COPY public/ ./public/
COPY src/ ./src/

CMD ["yarn", "dev"]
```

```
services:
  nextapp:
    image: nextapp
    container_name: nextapp
    build:
      context: ./nextapp
      dockerfile: ../dockerfile/nextapp/Dockerfile
    ports:
      - "127.0.0.1:3000:3000"
    tty: true
    volumes:
        #マウントさせたいホスト側のディレクトリ:マウントさせたいコンテナのディレクトリ
     - ./nextapp:/nextapp #ホスト:コンテナ
     
     - #コンテナのnode_modulesを匿名ボリュームに保存
     - #ホスト側のnode_modulesがコンテナにマウントされないようにしている
     - /nextapp/node_modules　
     
    environment:
     - WATCHPACK_POLLING=true
    command: sh -c "npm run dev"
```

# Docker Volumeについて

[Dockerでvolumesを設定する](https://zenn.dev/ajapa/articles/fc1205d4bcbfe7)
[VSCode&Docker Volumeにおけるnode_modules問題を解決する](https://zenn.dev/yumemi_inc/articles/3d327557af3554)
[Docker の Volume がよくわからないから調べた](https://qiita.com/aki_55p/items/63c47214cab7bcb027e0)