Dockerコンテナ構築手順② Docker Compose編

## 概要
Dockerハンズオン勉強会資料(初級者向け)続き

## Docker Composeとは
Dockerfileでコンテナの構築手順を省略できましたが、Dockerfileを使っても、
コンテナの設定を一部変更して再構築する際は一度コンテナの停止・削除、イメージの削除をしなければいけません。
さらに依存関係のある複数のコンテナを構築する時はコンテナの数だけ、ビルドと起動のコマンドを実行する必要があります。

こういった複数コンテナの構築の手順も設定ファイルにし、まとめて管理するのが***Docker Compose***です。
また、Docker Composeでは変更あったコンテナのみ再構築してくれます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/839e892a-a20f-d89a-1d17-0864cb454fcb.png)

---

## Docker Compose利用の流れ
Docker Composeを利用する際の基本の流れは以下になります。
**１．Dockerfileを用意する(コンテナのカスタムが必要な場合)
２．Composeファイル(複数コンテナの設定をまとめたファイル)を用意する
３．Docker Composeコマンドでまとめて構築**

---

## Composeファイル

### ComposeファイルはYAML
Composeファイルを書くためにまずはYAMLについて知る必要があります。  
:point_down: YAMLの基本文法
https://qiita.com/aminosan000/private/168e735d26fffdbaef52

---

#### Composeファイルに記述する基本的な属性
- **version**：Composeファイルの文法バージョン

```yaml
version: "1.0~3.7の数字"
# 小数点以下は省略化
```

- **services**：コンテナの設定の一覧

```yaml
services:
  # Composeファイルの中での定義名(コンテナ名とは別)
  contena_01:
    <contena_01の設定内容>
  contena_02:
    <contena_01の設定内容>
```

---

- **build**：Dockerfileのディレクトリパス(Dockerfileからのビルド時のみ必要)

```yaml
services:
  contena_01:
    build: <ディレクトリパス>
```

- **image**：元になるイメージ
※Dockerfileからのビルド時はビルドしたイメージにつける名前

```yaml
services:
  contena_01:
    image: <イメージ名[:タグ]>
```

---

- **ports**：コンテナの公開ポート指定

```yaml
services:
  contena_01:
    ports: <ホスト側ポート:コンテナ側ポート>
```

- **container_name**：コンテナの名前

```yaml
services:
  contena_01:
    container_name: <コンテナ名>
```
※その他書き方(公式リファレンス): http://docs.docker.jp/compose/compose-file.html

---

## Docker Composeの基本コマンド
Docker Composeの操作は以下のコマンドで行います。

```bash
> docker-compose [オプション] [サブコマンド] [引数...]
# Example
> docker-compose -f my-compose.yml start
```

|よく使うオプション|意味|
|:--:|:--:|
|-f|Composeファイルのパスを指定<br>(指定なしの場合、カレントの"docker-compose.yml")|

---

## Docker Composeのサブコマンド

- **ps**：Composeファイルで定義されているコンテナ全ての状態を確認

```bash
> docker-compose ps [オプション]
# Example
> docker-compose ps
```

- **build**：Dockerfileから構築するイメージの構築のみ行う

```bash
> docker-compose build [オプション]
# Example
> docker-compose build
```

---

- **up**：Composeファイルで定義されている全てのコンテナを作成し起動する

```bash
> docker-compose up [オプション]
# Example
> docker-compose up --build -d
```
|よく使うオプション|意味|
|:--:|:--:|
|-d|バックグラウンドでコンテナを実行|
|--build|コンテナを開始前にイメージを構築する<br>(変更があった場合のみ)|

---

- **down**：Composeファイルで定義されている全てのコンテナを停止し削除する

```bash
> docker-compose down [オプション]
# Example
> docker-compose down --rmi all
```
|よく使うオプション|意味|
|:--:|:--:|
|--rmi|'all'を指定するとイメージも全て削除|

---

- **start**：Composeファイルで定義されているコンテナ全てを起動

```bash
> docker-compose start [オプション]
# Example
> docker-compose start
```

- **stop**：Composeファイルで定義されているコンテナ全てを停止

```bash
> docker-compose stop [オプション]
# Example
> docker-compose stop
```

