DockerとWSL2を使ってReact&Django&MySQLの開発環境を作る

## 目的
```
# docker-compose up -d --build
```

環境構築がとても嫌い
これだけで全てを完結させたい

そんな人のための手順書になります。

## 使うもの
#### Docker
コンテナ型の仮想化ソフトウェアです。
データやプログラム（Apache、MySQL、Softwareなど）を隔離（コンテナ化）できる仕組みです。
バージョン：v20.10.17

#### Docker Compose
複数のコンテナを定義し実行する Docker アプリケーションのためのツールです。
コンテナをまとめて実行・停止・破棄したりできるます。
バージョン：v2.6.1

#### Docker Desktop
Dockerコンテナーなどの開発環境を構築できる便利なツールです。
バージョン：v4.10.1

#### WSL2
windowsからリナックスカーネルを操作できるようになります。
DockerはLinux上で動作するので、これがあると何かと便利です。
WindowsのエディタであるvsCodeからLinux上にあるファイルへアクセス（編集）出来るようになります。

また、従来のHyper-V上でDockerを動かすよりも優れたパフォーマンスを提供してくれます。
バージョン（Ubuntu）：20.04 LTS

#### VS Code
言わずもがな有能エディターです。


## 構築するもの
構築する環境は以下のようなイメージです。
WSL2上でDockerを動かしコンテナを構築します。そのコンテナにVS Codeを使ってアクセスできるようにします。

<img width=600 alt="環境" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/fd5fcc0c-9c61-cab0-a071-f51504fbd8d2.png">

## フォルダ構成
今回構築するフォルダ構成はこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/6dc706ee-1dc6-877c-a0e7-a3c4148af029.png)

| 1 | 2 |
|:-:|:-:|
| PROJECT | プロジェクトのルートフォルダ |
| back | バックエンド（Django）ファイル置き場 |
| code | コンテナのワークディレクトリ |
| Dockerfile | Dockerの定義ファイル |
| .devcontainer.json | コンテナ接続用のVS Code設定ファイル |
| requirements.txt | Pythonのパッケージ管理ファイル |
| front | フロントエンド（React）ファイル置き場 |
| Docker-compose.yml | Docker Composeの定義ファイル |

## ファイル作成
早速Dockerファイルを作っていきます。

#### Django
まずはバックエンド側を作っていきます。

- Dockerfile
Dockerコマンドについての説明は省略しますが、各命令文で何をやっているかはコメントに記載しています。
```Dockerfile:Dockerfile
# ベースとなるDokcerイメージを指定する
FROM python:3

# コンソールのstdout（標準出力）と
# stderr（標準エラー出力）のバッファーを無効にする
ENV PYTHONUNBUFFERED 1

# ワークディレクトリを指定する。
WORKDIR /code

# ホストマシンにあるrequirements.txtをImage側のマシンへコピーする
COPY ./requirements.txt .

# pipコマンドを最新にし、
# requirements.txtファイル内のパッケージをインストールする
RUN pip install --upgrade pip && pip install -r ./requirements.txt
```

- requirements.txt
今回はDjangoとMySQLを操作するためのクライアントを入れます。
ついでにコードフォーマッティングのblackも入れておきます。
```:requirements.txt
django==3.2
mysqlclient
black
```

- .devcontainer.json
ここにはVS Codeで接続するコンテナに関する設定と記述します。
また、VS Code自体の拡張機能や設定内容もあらかじめ定義することが可能です。
```:.devcontainer.json
{
  // コンテナに関する設定
  "name": "handson-back",
  "dockerComposeFile": [
    "../docker-compose.yml"
  ],
  "service": "handson-back",
  "shutdownAction": "none",
  "workspaceFolder": "/code",
  // コンテナにつなげるVS Codeの拡張機能設定
  "extensions": [
    "ms-python.python",
    "CoenraadS.bracket-pair-colorizer-2"
  ],
  // コンテナにつなげるVS Codeの設定
  "settings": {
    "python.formatting.provider": "black",
    "editor.defaultFormatter": null,
    "editor.formatOnSave": true
  }
}
```

#### React
つづいてフロントエンド側を作っていきます。

- Dockerfile
これだけ
```Dockerfile:Dockerfile
FROM node:17-alpine

WORKDIR /code
```

- .devcontainer.json
ここにはVS Codeで接続するコンテナに関する設定と記述します。
また、VS Code自体の拡張機能や設定内容もあらかじめ定義することが可能です。
```:.devcontainer.json
{
  // コンテナに関する設定
  "name": "handson-front",
  "dockerComposeFile": [
    "../docker-compose.yml"
  ],
  "service": "handson-front",
  "shutdownAction": "none",
  "workspaceFolder": "/code",

  // コンテナにつなげるVS Codeの拡張機能設定
  "extensions": [
    "dsznajder.es7-react-js-snippets",
    "esbenp.prettier-vscode",
    "CoenraadS.bracket-pair-colorizer-2"
  ],

  // コンテナにつなげるVS Codeの設定
  "settings": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "prettier.singleQuote": false,
    "prettier.jsxSingleQuote": false
  }
}
```

