RancherでDockerクラスタを構築する-④ 【DockerHub編】Railsスタックを立ち上げる

Rancherを用いてRailsスタックを立ち上げます。

## サンプルアプリ

簡単な書籍管理のRailsアプリです。

[BookStore](https://github.com/TongTheDopeness/book-store)

![qiita_rancher_13.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/f980933d-7d15-55fd-b710-2f8e13834b86.png)

* Rails 4.2
* データベース・サーバは Postgresql
* Admin画面にThoughtBotの[Administrate](https://github.com/thoughtbot/administrate)

という構成です。

## Rancherを使ったビルド戦略

Rancherは、同様のオーケストレーションである[Docker Cloud](https://cloud.docker.com/)と違い、Rancher単体でDockerをビルドすることは出来ません。したがって、事前にビルドしたものをpullする必要があります。

Rancherを使ったDockerビルド戦略は大きくは

1. [DockerHub](https://hub.docker.com/)でAutomated Buildする
2. [Quay.io](https://quay.io/)でAutomated Buildする
3. ローカルでビルドしたものをコンテナレジストリにpushする
4. CircleCI等のCIツールでビルドしたものをコンテナレジストリにpushする

などがあります。今回は1. DockerHubを利用したデプロイ方法をご紹介します。後日、Amazon ECRを使った方法もご紹介します。

## Rancherと相性の良い Container Registry

Dockerのコンテナを置いておく場所としてContainer Registryがあります。自前で構築することも出来ますが、セキュリティや可用性など面倒なことが多いので私は使っていません。クラウドサービスとして利用出来るContainer Registryでメジャーどころとしては：

1. [DockerHub](https://hub.docker.com/)→ビルドしてくれる
2. [Quay.io](https://quay.io/)→ビルドしてくれる
3. [Amazon ECR](https://aws.amazon.com/jp/ecr/)→自分でビルド
4. [Google Container Reqistry](https://cloud.google.com/container-registry/)→自分でビルド

などがあります。Rancher本家ブログの[Comparing Four Hosted Docker Registries](http://rancher.com/comparing-four-hosted-docker-registries/)にDockerレジストリの比較がありますが、相性の良い順としては、

DockerHub = Quay.io >> Amazon ECR >>>>>>>>> Google Container Registry

という感じでしょうか。また、__DockerHubは無料プランでもプライベートリポジトリを１つもらえます__。Quay.ioは高くてビルドに少し時間がかかります。加えて、DockerHubとQuay.ioは海外にホスティングしていると予想されるため、ダウンロードのレイテンシが馬鹿になりません。

したがって、__本番運用で現実的なのは東京リージョンも使えるAmazon ECR__でしょうか。実際私も多くのDockerコンテナをAmazon ECRに突っ込んでいます。

## とりあえず立ち上げてみる

DockerHubにpublicイメージを公開していますので、これを使って手っ取り早く立ち上げてみます。
[tongthedopeness/book-store](https://hub.docker.com/r/tongthedopeness/book-store/)

### Stackを追加する

![qiita_rancher_14.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/b82fc6c6-aaa9-1205-0d54-459f4140a10c.png)

`STACKS > Add Stack`でスタックを追加します。

### docker-compose.ymlをアップロードする

UIコンソールから一つずつサービスを起動することも出来ますが、ここでは手っ取り早くdocker-compose.ymlをアップロードします。

アップロードするdocker-compose.yml
YOUR_SECRET_KEYは`rake secret`で適当なsecretを入れてください。
（面倒な方は`7716957d8268d38005eddb5eb5eadf39c9b0fffd3106d304447c9a1e366b61c88a05e06d144283be0d8b400a464049e297c036f0275ba00033a2e1a71daa6c1`を入力してください)

``` docker-compose.yml
rails:
  ports:
  - 3000:3000/tcp
  environment:
    RAILS_ENV: production
    RACK_ENV: production
    SECRET_KEY_BASE: YOUR_SECRET_KEY
    RAILS_SERVE_STATIC_FILES: 'true'
  labels:
    io.rancher.container.pull_image: always
  tty: true
  image: tongthedopeness/book-store
  links:
  - postgres
  stdin_open: true

postgres:
  environment:
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: postgres
  tty: true
  image: kiasaki/alpine-postgres
  stdin_open: true
```

参考までに、Dockerfileも載せておきます。

``` Dockerfile
FROM tongthedopeness/alpine-ruby

WORKDIR /usr/src/app

COPY Gemfile Gemfile.lock ./
RUN bundle install --without test development && bundle clean

COPY . /usr/src/app

RUN RAILS_ENV=production bundle exec rake assets:precompile

EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
```

![qiita_rancher_15.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/1c84113e-624a-295f-dcd1-86842da9d2cb.png)

NameにStack名、docker-compose.ymlは上記のファイル（デスクトップなどに保存して選択してください）。`Create`するとimageをダウンロードして、Stackが起動します。

![qiita_rancher_16.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/5ad8deca-5580-6661-8773-76569707db89.png)

↑こうなれば成功です。

`http://[VULTRのホスト]:3000/admin`でアクセスします（データベースが無いのでまだエラーになります）。


### Rancher式 rake db:create db:migrate 

dockerを使ってて、

* __`rake db:migrate` とかどうするねん！？__
* __`rails c` 出来ねぇ。。__

と悩んだことが一度はあると思います。私もそうでした。migrateが必要になる度にググって長いコマンドを打って、また忘れて。。。。の繰り返しでした。

しかしながらRancherを使うようになってからは、何も考えずに直感的にそれが出来るようになりました。

![qiita_rancher_16.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/8c28ed36-c00c-3c30-3b0c-342dfa5fbc50.png)

上記の画面の`rails`をクリックすると、railsサービスの詳細が表示されます。

![qiita_rancher_17.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/0bd8506a-bd1d-b339-14b0-36ae561dea07.png)

上記画像の右下の赤枠の部分をクリックし、`Execute Shell`をクリックしてください。

![qiita_rancher_18.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/4e3f8350-aecb-bdfa-3c96-8d52dc3f69ff.png)

このように、shellが表示されます。このshellは

__Railsのコンテナ内部に入った状態__

です。したがって、Dockerでありながら、Dockerを意識することなく、普通にコマンドを打つことで出来ます。

```
bash-4.3# ls -la
total 180
drwxr-xr-x    1 root     root          4096 Oct 11 08:58 .
drwxr-xr-x    1 root     root          4096 Oct 11 08:57 ..
drwxr-xr-x    8 root     root          4096 Oct 11 09:02 .git
-rw-r--r--    2 root     root           864 Oct 11 08:54 .gitignore
-rw-r--r--    2 root     root           282 Oct 11 08:54 Dockerfile
-rw-r--r--    4 root     root          1568 Oct 11 08:54 Gemfile
-rw-r--r--    4 root     root          4939 Oct 11 08:54 Gemfile.lock
-rw-r--r--    2 root     root           478 Oct 11 08:54 README.rdoc
-rw-r--r--    2 root     root           249 Oct 11 08:54 Rakefile
drwxr-xr-x    9 root     root          4096 Oct 11 09:02 app
drwxr-xr-x    2 root     root          4096 Oct 11 09:02 bin
-rw-r--r--    2 root     root           519 Oct 11 08:54 circle.yml
drwxr-xr-x    5 root     root          4096 Oct 11 09:02 config
-rw-r--r--    2 root     root           153 Oct 11 08:54 config.ru
drwxr-xr-x    3 root     root          4096 Oct 11 09:02 db
-rw-r--r--    2 root     root           444 Oct 11 08:54 docker-compose.yml
drwxr-xr-x    4 root     root          4096 Oct 11 09:02 lib
drwxr-xr-x    1 root     root          4096 Oct 11 08:58 log
drwxr-xr-x    3 root     root          4096 Oct 11 08:58 public
drwxr-xr-x    8 root     root          4096 Oct 11 09:02 test
drwxr-xr-x    1 root     root          4096 Oct 11 14:58 tmp
drwxr-xr-x    3 root     root          4096 Oct 11 09:02 vendor
```
```
bash-4.3# rake db:create db:migrate
== 20161011064051 CreateBooks: migrating ======================================
-- create_table(:books)
   -> 0.0097s
== 20161011064051 CreateBooks: migrated (0.0102s) =============================
```

```
bash-4.3# rails c
Loading production environment (Rails 4.2.6)
irb(main):001:0> Book.count
   (3.6ms)  SELECT COUNT(*) FROM "books"
=> 0
irb(main):002:0> Book.create(title: "How to Win Friends and Influence People")
   (0.2ms)  BEGIN
  SQL (0.7ms)  INSERT INTO "books" ("title", "created_at", "updated_at") VALUES
($1, $2, $3) RETURNING "id"  [["title", "How to Win Friends and Influence People
"], ["created_at", "2016-10-11 15:52:19.366197"], ["updated_at", "2016-10-11 15:
52:19.366197"]]
   (3.7ms)  COMMIT
=> #<Book id: 1, title: "How to Win Friends and Influence People", isbn: nil, de
sc: nil, created_at: "2016-10-11 15:52:19", updated_at: "2016-10-11 15:52:19">
```

これで、もう一度

`http://[VULTRのホスト]:3000/admin`

にアクセスしてみてください。

## DockerHubを使う

長くなりましたが、RancherでDockerHubを使う方法をご紹介します。ここまでは、私がDocker Hubに公開しているDockerイメージを使いましたが、__自前のイメージをDockerHubにプライベートリポジトリとして置いておく__という筋書きです。

![qiita_rancher_19.PNG](https://qiita-image-store.s3.amazonaws.com/0/143640/bf252ab0-e1f3-acff-a227-0b9fe52d6033.png)

`Insfrastructure > Registries > Add Registry ` でレジストリを追加します。

DockerHubの場合、これだけでPrivate リポジトリをpullすることが出来ます。Quay.ioも同様です。
（imageの部分は自前のimage名に変更してください）

今回はdocker-compose.ymlを使ってstackを構成しましたが、Add Serviceでサービスを是非色々立ち上げてみてください。

## （参考）Dockerfileについて

今回のサンプルアプリでは、


``` Dockerfile
FROM tongthedopeness/alpine-ruby

WORKDIR /usr/src/app

COPY Gemfile Gemfile.lock ./
RUN bundle install --without test development && bundle clean

COPY . /usr/src/app

RUN RAILS_ENV=production bundle exec rake assets:precompile

EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
```

というDockerfileを作成しました。ベースイメージはalpine-rubyをrails仕様にしたミニマムイメージです。