Docker Composeで手軽に開発環境を構築  (すっきりPHPなど）

[Docker Composeで手軽に開発環境を構築（PHP+MySQL+Elasticsearch+Memcached）](http://qiita.com/acro5piano/items/1d907f81afd0fb3a199e)で紹介したファイル群をリファクタリングしました。記事にする前にリファクタリングしろよっていう話ですが・・・。

DockerやDocker Composeについての基本的な記事は、上記をご覧いただければ幸いです。

今回作成したファイル群は、こちらに置いてあります。

https://github.com/acro5piano/docker-compose-dev-env

docker-composeが入っていれば、

```bash
git clone https://github.com/acro5piano/docker-compose-dev-env.git
cd docker-compose-dev-env
docker-compose up
```

とすると

- 各コンテナが起動
- <localhost:3000>にPHPのビルトインサーバーが起動
- MySQLとの接続テストに成功

するはずです。

このファイル群を作るまでの流れを書いていきます。

# ファイル構成

```txt:tree
.
|-- docker
|   |-- web
|   |   `-- Dockerfile
|   `-- db
|       |-- Dockerfile
|       `-- my.cnf
|-- docker-compose.yml
|-- index.php
`-- README.md
```

[Rocker.Chat](https://github.com/RocketChat/Rocket.Chat)を参考にしました。

プロジェクトのルートディレクトリに`docker`ディレクトリがあり、全てのdockerコンテナ用のファイルがここに収まっているので、かなりすっきりした気がします。

Docker Composeだけで構築して、Dockerfileは書かないという方法を模索しましたが、素のPHPでは`MySQLi`が入っておらず、また公式で`php-mysql`を探しても無かったので、結局書きました。

# 各ファイルの説明

## docker-compose.yml

```yaml:docker-compose.yml
version: "2"
services:
  web:
    build: ./docker/web
    ports:
      - "3000:3000"
    links:
      - db
      - memcached
      - elasticsearch
    volumes:
      - ./:/code
    working_dir: /code
    command: php -S 0.0.0.0:3000
    container_name: some-web

  db:
    image: "mysql:5.7"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app
      MYSQL_HOST: ""
      # If you want to set mysql user manually, remove these comments:
      #MYSQL_USER: user
      #MYSQL_PASSWORD: password
    mem_limit: 1000000000
    container_name: some-db

  elasticsearch:
    image: "elasticsearch:2.4"
    container_name: some-elasticsearch

  memcached:
    image: "memcached:1.4"
    container_name: some-memcached
```

| 項目           | 説明                                                                                 |
|----------------+--------------------------------------------------------------------------------------|
| build          | コンテナの作成をするワークスペースの指定。Dockerfileがある場所                       |
| image          | ベースイメージ。`build`とは排反                      |
| ports          | ホスト側のポートとコンテナ側のポートのマッピング                                     |
| links          | コンテナ間の通信を定義。実際は/etc/hostsにコンテナ名とIPアドレスの名前解決が書かれる |
| volumes        | ホストとコンテナで共有するディレクトリ                                               |
| environment    | 環境変数                                                                             |
| command        | コンテナ起動時に実行するコマンド。Dockerfileで既存のものを上書きする                             |
| working_dir    | コンテナでコマンドを実行する時のカレントディレクトリ                                 |
| container_name | コンテナの名前。`docker exec -it`などでコンテナを指定する時に使える                                |

Dockerが使うホスト側のポートは、最小限にした方が良いです。ホスト側からコンテナに任意のコマンドを実行できるので、それでも困りません（後述）。そのうち欲が出てDockerコンテナを複数動かしたくなった時に修正が面倒というのもあります。
今回は3000番だけ開放しています。

## docker/web/Dockerfile

```bash:docker/web/Dockerfile
FROM php:7.0

RUN apt-get update
RUN apt-get install -y zlib1g-dev libjpeg-dev libpng-dev libfreetype6-dev

RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/
RUN docker-php-ext-install gd
RUN docker-php-ext-install mysqli
```

Apacheをインストールしていないので、設定ファイル類が無くて済みます。またDocker公式のPHPイメージを利用して、記述量を減らしています。

PHPのビルトインサーバーは、Dockerコンテナ内でrootユーザーにより実行されます。これは開発時には権限設定などをほぼ考えなくて良いので、便利です。もちろん本番では厳密に設定する必要がありますが。

# コンテナを起動する

これらのファイルができたら、あとは`docker-compose.yml`のあるディレクトリで`docker-compose up`すれば各コンテナが起動します。

# よく使うコマンドまとめ

## webコンテナにログイン

`docker exec -it some-web bash`

コンテナ間ポートフォワーディング等をしない限り、`sshd`を入れる必要は無いです。

このコマンドですが、任意のコマンドが実行できるので、
`docker exec -it some-web cat /etc/hosts`
とかしてみると面白いかもしれません。

ここでのsome-webというのは、`docker-compose.yml`で設定したコンテナ名です。

`docker-compose exec web bash`でも構いません。

## mysqlコンソールにログイン

`docker exec -it some-db mysql -u root -proot -D app`

※アプリケーションがDocker内のMySQLに接続するのに使うユーザーは、なるべくrootにした方が楽かと思います。

## 作成したコンテナを消す

`docker-compose down`

MySQLのみ、データが永続化されないようになっていますので、このコマンドで影響を受けるのはMySQLコンテナだけです。

※基本的にDockerコンテナ内のデータは永続化されません。