Next.js+Go+MySQLの環境をDockerで構築する

# はじめに
この記事では、frontend、backend、dbのコンテナを作成しコンテナ間通信が出来るようにする所まで説明しています。
ですので、それぞれの層での実装までは行わないので、予めご了承ください。🙇
## 環境
Docker : v24.0.6
Docker Compose : v2.23.0-desktop.1

## 構成図
```
.
├── docker-compose.yml
├── backend
│   ├── Dockerfile
│   └── app
│       └── main.go
├── frontend
│   ├── Dockerfile
│   ├── app
│   ├── public
│   ├── node_modules
│   ├── .eslintrc
│   ├── next-env.ts
│   ├── next.config.js
│   ├── package-lock.json
│   ├── package.json
│   ├── postcss.config.js
│   ├── README.md
│   ├── tailwind.config.ts
│   └── tsconfig.json
└── db
    ├── Dockerfile
    └── .env
```

# 1. 各ディレクトリの用意、docker-compose.yml記述
まずは、プロジェクト直下に以下の構成を作成して下さい。
```
.
├── docker-compose.yml
├── backend
│   ├── Dockerfile
│   └── app
│       └── main.go
└── db
    ├── Dockerfile
    └── .env
```

次に、frontendフォルダを作成していきます。
Next.jsのプロジェクトを作成するために以下のコマンドをターミナルで実行します。
``` bash
$ npx create-next-app frontend
```
すると、次々に設定をどのようにするか聞かれます。
今回は以下のように選択します。
``` bash
✔ Would you like to use TypeScript with this project? … Yes
✔ Would you like to use ESLint with this project? … Yes
✔ Would you like to use Tailwind CSS with this project? … Yes
✔ Would you like to use `src/` directory with this project? … No
✔ Use App Router (recommended)? … Yes
✔ Would you like to customize the default import alias? … No
```
これらのメッセージがどのような意味を持つかは、以下の記事が参考になりますので興味がありましたらご覧ください。😊
[create-next-appで訊かれていること
](https://zenn.dev/ikkik/articles/51d97ff70bd0da)

しばらく待つとfrontendディレクトリ内に色々なものがごちゃごちゃっと入りますが、とりあえずは無視でOKです。
また、frontendディレクトリ内に`Dockerfile`を作成します。

docker-compose.ymlを編集していきます。
``` docker-compose.yml
version: "3.8"
services:
    frontend:
        container_name: frontend
        build: ./frontend
        tty: true
        ports:
            - "3000:3000"
        depends_on:
            - backend
        volumes:
            - type: bind
              source: ./frontend
              target: /src/app
            - type: volume
              source: node_modules
              target: /src/app/node_modules
        command: "npm run dev"
        networks:
            - frontend_network
    backend:
        container_name: backend
        build: ./backend
        tty: true
        ports:
            - "8080:8080"
        depends_on:
            - db
        volumes:
            - type: bind
              source: ./backend/app
              target: /go/src/app
        networks:
            - frontend_network
            - backend_network

    db:
        container_name: db
        build: ./db
        tty: true
        platform: linux/x86_64
        ports:
            - 3306:3306
        env_file:
            - ./mysql/.env
        volumes:
            - mysql_test_volume:/var/lib/mysql
        networks:
            - backend_network

volumes:
    mysql_test_volume:
    node_modules:

networks:
    frontend_network:
        external: true
    backend_network:
        external: true
```

詳しいことは説明を省きますが、node_modulesに対してボリュームを設定することで、node_modulesが空の状態でホスト側の情報を反映させないようにしています。
詳しくは以下の記事を見ると分かりやすいです。
[【Docker】コンテナ内のnode_modulesが消える問題を改善する](https://qiita.com/P-man_Brown/items/c2a69d943853cb381fbe)

また、ネットワークの設定をすることで、コンテナ間通信が行えるようになります。

そして、dbディレクトリ内の`.env`ファイルを以下のように記述します。
``` .env
MYSQL_DATABASE=test_database
MYSQL_USER=test_user
MYSQL_PASSWORD=password
MYSQL_ROOT_PASSWORD=root_password
```
こちらの情報は、MySQLに接続するために使用します。
それぞれのキーには、好きな文字を当てはめてくだちい。

また、main.goは以下のようにします。
``` main.go

package main

import "fmt"

func main() {
	fmt.Println("Senritsu Big Love!")
}
```

# 各ディレクトリのDockerfileを編集、ネットワーク作成
続いて、Dockerfileに情報を追記します。
### backend/Dockerfile
``` Dockerfile
# goのバージョン指定
FROM golang:1.19.2-alpine3.16
# ディレクトリ作成
RUN mkdir /go/src/app
# 作業ディレクトリ変更
WORKDIR /go/src/app
# main.go実行
CMD ["go", "run", "main.go"]
```
### frontend/Dockerfile
``` Dockerfile
# node.jsのバージョン指定
FROM node:18.16.1-alpine
# 作業ディレクトリ変更
WORKDIR /src/app
# ホストのpackage.jsonをコンテナにコピー
COPY ./package.json ./
# コンテナに必要なパッケージをインストール
RUN npm install
```
### db/Dockerfile
```Dockerfile
# MySQLのバージョン指定
FROM mysql:8.0
```

後は、ネットワークの追加を行うだけで完了です。
以下のコマンドをターミナルに打ち込みます。
``` bash
$ docker network create frontend_network
$ docker network create backend_network
```

これで必要なものは揃えたので、Dockerイメージの作成とコンテナ起動を行います。
```
$ docker compose up
```
これで特にエラーが発生しなければ環境構築は完了となります。

# おわりに
今回はコンテナを作成する所まで行いました。
ここから実際にNext.jsとGoでやり取りを行うためにはCORSを設定しないといけないのですが、そちらは他の記事を参考に実装してみて下さい。😅

最後までご覧いただきありがとうございました！🎉

### 参考文献
- [create-next-appで訊かれていること
](https://zenn.dev/ikkik/articles/51d97ff70bd0da)
- [【Docker】コンテナ内のnode_modulesが消える問題を改善する](https://qiita.com/P-man_Brown/items/c2a69d943853cb381fbe)