DockerでRails5APIモードの環境構築

## 概要
DockerでRails5のAPIモードの開発用環境構築です。
Rails5の中身などについては触れません。

## 今回作る環境
DBにMySQLを使い、フロントサーバにNginxとUnicornを使います。

## 必要な環境
macOSXを対象としています。(Windowsでも動くと思いますが、未確認です。)
下記の環境を想定しています。

- docker 1.12.0
- docker-compose 1.8.0
- Rails5
- ruby 2.3

## フォルダ構成
フォルダ構成は説明を簡単にするため、Docker関連をRailsアプリのルート直下に置くことにします。

```
Railsアプリのルート
|- app/
|- config/
|- Gemfile
~
|- docker/
   |- nginx/
|- Dockerfile
|- docker-compose.yml
```

## Railsの設定
DB周りの設定

```config/database.yml
...
production:
  adapter: mysql2
  encoding: utf8
  pool: 5
  host: <%= ENV['DB_HOST'] %>
  database: <%= ENV['DB_NAME'] %>
  username: <%= ENV['DB_USER'] %>
  password: <%= ENV['DB_PASS'] %>
```

次に、Dockerfileを次のようにします。

```bash:Dockerfile
FROM ruby:2.3.1

RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

RUN apt-get update && \
    apt-get install -y libssl-dev && \
    rm -rf /var/lib/apt/lists/*

RUN gem install bundler

RUN mkdir -p /app
WORKDIR /app

COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install --without development test --path vendor/bundle

COPY . /app

EXPOSE 8080

ENTRYPOINT bin/start_server.sh
```

最後にスクリプトの設定

```bin/start_server.sh
#!/bin/bash -x
bundle exec rails db:create RAILS_ENV=production
bundle exec rails db:migrate RAILS_ENV=production
bundle exec unicorn -E production -c config/unicorn.rb
```

`$ chmod 755 bin/start_server.sh` と忘れずに行ってください。

##### 2016年8月7日追記
unicornの設定を忘れていました。

```ruby:config/unicorn.rb
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end 

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end
```

## Nginx
Dockerfileは次のようにします。

```bash:docker/nginx/Dockerfile
FROM nginx

COPY default.conf /etc/nginx/conf.d/default.conf
```

次にconfファイルを次のようにします。

```bash:docker/nginx/default.conf
server {
  listen 80;
  server_name localhost;

  location / {
    if (-f $request_filename) { break; }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://ruby:8080;
  }
}
```

## docker-compose.yml

```docker-compose.yml
version: '2'
services:
  mysql:
    image: mysql:5.6
    environment:
      - MYSQL_ROOT_PASSWORD=password
    ports:
      - '3306:3306'
  nginx:
    build: ./docker/nginx
    ports: 
      - '80:80'
    links:
      - ruby
  ruby:
    build: .
    ports:
      - '8080:8080'
    links:
      - mysql
    environment:
      ## SECRET_KEY_BASEはconfig/secrets.ymlにあります 
      - SECRET_KEY_BASE=[適当に入力してください]
      - DB_HOST=mysql
      - DB_USER=root
      - DB_PASS=password
      - DB_NAME=sample
```

ここでの注意点ですが、environmentで `"` これを使うのは避けましょう。
DB_PASS="pass"
DB_PASS=pass
この２つは別物として扱われてしまいます。

## 実行

```bash
$ docker-machine create -d virtualbox sample

$ docker-machine ls
マシンが作成されたこととACTIVE状態を確認してください

$ eval $(docker-machine env sample)

$ docker-machine ls
ACTIVEになったことを確認してください

$ docker-compose up -d
コンテナを立ち上げます。長いのでひと休憩をとりましょう。

$ docker-compose ps
ruby以外がちゃんと立っていることを確認してください。

$ docker-compose up -d --build
少し長いのでゆっくり待ちましょう

$ docker-compose ps
ちゃんと起動していることを確認してください
もしエラーがあったら docker-compose logs で確認してください

$ docker-machine ip sample
ipアドレスがでます。
メッセージを返すGETのエンドポイントを立てて、ブラウザアクセスで確認してみましょう。
```

`docker-compose up -d` を２回行っている理由ですが、
コンテナの立ち上げに成功するかの確認とmysqlコンテナの立ち上がり前にdbのcreateコマンドが走り、rubyコンテナがこけることがあるからです。
また、今回はdocker-composeでイメージのビルドをしていますが、予めイメージをビルドしておくのが良いと思われます。この場合は `docker-compose up -d --build` の `--build` を省きます。

## 最後に
今回の設定は開発用に使うことを推奨します。本番での運営ではお勧めしません。
本番で運営するならmysqlコンテナを削除してRDSなどを使ったり、Fluentdを噛ませてログを別サーバに集約したりすることをお勧めします。