開発環境向けミドルウェア複数バージョン管理としてのDocker

対象
----------

複数の案件を掛け持ちしつつ、開発環境はローカルのMacなどで開発し、複数バージョンのミドルウェアを混在させたい方には有用かもしれません。
僕の場合は複数のRailsアプリケーションを扱っていますが、DBのMySQLのバージョンが微妙に5.5のものから5.6のものなど複数あり、とりあえずローカルは5.6をいれて共有して使っていましたが、最新の5.7が使えないことや本番とバージョンが異なっていることを解消したくDockerで複数バージョン管理することにしました。

事前準備
----------

## ツールのインストール

* [Vartualbox](https://www.virtualbox.org/)
適当に最新版入れてください。(試した環境は　5.1.2 r108956)

* `docker` と `docker-machine`
[Docker Toolbox](https://www.docker.com/products/docker-toolbox) をインストールするか、 homebrewなどで個別に `docker` と `docker-machine` をインストールしてもいいです。


docker-machineでホスト用のマシンを起動
----------

docker-machineはdockerのコンテナを起動させるためのVirtualboxのホストを操作するツールとなります。（`--driver` で他のドライバを指定することでVirtualboxではなくvmwareなども利用可能です。 [サポートドライバ](https://docs.docker.com/v1.11/machine/drivers/)）

```shell-session:devという名前のdockerホストを作成
$ docker-machine create --driver virtualbox dev
```

```sh:dockerホストの作成確認
$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
dev       *        virtualbox   Running   tcp://192.168.99.100:2376           v1.11.2
```

これにより、Virtualboxに dev という名前でインスタンスができます。


docker-machineを経由してdockerを利用
----------

### env を設定して `docker` コマンドを利用できるようになります。
以下のコマンドを打つことで、開いているターミナルのシェル上で、 `docker` コマンドを打つと `docker-machine` で動作しているDockerホストで操作している状態となります。

```sh:環境設定
$ eval $(docker-machine env dev)
```

```sh:以下の様なdockerコマンドをMac上で打つとDockerホスト上で実行される
$ docker ps
$ docker images
```

dockerで ミドルウェアごとの公式イメージを run してコンテナを起動します
-------------

MySQL, Redis, Postgres を複数バージョン管理するための記述を以下に記載していきます。

### MySQLコンテナを管理

[https://hub.docker.com/_/mysql/](https://hub.docker.com/_/mysql/)  
以下の各 `docker run` コマンドのオプションを見てもらうとわかるように、明示的に起動するときにマッピングするポートをを変えることで複数のバージョンにアクセスできるようにしています。

#### MySQL5.6

以下のコマンドでMySQL5.6のコンテナを mysql56 という名前で立ち上げられます。
ポートを `３３５６` に マッピングし ボリューム を `/var/lib/docker/mysql56` にマッピングします。

```sh:mysql5.6のイメージを取得してコンテナ起動する
docker run --name mysql56 -v /var/lib/docker/mysql56:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password -p 3356:3306 -d mysql:5.6 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
```

```sh:接続方法
mysql -uroot -h$(docker-machine ip dev) -p -P3356

パスワードに password と入力します。
```

#### MySQL5.7
以下のコマンドでMySQL5.7のコンテナを mysql57 という名前で立ち上げます。
ポートを `３３５7` に マッピングし ボリューム を `/var/lib/docker/mysql57` にマッピングします。

```sh:mysql5.7のイメージを取得してコンテナを起動する
docker run --name mysql57 -v /var/lib/docker/mysql57:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password -p 3357:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
```

```sh:接続方法
mysql -uroot -h$(docker-machine ip dev) -p -P3357

パスワードに password と入力します。
```

#### dockerコマンドの使い方

* 個別にコンテナを止めたいときは、以下を実行します。
  `$ docker stop mysql56`

* 個別でコンテナを起動させたい時は、以下を実行します。
  `$ docker start mysql56`

コンテナは作成済みで、コンテナだけを個別に起動したり、停止するときによく使います。（主に2回目以降ですでに `docker run` や `docker create` でコンテナを作成したあとに使います。

### Redisコンテナを管理

[https://hub.docker.com/_/redis/](https://hub.docker.com/_/redis/)

#### redis3.0

ポートを `6330` に マッピングし ボリューム を `/var/lib/docker/redis30` にマッピングします。

```sh:redis3.0のイメージを取得してコンテナを起動する
docker run --name redis30 -v /var/lib/docker/redis30:/data -p 6330:6379 -d redis:3.0
```

```sh:接続方法
redis-cli -h $(docker-machine ip dev) -p 6330
```

#### redis3.2

ポートを `6332` に マッピングし ボリューム を `/var/lib/docker/redis32` にマッピングします。

```sh:redis3.0のイメージを取得してコンテナを起動する
docker run --name redis32 -v /var/lib/docker/redis32:/data -p 6332:6379 -d redis:3.2
```

```sh:接続方法
redis-cli -h $(docker-machine ip dev) -p 6332
```

### Postgresコンテナを管理

[https://hub.docker.com/_/postgres/](https://hub.docker.com/_/postgres/)

#### postgres9.4

ポートを `5494` に マッピングし ボリューム を `/var/lib/docker/postgres94` にマッピングします。

```sh:postgres9.4のイメージを取得してコンテナを起動する
docker run --name postgres94 -e POSTGRES_PASSWORD=password -v /var/lib/docker/postgres94:/var/lib/postgresql/data -p 5494:5432 -d postgres:9.4

パスワードに　password　と入力します。
```

```sh:接続方法
psql -U postgres -h $(docker-machine ip dev) -p 5494
```

#### postgres9.5

ポートを `5495` に マッピングし ボリューム を `/var/lib/docker/postgres95` にマッピングします。

```sh:postgres9.5のイメージを取得してコンテナを起動する
docker run --name postgres95 -e POSTGRES_PASSWORD=password -v /var/lib/docker/postgres95:/var/lib/postgresql/data -p 5495:5432 -d postgres:9.5
```

```sh:接続方法
psql -U postgres -h $(docker-machine ip dev) -p 5495

パスワードに　password　と入力します。
```

補足
--------

### 補足1) 上記のように設定したdocker上で Railsを使った場合の `database.yml` の指定方法

```config/database.yml(mysql5.6のDBを利用する場合)
development:
  adapter:   mysql2
  encoding:  utf8
  charset:   utf8
  collation: utf8_general_ci
  pool:      5
  username:  root
  password:  password
  host:      <%= `docker-machine ip dev` %>
  port:      3356
  database:  db_development
```


### 補足2) VOLUME の共有に `/var/lib/docker/` を使っている理由

各環境の設定において　`docker run` するときに必ず　 `-v /var/lib/docker/xxxxx:path/to/dir` のような設定があったと思いますが、データを永続化するために指定しています。

docker-machineのOS（Dockerホスト)は `/` のマウントポイントは　`tempfs` でフォーマットされているため、 `docker-machine` を停止してしまうと、基本的にはデータが消えてしまいます。
それを防ぐため、 `/var/lib/docker` と `/var/lib/boot2docker` 以下にデータディレクトリを共有しておけば永続化されるので指定しています。
詳しくは以下も合わせてご参照ください。

* [Docker MachineでDドライブなどUsers以外を自動マウントする - Qiita](http://qiita.com/Bakudankun/items/d612865440565b10523f)
* https://github.com/boot2docker/boot2docker/blob/851479ce9d07c384880ed9061297d76cacbb4dad/doc/FAQ.md#local-customisation-with-persistent-partition