docker-compose.ymlの記述を考える(Django + MySQL③)

## この記事について
この記事は、[Django + MySQLの環境構築を通じてDockerの使い方を学ぶ](https://qiita.com/toffe_hy/items/f17d78abd92f0b4272f6)に関連する記事群の **Part.3** にあたります。

1. [venvを利用してPythonの仮想環境を構築する](https://qiita.com/toffe_hy/items/8c62f2bc7b14f1ce2ae0)
2. [Dockerfileの記述を考える](https://qiita.com/toffe_hy/items/0429a95bfe1786955c2a)
3. **docker-compose.ymlの記述を考える ( 当記事 )**
4. [設定ファイルを編集し docker-compose up を実行する](https://qiita.com/toffe_hy/items/0571b84faa3e6b834c6e)
5. [依存関係にあるサービス間のコンテナ立ち上げタイミングを調整する](https://qiita.com/toffe_hy/items/4b7d8c47c5a1a2defcac)

## はじめに

この記事では、**環境構築にあたっての手間や、実行が必要なコマンドを極力少なく**しながら、今後できる限り**狙った通りに Dockerコンテナ を作成することができる**よう、**`docker-compose.yml`**の記述について考えていきます。

Dockerコンテナについては、前回までに学んだ **Dockerイメージ** を実際に動かし、その動かされた**「プロジェクト用の小さなマシン」の現在の状態を実体化したもの**と捉えています。

Djangoのコンテナは前回作成した`Dockerfile`を元に、一方でMySQLのコンテナについては公式のイメージをそのまま使う流れで、作業を進めていきます。

今回は**`docker-compose.yml`も`Dockerfile`と同じ階層に作成**します。

## 記述内容
`docker-compose.yml`の全体としての記述は、以下の通りです。

```yml:docker-compose.yml
version: "3"
services:
    web:
        container_name: djst_django
        build: .
        restart: always
        command: >
            bash -c "
                pip install -r requirements.txt &&
                python manage.py runserver 0.0.0.0:8000
            "
        working_dir: /code
        ports: 
            - 127.0.0.1:8000:8000
        volumes:
            - .:/code
        depends_on:
            - db
    db:
        container_name: djst_mysql
        image: mysql:5.7
        restart: always
        environment: 
            MYSQL_DATABASE: $DB_NAME
            MYSQL_USER: $DB_USER
            MYSQL_PASSWORD: $DB_PASSWORD
            MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
            MYSQL_TCP_PORT: 3306
            TZ: 'Asia/Tokyo'
        volumes: 
            - ./mysql/data:/var/lib/mysql/
            - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
        ports: 
            - 3306:3306

```

## 記述の意味を考える


```yml
version: "3"
```
1行目、docker-composeのファイルフォーマットのバージョンです。
`$ docker-compose version`と実行して表示されるversionが`1.13.0`以降なら`"3"`、`1.10.0`以降なら`"2"`、このどちらでもなければ`"1"`になります。

```yml
services:
```
2行目から、このファイルで管理するサービス群に関する記述を始めます。


### Django側

```yml
web:
```
3行目、Djangoのアプリケーションを動かすサービスに関する記述を始めます。ここでimage名 ( の末尾 ) が命名されます。

```yml
container_name: djst_django
```
4行目、**生成されるコンテナの名前**です。ここで命名します。

```yml
build: .
```
5行目、この`docker-compose.yml`から見たときに、**どこにある`Dockerfile`を元にイメージを生成するか**を指定します。今回は同階層に配置しているため、`.`と記述します。

6行目は後ほどMySQLの項目で考えます。

```yml
command: >
    bash -c "
        pip install -r requirements.txt &&
        python manage.py runserver 0.0.0.0:8000
    "
```
7-12行目、後ほど`$ docker-compose up`コマンドを実行した際に、コンテナ内から走らせたいコマンドを記述します。`$ bash -c ""`で、`""`内に記述したコマンドを実行してくれます。

1. **`pip install`を実行しホストとコンテナ内で利用するパッケージ群を自動で同期**
2. **`Django`サーバーの立ち上げをhost制限なし(`0.0.0.0`)で実行**

これらを順番に実行するよう、`&&`で区切って記述しています。

`host`の制限に関しては後ほどdjangoの設定ファイルから行います。

```yml
working_dir: /code
```
13行目、**ワークディレクトリを指定**します。コンテナ内の`code`ディレクトリを指定します。このディレクトリは、[前回](https://qiita.com/toffe_hy/items/0429a95bfe1786955c2a)記述した`Dockerfile`の記述を元に作成されています。

```yml
ports: 
    - 127.0.0.1:8000:8000
```
14-15行目、**利用するポートを指定**します。左側`127.0.0.1:8000`がホストマシン側の`host`とポート、`:`で挟んで右側がコンテナ側のポートに関する記述です。ホストマシン側から`127.0.0.1:8000`に接続すると、コンテナ側で自動で割り振られた`host`の`8000`番に接続されます。指定するポートに関しては、先述の`command`内、`runserver`で指定するポートと一致させています。
(なお、今回の場合は後ほど`localhost`と`127.0.0.1`以外からの接続を弾くようDjango側から設定を行うため、`127.0.0.1`の記述は必須ではありません。)

```yml
volumes:
    - .:/code
```
16-17行目、**データのマウントについて指定**します。前項と同じく**`:`を挟んだ左側がホストのパス、右側がコンテナ側のパス**です。変更が同期され、左右が同じ内容を管理する状態を保持します。この項目は[他にもいろいろな記述の仕方がある ( 公式ドキュメント ) ](https://docs.docker.com/compose/compose-file/#volumes)ようで、自在に使いこなすのは難しそうです。

```yml
depends_on:
    - db
```
18-19行目、**サービスの依存関係を指定**します。**`web`を起動する際に、先に`db`も起動する**ということのようです。
起動順には[問題](https://qiita.com/toffe_hy/items/4b7d8c47c5a1a2defcac)が起こり得るのですが、とりあえずこれで`Django`アプリケーションのDBとして`MySQL`を利用できるようになります。


### MySQL側
続いて、`MySQL`のサービスに関する記述を考えていきます。

```yml
db:
```
20行目、MySQLの動かすサービスについての記述を開始します。先ほどと同様、これがイメージ名(の末尾)になります。

```yml
container_name: djst_mysql
```
21行目、コンテナ名を命名しています。

```yml
image: mysql:5.7
```
22行目、**どのイメージを元に作成するか**を指定しています。前述した`web`の項目とは違い、`Dockerfile`でのカスタマイズを行わず、公式に準備されているイメージをそのまま利用する場合、このような記述になります。
もちろん、別の`Dockerfile`をディレクトリを分けて作成しておけば、それを指定して利用することも可能です。

```yml
restart: always
```
23行目、**コンテナ停止時の再起動に関する設定**です。ここでは`always`に設定し、手動時をのぞき常に再起動させるようにしています。デフォルトは`"no"`で、`always`の他には`unless-stopped`と`on-failure`が選択できるようです。

```yml
environment: 
    MYSQL_DATABASE: $DB_NAME
    MYSQL_USER: $DB_USER
    MYSQL_PASSWORD: $DB_PASSWORD
    MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
    MYSQL_TCP_PORT: 3306
    TZ: 'Asia/Tokyo'
```
24-30行目は、**環境変数の設定**です。`$`のついているものは、`GitHub`などへ公開したくなった時のことも考え、後ほど作成する`.env`ファイルに記述しておきます。これらが、`Django`から接続するDBの情報になります。

`MYSQL_TCP_PORT`は、後ほど見る`ports`オプションと整合性を持たせる必要があります。ここではMySQLのデフォルト番号`3306`を指定しました。`TZ`は地域の設定です。

```yml
volumes: 
    - ./mysql/data:/var/lib/mysql/
    - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
```
31-33行目は、**データのマウント設定**です。これまでと同様、**`:`より左がホストで、右がコンテナ内のパスです。**

上行は、**永続化のためのマウント設定**です。アプリケーションが利用される過程でDBに保存された情報が、ホストの`./mysql/data`ディレクトリに同期されます。
下行は、**設定ファイルのマウント設定**です。言語設定などを記述した`./mysql/my.cnf`ファイルを準備しておけば、コンテナ側の`MySQL`の設定に反映されます。

他にも、コンテナ内の`/docker-entrypoint.init.d`ディレクトリ内にマウントする形でSQLファイルなどを用意しておけば、DBに初期データを投入することなどもできるようです。

```yml
ports: 
    - 3306:3306
```
最後に、**利用するポートの設定**です。先ほど記述した環境変数`MYSQL_TCP_PORT`と整合性を持たせればOKです。

## .envファイルの作成
環境変数を記述するための**`.env`ファイルを作成**します。こちらも同じ階層に配置します。

```txt:.env
DB_NAME=********
DB_USER=********
DB_PASSWORD=********
DB_ROOT_PASSWORD=********
```
記述内容は、先ほどの`docker-compose.yml`で記述した`environment`オプションに対応する**環境変数の定義**です。`*********`のところにお好みで記述してください。
`GitHub`などに公開する場合は、**このファイルは管理対象から外して**おきます。

## MySQL設定関連ファイルの作成
MySQLのマウント用ディレクトリ`./mysql`を作成し、その中に設定ファイル`my.cnf`を配置します。

```config:mysql/my.cnf
[mysqld]
character-set-server=utf8mb4

[client]
default-character-set=utf8mb4
```
最初から変更しておきたい変数を予めこちらに記入しておきます。

DBのデータのマウント先に指定した`./mysql/data/`は、`$ docker-compose up`実行時に自動で生成されます。こちらは`GitHub`などに**公開する場合はあらかじめ管理対象から外して**おきます。

## 現時点でのディレクトリ構成
```shell
django_starter
    ├── .venv
    │   └── (略)
    ├── config
    │     ├── __init__.py
    │     ├── asgi.py
    │     ├── settings.py
    │     ├── urls.py
    │     └── wsgi.py
    ├── mysql                 <- New!
    │     └── my.cnf
    ├── .env                  <- New!
    ├── docker-compose.yml    <- New!
    ├── Dockerfile
    ├── manage.py
    └── requirements.txt
```

## 終わりに
これで、`Django`+`MySQL`環境を構築するための`docker-compose.yml`を作成することができました。

今回、それぞれのオプションの意味を理解しようと色々と調べてみて、`Docker`についてはもちろん、`MySQL`や`Django`などの**「扱いたい技術」そのものに対する知識を深めれば深めるほどもっと色々なことが自由にできそう**だと改めて感じたので、そちらも含めて引き続き学習を続けていきたいと思いました。

次回は**Djangoの設定ファイルを編集**し、**`$ docker-compose up`コマンドを実行**するまでを考えていきます。
次の記事はこちら↓
「 4. [設定ファイルを編集し docker-compose up を実行する](https://qiita.com/toffe_hy/items/0571b84faa3e6b834c6e) 」


ご覧いただきありがとうございました。