---

- **rm**：Composeファイルで定義されているコンテナ全てを削除

```bash
> docker-compose rm [オプション]
# Example
> docker-compose rm
```

その他のコマンド(公式リファレンス): http://docs.docker.jp/compose/reference/

---

## Docker Composeでコンテナを構築する
前の手順で構築したコンテナと同じものをDocker Composeで作ってみましょう。

１. 前の手順で作ったコンテナとイメージの削除
※ Docker Composeで作っていないので、Docker Composeでupdateできないため

```bash
> docker stop pyweb
> docker rm pyweb
> docker rmi web/python:1.0
```

---

２. Composeファイルを作成
>C:¥Users¥USERNAME
>　　├ docker-compose.yml　:point_left: これ
>　　└ dockerdir
>　　　　 ├ Dockerfile
>　　　　 └ index.html

```yaml:docker-compose.yml
version: "3"
services:
  pyweb:
    build: dockerdir
    image: web/python:1.0
    ports:
      - 5000:80
    container_name: pyweb
```

---

２. コンテナの構築 + 起動

```bash
> docker-compose up --build -d
```

これだけでイメージを再ビルドし、コンテナが既に存在しイメージとの差分があった場合のみコンテナを再作成もしてくれます。
`localhost:5000`でDockerfileのみの時と同じものが表示されればOK

---

## 複数コンテナの一括管理
コンテナが一つだけだと、Docker Composeを使う意味があまりないので、他のコンテナも追加してみましょう。
Apacheのコンテナを追加する場合、下記のようになります。

１. Composeファイルを修正
>C:¥Users¥USERNAME
>　　├ docker-compose.yml　:point_left: これ
>　　└ dockerdir
>　　　　 ├ Dockerfile
>　　　　 └ index.html

---

```yaml:docker-compose.yml
version: "3"
services:
  pyweb:
    build: dockerdir
    image: web/python:1.0
    ports:
      - 5000:80
    container_name: pyweb
  httpd:
    image: httpd:alpine
    ports:
      - 8080:80
    container_name: httpd
```

---

２. コンテナの構築 + 起動

```bash
> docker-compose up --build -d
```

３. 動作確認
`localhost:5000`と`localhost:8080`でそれぞれのページが表示されればOK

---

## コンテナ同士の通信
複数のコンテナを扱う場合、コンテナ同士の連携が必要な場合が多いかと思います。
(WebサーバからDBサーバへのアクセス等)
Dockerにはネットワーク機能があり、1つのComposeファイルで作成したコンテナはデフォルトだと全て「{Composeファイルのあるディレクトリ名}_default」という名前のネットワーク内に入ります。
同一ネットワーク内なので相互通信が可能ですが、Composeファイルで指定をしないとサブネットとIPは自動で割り振られてしまいます。
なので、IPアドレスの代わりにサービス名でアクセスします。
MySQLのコンテナを2つ用意して、クライアントとサーバとして相互に通信してみましょう。

:point_down: Dockerのネットワークについて参考になる記事
https://qiita.com/zembutsu/items/1da05cb6a60e1c5acc25

---

１. Composeファイルを修正
>C:¥Users¥USERNAME
>　　├ docker-compose.yml　:point_left: これ
>　　└ dockerdir
>　　　　 ├ Dockerfile
>　　　　 └ index.html

```yaml:docker-compose.yml
version: "3"
services:
  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
  mariadb:
    image: mariadb
    container_name: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: root
```

---

２. コンテナの構築 + 起動

```bash
> docker-compose up --build -d
```

---

３. mysqlコンテナをクライアントにして、mariadbコンテナへ接続

```bash
# mysqlコンテナのBashを実行
C:¥Users¥USERNAME> docker exec -it mysql bash
# MySQLでmariadbコンテナへ接続
root@178cad03cf09:/# mysql -h mariadb -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.5.5-10.3.15-MariaDB-1:10.3.15+maria~bionic mariadb.org binary distribution

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```
接続できればOK(Server versionがMariaDBになっている)

---

## Previous
Dockerコンテナ構築手順① Dockerfile編:
https://qiita.com/aminosan000/private/ef8778cbd880aa6e655c