DockerでのRuby on Rails環境構築を一つずつ詳解する

##結論

Docker公式の「Quickstart: Compose and Rails」に書いてます。
なのでスラスラ理解できる方は下記リンク先へどうぞ
https://docs.docker.com/compose/rails/


公式のクイックスタートは全部英語で書かれていて、
知能の低い僕は疲れてしまいますので
こちらの公式ガイドを少しずつ紐解きながら環境構築します。

http://docs.docker.jp/glossary.html
http://docs.docker.jp/engine/articles/dockerfile_best-practice.html
こちらのdockerガイドとベストプラクティス集が詳しい、かつ分かりやすいです。

##Dockerとは？
多くの方々が分かりやすくDocker、コンテナ技術について解説してくれてますので
そちらを読みましょう。

**<解説リンク>**
https://knowledge.sakura.ad.jp/13265/
https://qiita.com/kotaro-dr/items/b1024c7d200a75b992fc


##Dockerfile

```ruby:Dockerfile
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
```

これをとりあえず使ってね！らしい。
しかしなんとなくで使うのは気持ち悪いのでコマンドを見ていく。

**[FROM]** 使用するイメージとバージョン
**[RUN]** コマンドの実行。railsに必要な必要なnodejsとpostgeqsqlをインストールしている
**[WORKDIR]** そのままの意味。作業ディレクトリを設定します。
**[COPY]**　ローカルのファイルをコンテナへコピーする
**[ENTRYPOINT]** 一番最初に実行するコマンド（ここではentrypoint.shを参照）
**[EXPOSE]** コンテナがリッスンするport番号
**[CMD]**　イメージ内部のソフトウェア実行（つまりRailsのことですね）


##Gemfile

```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
```

rails newをするとGemfileはrails用に書き換えられます。
バージョンは適宜変更しましょう。


##Gemfile.lock

空の状態でGemfile.lockファイルを作ります。

```
$ touch Gemfile.lock
```


##entrypoint.sh

```ruby:entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```

set -e は　「エラーが発生するとスクリプトを終了する」オプション
rm ではrailsのpidを削除
exec "$@"でCMDで渡されたコマンドを実行しています。(rails s)

##docker-compose.yml

公式によるとdocker-composeは魔法が起こる場所らしいです（ステキ

```ruby:docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```

一番重要であろうdocker-compose.ymlです。
docker-composeについてもdockerガイドに分かりやすい説明が記載されています。

こちらも何が起こっているか見ていきましょう。

**[version]** docker-composeのバージョンです。2019年4月現在最新は'3'です。
**[services]** この下のハッシュにサービスを作りましょう。なんでも良いですが通常はwebとdbと名付けます。
**[image]** 使用するimage
**[volumes]** ディレクトリのマウント設定（dbデータなどを残せます。。）
**[build]** Dockerfiletなどがあるパス（基本的にカレントディレクトリ）
**[command]** コマンド（pid削除してからrails s)
**[ports]** ポート番号。[ホスト：コンテナ]で設定。
**[depends_on]**　依存関係を示していて、起動順を制御できます。ここではdb→webへと起動します。

volumeについては
https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32
を参考にしました。




##Rails newしよう！

Dockerfile, docker-compose.yml, entrypoint.sh, Gemfile, Gemfile.lock
が揃ったのでrails newします。

```
$ docker-compose run web rails new . --force --no-deps --database=postgresql --skip-bundle
```

DBはpostgresql、Gemfileがあるためforce(上書き）オプション付き
--no-depsはリンクしたサービスを起動しない設定。
最後にbundleしますのでここではbundleをskipします。
webのimageがビルドされてその中でrails newコマンドが実行されます。


##bundle install

Gemfileが更新されたのでビルドを実行しましょう
```
$ docker-compose build
```


##Rails側のDB設定

```yml:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

```
config/database.ymlを上記の通りに変更します。
Railsはデフォルトでhost:localhostとなりますので
hostを先ほど作成したdbに変更します。


##コンテナの起動

```
$ docker-compose up
```

docker-compose.yml通りにdbサービスが起動し、webサービスが起動します。

##DB作成

```
$ docker-compose run web rake db:create
```

あとはdb:createすれば完了です。
マイグレーションする必要があるときは上のコマンドをdb:migrateに変えて実行しましょう。