WindowsでDocker Composeを使ってマルチコンテナ環境を作ってみる

# 概要

Windows10にDocker環境を構築したのでいろいろ試してみた
今回はWEBサーバ／APサーバ／DBサーバなど一度に複数のコンテナが必要になるWebシステム等の構築時に使用するコンテナ構成情報一元管理ツール「Docker Compose」
「Docker Compose」のコンテナ構成情報を定義するdocker-compose.ymlの書き方とそのまとめ

Dockerとdocker-compose.ymlの関連は以下を参照

　[Dockerの基本機能と全体像のイメージを整理してみる](https://qiita.com/fkooo/items/934c7b6f1f0c0e8d1b21 "Dockerの基本機能と全体像のイメージを整理してみる")

動作環境とDocker環境構築方法は以下を参照

* Windows 10 Pro 64bit
* Docker for Windows

　[WindowsでDocker環境を試してみる](https://qiita.com/fkooo/items/d2fddef9091b906675ca "WindowsでDocker環境を試してみる")

「Docker Compose」はDocker for Windowsのインストールで同時にインストールされる

## およその作業時間

1時間

## 参考書籍

[プログラマのためのDocker教科書](https://amzn.to/32laoJw "プログラマのためのDocker教科書")　第6章
<a target="_blank"  href="https://www.amazon.co.jp/gp/product/4798153222/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4798153222&linkCode=as2&tag=docker_start_007-22&linkId=bf3a2362fd2a7a258c05bb4d99a608c2"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=4798153222&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL110_&tag=docker_start_007-22" ></a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=docker_start_007-22&l=am2&o=9&a=4798153222" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
わかりやすくてDockerの入門書的な良本です^^
みんな購入していて売れ行き好調なのか第2版が発売されていたのでリンク更新

[【Kindle版】プログラマのためのDocker教科書](https://amzn.to/3l6wLdh "【Kindle版】プログラマのためのDocker教科書")
<a target="_blank"  href="https://www.amazon.co.jp/gp/product/B07BHK5KX7/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B07BHK5KX7&linkCode=as2&tag=docker_start_007-22&linkId=45db0f86fc7a2ffbd1f71edfaa5e9d8d"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=B07BHK5KX7&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL110_&tag=docker_start_007-22" ></a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=docker_start_007-22&l=am2&o=9&a=B07BHK5KX7" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

## 使用コマンド一覧

```docker
docker run --link 接続したいコンテナ名：エイリアス名 イメージ名 実行コマンド
docker-compose up
docker-compose scale コンテナ名=数
docker-compose ps
docker-compose logs
docker-compose run コンテナ名 実行コマンド
docker-compose start
docker-compose stop
docker-compose restart
docker-compose kill
docker-compose rm
```


## docker-compose.yml定義一覧

```yaml
image イメージ名
build ファイルパス
command 実行コマンド
links／external_links コンテナ名:エイリアス名
ports／expose "ポート番号"
volumes マウントポイント
volumes_from マウント先のコンテナ名
environment 環境変数名=値
container_name コンテナ名
labels ラベル内容
```


## YAML形式の基本的なdocker-compose.ymlの書き方

* インデント（半角スペース）でデータ階層構造を表す
* #はコメントになる
* 配列を使用するときは先頭「- 」（ハイフンと半角スペース）に続き定義内容を記載する
* インデントなしの行の先頭に定義するコンテナの種類ごとにコンテナ名を指定する

## image イメージ名

ベースイメージを指定する
dockerコマンド等と同様 : に続きタグ指定も可能（タグの省略で最新イメージの指定となる）

```yaml:docker-compose.yml
testserver:
 image: ubuntu
```

testserverが生成するコンテナ名

## build ファイルパス

イメージ作成にDockerfileを使用する場合は、buildに続きDockerfileが置かれているファイルパスを指定する

```yaml:docker-compose.yml
testserver:
 build: .
```

docker-compose.ymlファイルでは、image／buildのいずれかの指定が必要
build(Dockerfile)を使用する場合は、一度イメージを作成しコンテナを作成することになる

## command 実行コマンド

コマンド実行を行う場合はコマンドを指定する
DockerfileにCMD指定がある場合は上書きされる

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 command: /bin/bash
```

## links／external_links コンテナ名:エイリアス名

指定したコンテナに対し容易にアクセス可能なように環境変数にIPアドレスなどを自動的に設定して、コンテナ名やエイリアス名でアクセスできるようになる機能（リンク機能）

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 links:
  - dbserver:mysql
```

links指定は同一のdocker-compose.ymlに定義があるコンテナのみ指定可能であることに対し、external_linksは外部の別のコンテナとリンク機能を使って連携するときに指定する
docker-compose.ymlを使用しない場合は、以下のコマンドでdocker run時にもリンク機能の指定が可能

## docker run --link 接続したいコンテナ名：エイリアス名 イメージ名 実行コマンド

引数で指定したコンテナに対し環境変数に自動的に設定してくれる
ただし、同一ホストマシン上で起動しているコンテナ間でしか、アクセスできないという制限がある

## ports／expose "ポート番号"

コンテナの公開するポート指定に使用する
「ホストマシンのポート番号:コンテナのポート番号」の形式でホストマシンのポートを明示的に指定することもできるが、記載がなければランダムなポートが使用される
必ず""（ダブルクォート）で囲む必要がある

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 ports:
  - "80:80"
```

ホストマシンには公開せず、リンク機能を使って連携するコンテナにのみポートを公開する場合は、expose指定となる
その場合は、ホストマシンのポート番号は省略する

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 expose:
  - "8000"
```

## volumes マウントポイント

ボリュームをマウントする場合に使用する
ホスト側でマウントするパスを指定する場合は、「ホストマシンのフォルダパス:コンテナのフォルダパス」の形式で指定する

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 volumes:
  - /var/lib/mysql
```

## volumes_from マウント先のコンテナ名

特定のコンテナに対しボリュームをマウントする場合に使用する

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 volumes_from:
  - dataserver
```

## environment 環境変数名=値

環境変数を指定する場合に使用する

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 environment:
  - HOGE=hoge
```

## container_name コンテナ名

生成されるコンテナに名前を付けるときに使用する

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 container_name: webserver
```

## labels ラベル内容

コンテナにラベルを付けるときに使用する

```yaml:docker-compose.yml
testserver:
 image: ubuntu

 labels:
  - "description=testserver"
```

## docker-compose.ymlを使いコンテナ生成を行うdocker-composeコマンド

## docker-compose up

docker-compose.ymlを使って複数のコンテナの生成／起動を行う

-f でdocker-compose.ymlのファイル指定が可能
-f がなければカレントにあるdocker-compose.ymlを使う
-d でバックグラウンド起動する

```docker
> docker-compose -f webdb-docker-compose.yml up -d
Creating wordpress_dbserver_1 ...
Creating wordpress_dbserver_1 ... done
Creating wordpress_webserver_1 ...
Creating wordpress_webserver_1 ... done
```

```yaml:webdb-docker-compose.yml
webserver:
 image: wordpress
 ports:
  - "80:80"
 links:
  - dbserver:mysql

dbserver:
 image: mysql
 environment:
  MYSQL_ROOT_PASSWORD: password
```

コンテナ起動を確認

```docker
> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES
d9c5c3b521a5        wordpress           "docker-entrypoint..."   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp   wordpress_webserver_1
f02a94dcee33        mysql               "docker-entrypoint..."   About a minute ago   Up About a minute   3306/tcp             wordpress_dbserver_1
```

コンテナ名は正確には「実行フォルダ\_docker-compose.ymlのコンテナ名\_通番」なるらしい
そのためdocker-compose.yml記載のコンテナ名はサービス名と言われる

## docker-compose scale コンテナ名=数

起動コンテナ数を指定する時に使用する

```docker
> docker-compose scale webserver=1 dbserver=2
WARNING: The scale command is deprecated. Use the up command with the --scale flag instead.
Creating wordpress_webserver_1 ...
Creating wordpress_webserver_1 ... done
Creating wordpress_dbserver_1 ...
Creating wordpress_dbserver_2 ...
Creating wordpress_dbserver_1 ... done
Creating wordpress_dbserver_2 ... done
```

複数起動時に矛盾が発生する場合はエラーが発生する
例えばwebserverを2つ起動する場合は80ポートが競合する、、、

```docker
> docker-compose scale webserver=2 dbserver=1
WARNING: The scale command is deprecated. Use the up command with the --scale flag instead.
WARNING: The "webserver" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating wordpress_webserver_1 ...
Creating wordpress_webserver_2 ...
Creating wordpress_webserver_1 ... error
Creating wordpress_webserver_2 ... done

ERROR: for wordpress_webserver_1  Cannot start service webserver: driver failed programming external connectivity on endpoint wordpress_webserver_1 (e1a6f29e4ec9f31c40b5470cf9109c98765c5a7e03a10013758063beb54b8436): Bind for 0.0.0.0:80 failed: port is already allocated
ERROR: Cannot start service webserver: driver failed programming external connectivity on endpoint wordpress_webserver_1 (e1a6f29e4ec9f31c40b5470cf9109c98765c5a7e03a10013758063beb54b8436): Bind for 0.0.0.0:80 failed: port is already allocated
```

## docker-compose ps

複数コンテナの一覧表示を行う
docker psコマンドと比較すると気持ちシンプル表示になっている？

```docker
> docker-compose ps
        Name                       Command               State         Ports
-----------------------------------------------------------------------------------
wordpress_dbserver_1    docker-entrypoint.sh mysqld      Up      3306/tcp
wordpress_dbserver_2    docker-entrypoint.sh mysqld      Up      3306/tcp
wordpress_webserver_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:80->80/tcp

> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
d9f2dec9af02        mysql               "docker-entrypoint..."   5 minutes ago       Up 5 minutes        3306/tcp             wordpress_dbserver_1
cde58d78dc3d        mysql               "docker-entrypoint..."   5 minutes ago       Up 5 minutes        3306/tcp             wordpress_dbserver_2
816fcbe2c4f7        wordpress           "docker-entrypoint..."   5 minutes ago       Up 5 minutes        0.0.0.0:80->80/tcp   wordpress_webserver_1
```

## docker-compose logs

コンテナのログを確認する場合に使用する
コンテナごとのログが表示される

```docker
> docker-compose logs
Attaching to wordpress_dbserver_1, wordpress_dbserver_2, wordpress_webserver_1
webserver_1  | WordPress not found in /var/www/html - copying now...
webserver_1  | Complete! WordPress has been successfully copied to /var/www/html
dbserver_1   | Initializing database
webserver_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
dbserver_2   | Initializing database
dbserver_1   | 2018-01-27T02:09:56.866053Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
webserver_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
dbserver_2   | 2018-01-27T02:09:56.887342Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
～～～省略～～～
```

## docker-compose run コンテナ名 実行コマンド

起動したコンテナに新たにコマンドを実行する場合に使用する
runのあとにコンテナ名を指定すると指定したコンテナだけの操作となる（他のコマンドでも同様）
コンテナ内でコマンド実行したい場合など/bin/bashを実行する

```docker
> docker-compose run webserver /bin/bash
Starting wordpress_dbserver_1 ... done
Starting wordpress_dbserver_2 ... done
root@8271d38f7036:/var/www/html#
```

## docker-compose start

複数のコンテナを一括で起動する場合に使用する

```docker
> docker-compose start
Starting dbserver  ... done
Starting webserver ... done

> docker-compose ps
        Name                       Command               State         Ports
-----------------------------------------------------------------------------------
wordpress_dbserver_1    docker-entrypoint.sh mysqld      Up      3306/tcp
wordpress_dbserver_2    docker-entrypoint.sh mysqld      Up      3306/tcp
wordpress_webserver_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:80->80/tcp
```

## docker-compose stop

複数のコンテナを一括で停止する場合に使用する

```docker
> docker-compose stop
Stopping wordpress_dbserver_1  ... done
Stopping wordpress_dbserver_2  ... done
Stopping wordpress_webserver_1 ... done
```

## docker-compose restart

複数のコンテナを一括で再起動する場合に使用する

```docker
> docker-compose restart
Restarting wordpress_dbserver_1  ... done
Restarting wordpress_dbserver_2  ... done
Restarting wordpress_webserver_1 ... done
```
 
## docker-compose kill

複数のコンテナを一括で強制停止する場合に使用する

```docker
> docker-compose kill
Killing wordpress_dbserver_1  ... done
Killing wordpress_dbserver_2  ... done
Killing wordpress_webserver_1 ... done

> docker-compose ps
        Name                       Command                State     Ports
-------------------------------------------------------------------------
wordpress_dbserver_1    docker-entrypoint.sh mysqld      Exit 137
wordpress_dbserver_2    docker-entrypoint.sh mysqld      Exit 137
wordpress_webserver_1   docker-entrypoint.sh apach ...   Exit 137
```

## docker-compose rm

複数のコンテナを一括で削除する場合に使用する

```docker
> docker-compose rm
Going to remove wordpress_dbserver_1, wordpress_dbserver_2, wordpress_webserver_1
Are you sure? [yN] y
Removing wordpress_dbserver_1      ... done
Removing wordpress_dbserver_2      ... done
Removing wordpress_webserver_1     ... done
```