### Docker Compose
最後にdocker-compose.ymlファイルを作成します。
ymlファイルの書き方については省略しますが、何をやっているかはコメントに記載しています。

```yml:docker-compose.yml
# Composeファイル形式
version: '3'

# Dockerの中にボリュームというデータを保持する領域を確保
volumes:
  handson-db-data:

services:
  # データベース（mysql）
  handson-db:
    image: mysql:8.0.23
    container_name: my-db
    # mysqlコンテナがデータを保管する場所とコンテナが保持する領域を紐づける
    volumes:
      - 'handson-db-data:/var/lib/mysql'
    ports:
      - '3308:3306'
    environment:
      # rootユーザーのパス（必須）
      - 'MYSQL_ROOT_PASSWORD=root'
      # 初期作成されるDB名（任意）
      - 'MYSQL_DATABASE=my-db'
      # 作成されるユーザー名（任意）
      - 'MYSQL_USER=my-user'
      # ユーザーのパス（任意）
      - 'MYSQL_PASSWORD=my-user'
      - 'TZ=Asia/Tokyo'

  # バックエンド（django）
  handson-back:
    container_name: my-back
    # docker build で指定するDockerfileの場所
    build: ./back
    # ポートの指定
    ports:
      - '8000:8000'
    # ファイルシステムのマウント設定
    volumes:
      - './back/code:/code'
    # バッシュを開くためのコマンド
    tty: true
    stdin_open: true

    depends_on:
      - handson-db

  # フロントエンド（React）
  handson-front:
    container_name: my-front
    # docker build で指定するDockerfileの場所
    build: ./front
    # ポートの指定
    ports:
      - '3000:3000'
    # ファイルシステムのマウント設定
    volumes:
      - './front/code:/code'
    # バッシュを開くためのコマンド
    tty: true
    stdin_open: true

```

## コンテナの起動
では各ファイルの準備ができたら実際にコンテナを作っていきます。
docker-compose.ymlファイルがある階層にて下記コマンドを実行してください。

```
$ docker-compose up –d --build
```

ビルドが完了したらDocker Desktopからコンテナが作られたかを確認できます。
![コンテナ確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/003e794f-28f6-8a9e-0711-ebb7a2c25f35.png)


## VS Codeからコンテナへ接続
#### 拡張機能のインストール
まずコンテナに接続するためにリモート開発の拡張パックをインストールします。
https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack

#### コンテナに接続
拡張機能がインストールできたら、画面左下にリモート接続のアイコンが表示されます。
アイコンを押下し、画面上部に出てくるメニューの中から「Open Folder in Container...」を選択してください。
![VSCode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/1f9e65c1-271c-eb72-0328-07787db5bc23.png)

エクスプローラーが立ち上がりますので、バックエンド用のDockerfileを配置している場所を選択し開いてください。
今回は「back」というフォルダになります。

接続が成功した場合、VS Codeの左下に接続先のコンテナ名が表示されます。
また、コンテナのワークディレクトリとして設定した「code」フォルダが開かれている状態となります。
![VSCode_django.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/48c5a537-10ed-0fee-1a68-0de16620014c.png)


同様の手順で「front」というフォルダになりますを選択し開けば、フロイントエンド用のコンテナに接続ができるようになります。


ここまでの手順で当初予定していた開発環境の構築は完了となります。

<img width=600 alt="環境" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/fd5fcc0c-9c61-cab0-a071-f51504fbd8d2.png">


ついでにDjangoおよびReactをインストールし、開発サーバーが立ち上げられるか確認します。

## 開発サーバーの起動

#### Django
バックエンド用のコンテナに接続したVS Codeターミナルで下記コマンドを実行してください。
```
# django-admin startproject mysite
```

![django.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/f1c71940-e9b6-f8a8-4961-c134f833bc7b.png)

djangoのプロジェクトが作られたら「manage.py」がある階層に移動し、下記コマンドにてサーバーを起動します。
```
# python manage.py runserver
```

最後にローカルのアドレスを開くDjangoが起動していることを確認できればOKです。

http://127.0.0.1:8000/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/7462e343-6318-ea86-b224-748c40879828.png)

#### React
同様の手順で今度はフロントエンド用のコンテナに接続したVS Codeターミナルで下記コマンドを実行してください。
```
# yarn create react-app my-app
```

![Rect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/ada4d9f0-44e9-6c5a-8a4c-32fdbda964a9.png)

Reactのアプリが作られたら「package.json」がある階層に移動し、下記コマンドにてサーバーを起動します。
```
# yarn start
```

最後にローカルのアドレスを開くReactが起動していることを確認できればOKです。

http://localhost:3000/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/662c3d40-39cd-c499-4fcc-62ec7158a1b6.png)


## まとめ
以上でDocker、WSL2を使った開発環境の手順になります。

「Dockerfile」や「docker-compose.yml」を一度定義してしまえば、次回以降誰が開発環境を構築しようとも
```
# docker-compose up -d --build
```
だけで済むようになります。

Dockerを使うメリットを少しでも感じていただけたら幸いです。