Docker Compose を使って Sinatra と Redis コンテナを 1 コマンドで立ち上げる


## 概要
Docker公式オーケストレーションツールの 1 つ Docker Compose を使って Redis と Sinatra からなるアプリケーションを動かしてみるという話。

Redis, Sinatra はそれぞれ別のコンテナとして動かす。通常であれば `docker run` を 2 回実行したり、実行時に `-e` や `-p` などあれこれオプションを付ける必要があるが、Compose を使うと 1 コマンドでサクッと動かせる。

## Hello World
### サンプルアプリケーション

```bash
$ mkdir sample && cd sample
```

Sinatar アプリケーションのコードはこんな感じ。アクセスされたら `Hello World` といってアクセスされた数をインクリメントする。

```ruby
# app.rb
require "sinatra"
require "redis"

redis = Redis.new(
  host: ENV["REDIS_HOST"],
  port: ENV["REDIS_PORT"]
)

set :bind, '0.0.0.0'

get "/" do
  "Hello World! I have been seen #{redis.incr('/')} times."
end
```

```ruby
# Gemfile
source "https://rubygems.org"
ruby "2.2.0"

gem "sinatra"
gem "redis"
```

### Dockerfile の作成
アプリケーションの依存関係を `Dockerfile` に書く

```bash
FROM ruby:2.2.0

ADD . /app
WORKDIR /app
RUN bundle install -j4
```

`.dockerignore` も用意しておきます。

```bash
# .dockerignore

## environment normalization
.env
.bundle
# ホストマシン側で bundle install --path vendor/bundle している場合
vendor/bundle
.ruby-version

## git
.git
.gitignore

## log
log
tmp

## docker
.dockerignore

## etc
# 他にも色々あるけど省略
```

### サービスの定義
サービスの定義を `docker-compose.yml` に書く。

```yaml
web:
  build: .
  command: bundle exec ruby app.rb
  ports:
    - 80:4567
  volumes:
    - .:/app
  links:
    - redis
  environment:
    - REDIS_HOST=redis
    - REDIS_PORT=6379
redis:
  image: redis:latest
```

ここでは `web` と `redis` 2 つのサービス定義している。

### Compose を使ってイメージのビルドとアプリケーションの起動
`docker-compose up` コマンドで、Sinatar アプリケーションの Docker イメージのビルドをしてアプリケーションを起動する。

```bash
$ docker-compose up
Creating sample_redis_1...
Creating sample_web_1...
Building web...
Step 0 : FROM ruby:2.2.0
 ---> 51473a2975de
Step 1 : ADD . /app
 ---> 43ea79246bc4
Removing intermediate container 42a9412e6601
Step 2 : WORKDIR /app
 ---> Running in b8ccb1554b59
 ---> 4a5e4f5daae2
Removing intermediate container b8ccb1554b59
Step 3 : RUN bundle install --path vendor/bundle -j4
 ---> Running in 3bee7f6cdd9b
Don't run Bundler as root. Bundler can ask for sudo if it is needed, and
installing your bundle as root will break this application for all non-root
users on this machine.
Using tilt 1.4.1
Using redis 3.2.1
Using bundler 1.7.12
Using rack 1.6.0
Using rack-protection 1.5.3
Using sinatra 1.4.5
Your bundle is complete!
It was installed into ./vendor/bundle
 ---> cc2a6d3d33e4
Removing intermediate container 3bee7f6cdd9b
Successfully built cc2a6d3d33e4
Attaching to sample_redis_1, sample_web_1
redis_1 | [1] 01 Mar 11:24:35.546 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1 |                 _._
redis_1 |            _.-``__ ''-._
redis_1 |       _.-``    `.  `_.  ''-._           Redis 2.8.19 (00000000/0) 64 bit
redis_1 |   .-`` .-```.  ```\/    _.,_ ''-._
redis_1 |  (    '      ,       .-`  | `,    )     Running in stand alone mode
redis_1 |  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
redis_1 |  |    `-._   `._    /     _.-'    |     PID: 1
redis_1 |   `-._    `-._  `-./  _.-'    _.-'
redis_1 |  |`-._`-._    `-.__.-'    _.-'_.-'|
redis_1 |  |    `-._`-._        _.-'_.-'    |           http://redis.io
redis_1 |   `-._    `-._`-.__.-'_.-'    _.-'
redis_1 |  |`-._`-._    `-.__.-'    _.-'_.-'|
redis_1 |  |    `-._`-._        _.-'_.-'    |
redis_1 |   `-._    `-._`-.__.-'_.-'    _.-'
redis_1 |       `-._    `-.__.-'    _.-'
redis_1 |           `-._        _.-'
redis_1 |               `-.__.-'
redis_1 |
redis_1 | [1] 01 Mar 11:24:35.547 # Server started, Redis version 2.8.19
redis_1 | [1] 01 Mar 11:24:35.547 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1 | [1] 01 Mar 11:24:35.547 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1 | [1] 01 Mar 11:24:35.547 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | [1] 01 Mar 11:24:35.547 * The server is now ready to accept connections on port 6379
web_1   | [2015-03-01 11:24:43] INFO  WEBrick 1.3.1
web_1   | [2015-03-01 11:24:43] INFO  ruby 2.2.0 (2014-12-25) [x86_64-linux]
web_1   | == Sinatra/1.4.5 has taken the stage on 4567 for development with backup from WEBrick
web_1   | [2015-03-01 11:24:43] INFO  WEBrick::HTTPServer#start: pid=1 port=4567
```

アクセスすると `Hello World` が出てる。

![スクリーンショット 2015-03-01 20.25.04.png](https://qiita-image-store.s3.amazonaws.com/0/20833/534a5697-30b4-5ffc-ab34-f9f1cdf99adc.png "スクリーンショット 2015-03-01 20.25.04.png")

### デーモンモードで実行
`-d` を付けて `up` するとデーモンモードで実行する

```bash
$ docker-compose up -d
Recreating sample_redis_1...
Recreating sample_web_1...
```

`docker-compose ps` でステータスが見られる

```bash
$ docker-compose ps
     Name                  Command             State          Ports
---------------------------------------------------------------------------
sample_redis_1   /entrypoint.sh redis-server   Up      6379/tcp
sample_web_1     bundle exec ruby app.rb       Up      0.0.0.0:80->4567/tcp
```

## REF

* [公式ドキュメント](https://docs.docker.com/compose/)
* [Docker Compose リファレンス](http://qiita.com/spesnova/items/6e8919b34e763f27c34e)