そろそろ、自分のdocker-compose.yml周りを公開

docker便利ですね。
最近そんなことばかりしか言ってない気がします。
自分がdockerを使い始めた頃は、dockerってなんなのかわからない人が多く
話すと便利そうだけどプロダクションで使う想像がつかないとか
環境がめんど臭いとか
色々言われていました。

今現在は、開発環境として使うのであれば
docker for macというのがあって、これ入れるだけでかなり簡単にdockerが試せるようになりました。
環境を作るのが簡単になったのであれば、使えるdockerfileとかdocker-compose.ymlとかも
そろそろテンプレ的な何かがあった方が良いかな、と思い
今自分の手元でよく使っている構成でdocker-compose.ymlを公開してみます。

# 構成の検討

まずは、作りたい環境の構成ですが

サーバサイドとしてRuby on Railsを使うことが多いので、Ruby on Railsを立ち上げる
という前提で行きます。

必要なコンテナとしては

* Ruby on Railsが動くコンテナ  
  このコンテナの中には  
  /productsというディレクトリを作って、この中にRuby on Railsのプロジェクトを置くようにします。

* mysqlが動くコンテナ

この二つが最低限なので、この構成を作って行きます。

# 下準備

まずは手元にRuby on Railsのプロジェクトを適当に作ります。

```
rails new docker-compose-template
```

docker-compose-templateの中に入ってDockerのファイルを作って行きます。

# Dockerで作る環境の構成

主な構成ですが、プロジェクトのファイル以外に以下のようなファイルが追加になります。

```
docker-compose-template
┣Dockerfiles
┃┗mysql
┃　┣conf.d
┃　┃┗default.cnf
┃　┗docker-entrypoint-initdb.d
┃　　┗init-user-db.sh
┣Dockerfile
┣docker-compose.yml
┗entrypoint.yml
```

以下、それぞれのファイルについて中身とその解説をして行きます。

### Dockerfile

```docker
# 本体
#
# VERSION               0.0.1

FROM      gendosu/ruby-for-rails:2.3

MAINTAINER Gen Takahashi "gendosu@gmail.com"

ADD . /products
WORKDIR /products

RUN chmod a+x /products/entrypoint.sh
RUN ./entrypoint.sh

ENTRYPOINT ["./entrypoint.sh"]
```

FROMのベースになるイメージは、officialのrubyにRuby on Railsで良く使うパッケージを追加したものを使用しています。

あと、特徴は

entrypoint.shという物を作成しており、ここで毎回コンテナ起動するたびに実行したい処理などを入れておきます。

### entrypoint.sh

```bash
#!/bin/bash
set -e

bundle

rake db:migrate
# rake db:seed

if [ -e /products/tmp/pids/*.pid ]; then rm /products/tmp/pids/*.pid; fi

exec "$@"
```

bundle、db:migrate、pidファイル削除などを毎回起動時に行う

### Dockerfiles/mysql/conf.d/default.cnf

```
[client]
socket=/var/run/mysqld/mysqld.sock

[mysql]
max_allowed_packet=16M
socket=/var/run/mysqld/mysqld.sock

[mysqld]
character-set-server = utf8
max_allowed_packet=16M
socket=/var/run/mysqld/mysqld.sock

[mysqld_safe]
character-set-server = utf8
max_allowed_packet=16M
socket=/var/run/mysqld/mysqld.sock
```

mysqlのコンテナで、新らし目のコンテナだとsocketの置き場所が変わったりしているので

後ほどdocker-compose.ymlでmysqlのバージョン指定はしますが、今回はdockerのofficialのmysql:5.5.54を前提に書きます。

### Dockerfiles/mysql/docker-entrypoint-initdb.d/init-user-db.sh

```bash
#!/bin/bash
set -e

mysql -uroot -p"$MYSQL_ROOT_PASSWORD" <<-EOSQL
CREATE DATABASE example_development;
CREATE DATABASE example_test;
EOSQL

# mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -Dexample_development < /docker-entrypoint-initdb.d/example.dmp
```

mysqlインスタンスの初回起動時に実行されるスクリプトになります。

これはofficialのmysqlで、コンテナ内の

/docker-entrypoint-initdb.d

というディレクトリに置かれたシェルはインスタンスの作成時に実行される

という仕組みがあるので、そこにファイルを置くように設定します。

（あとでdocker-compose.ymlでファイルを指定します）

最後、docker-compose.yml

### docker-compose.yml

```yaml
version: "2"

services:

  #
  # メインコンテナ
  #
  main:
    build: .

    depends_on:
      - "mysql"

    volumes:
     - .:/products

    ports:
      - "3000:3000"

    environment:
      RAILS_ENV: development
      DATABASE_URL: mysql2://root:root@mysql/example_development

    command: rails s -b 0.0.0.0 -p 3000

  #
  # MySQLのコンテナ
  #
  mysql:
    image: mysql:5.5.54

    environment:
      - MYSQL_ROOT_PASSWORD=root

    volumes:
      - "./Dockerfiles/mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d"
      - "./Dockerfiles/mysql/conf.d:/etc/mysql/conf.d"

    ports:
      - "3306:3306"
```

ここまでで、docker-compose.ymlでRuby on Railsを起動するために必要なものは完成しました。

プロジェクトを起動するには

```
docker-compose up main
```
とやると、mysqlを起動して

init-user-db.shによってデータベースが作成され

その後にmainコンテナが起動して

entrypoint.shで初期化されて

プロジェクトが起動します。

init-user-db.sh
は、色々とカスタマイズすることで、すでにマイグレーションされたmysqlのダンプを置いて

それを初期データとして投入したり出来ます。

そうすると、

```
docker-compose stop
docker-compose rm mysql
docker-compose up main
```
とするだけで、データベースの初期化が完了します。

また、entrypoint.shで細工しているので

```
docker-compose up main
```
の時はdocker-compose.ymlに指定したcommandが実行されてプロジェクトが起動します。

railsコマンドを叩きたい時は

```
docker-compose run --rm main rake routes
```
とやると、コマンドが実行出来るようになっています。

なるべくシンプル構成でなるべく便利に使う想定で、今回このテンプレートっぽいファイルを作ってみました。

参考にしていただけたら幸いです。

一応githubリポジトリ
https://github.com/gendosu/docker-compose-template