rails開発環境をdockerで作ったメモ

# やったこと
railsの開発環境をDockerで立ち上げてみた。

# プロジェクトを作る
```shell-session
$ rails new -J --skip-bundle -T -d mysql rails_app
```

# mysqlの起動
mysqlのコンテナを立ち上げておく。
使うのはdocker公式イメージ。
docker-composeとか使うのはとりあえず後。

```shell-session
$ docker run -d -p 3306:3306 --name mysqld -e MYSQL_ROOT_PASSWORD=ルートパスワード mysql
```

data containerを使うのも後。

# db接続の設定

```yaml:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: コンテナ起動時に設定したパスワード
  host: mysqld
```

hostはmysqlコンテナ立ち上げ時に`--name`で指定した名前にしておく。

# Dockerfile
railsプロジェクトのトップにDockerfileを置く。

```:Dockerfile
FROM 2.1.5:onbuild

CMD ["bin/rails", "s"]
```

これだけ。使いたいversion名にする。`CMD`にはサーバ起動の命令を書いておく。

# bundle install
build時に`Gemfile.lock`が必須となるので、`bundle install`。

# build
```shell-session
$ docker build -t rails_app .
```

# dbの作成
```shell-session
$ docker run --rm --link mysqld:mysqld rails_app bin/rake db:create
```

`db:create`だけすれば良いので、`--rm`で終了後にコンテナを自動で削除する。

`--link`で、rails_appコンテナ内からホスト名`mysqld`でmysqlコンテナにアクセスできるように設定。

# 起動
```shell-session
$ docker run -d --name rails_app --link mysqld:mysqld -p 8080:3000 rails_app
```

これで、http://192.168.59.103:8080/ にアクセスするととりあえずwelcomeの画面は開ける。IPは、`boot2docker ip`で出力される値。

# ホスト上のソースファイルをマウント
ただし、これだとホスト上でファイルを編集しても、docker imageをリビルドしない限りコンテナ上のアプリに反映されない。これでは開発はままならないので、ホスト上のrailsディレクトリをコンテナにマウントする。

```shell-session
$ docker run -v "$PWD":/usr/src/app --link mysqld:mysqld -p 8080:3000 rails_app
```

`-v`オプションで、アプリのコードがあるカレントをコンテナ上のアプリのディレクトリにマウント。

`/usr/src/app`は、ベースに使っているイメージ`2.1.5:onbuild`のDockerfileに記載されている、コードのデプロイ先。

# scaffold
とりあえずscaffoldで適当なモデルを作り、ホスト上のコードに変更を加える。migrationも合わせてやっちゃう。

```shell-session
$ bin/rails g scaffold item name:string price:integer description:text
$ docker run --rm -v "$PWD":/usr/src/app --link mysqld:mysqld rails_app bin/rake db:migrate
```

http://192.168.59.103:8080/items にアクセスすると、Item一覧のページが見れるはず。リビルドなしでホスト上の変更が反映できたことがわかる。

# データの永続化
アプリは起動したが、mysqlコンテナが消えるとデータも消えてしまうので、data container patternに従ってmysqlコンテナとデータコンテナを分ける。

```
$ docker create --name mysql_data -v /var/lib/mysql busybox
$ docker run -d -p 3306:3306 --name mysqld --volumes-from mysql_data -e MYSQL_ROOT_PASSWORD=password mysql
$ docker run --rm -v "$PWD":/usr/src/app --link mysqld:mysqld rails_app bin/rake db:create
```

```
mysql> show databases;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| mysql                 |
| performance_schema    |
| rails_app_development |
| rails_app_test        |
+-----------------------+
5 rows in set (0.00 sec)
```

ここで再びmysqlコンテナを再度立ち上げてみる。

```
$ docker stop mysqld
$ docker rm mysqld
$ docker run -d -p 3306:3306 --name mysqld --volumes-from mysql_data -e MYSQL_ROOT_PASSWORD=password mysql
```

```
mysql> show databases;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| mysql                 |
| performance_schema    |
| rails_app_development |
| rails_app_test        |
+-----------------------+
5 rows in set (0.00 sec)
```

コンテナを再度立ち上げているが、data自体は永続化されたままである。

# docker-composeの出番です
ここまで来るといろいろとオプションとか面倒なので、docker-composeを使いたくなる。そこで、railsプロジェクトのトップに以下のファイルを置く。

```yaml:docker-compose.yml
mysqldata:
  image: busybox
  volumes:
   - /var/lib/mysql
mysqld:
  image: mysql
  volumes_from:
   - mysqldata
  ports:
   - 3306:3306
  environment:
    MYSQL_ROOT_PASSWORD: password
app:
  build: ./
  ports:
   - 8080:3000
  links:
   - mysqld:mysqld
  volumes:
   - $PWD:/usr/src/app
```

`docker-compose up -d`で諸々全てが立ち上がる。データコンテナを作り直しているので、
`docker-compose run`を使ってdbをセットアップ。このコマンドは、

```
Runs a one-off command on a service.
```

とマニュアルに書いてあるので、docker-compose.ymlで定義した各service（ymlの第一階層に定義したmysqldとかappなどをserviceと呼ぶ）に対して特定コマンドを実行したいときに使うのだろう。

```
$ docker-compose run app bin/rake db:create
$ docker-compose run app bin/rake db:migrate
```

以降、`docker-compose up`をしても、`volumes-from`で指定されたボリュームは保存されるので、mysqlのデータは永続化される。

ymlにMYSQLのパスワードを書いてしまっているのがいけてないなとは思う。が、`docker-compose help up`を見る限り、起動時に指定できそうな感じはしなかった。

# まとめ
dockerを使って、rails+mysqlの開発環境を作ってみた。サンプルプロジェクトは、こちら。
https://github.com/hokuma/docker_rails_sample

これで、

```shell-session
$ git clone xxx
$ docker-compose up -d
```

だけでとりあえず開発環境は立ち上げられる。