DockerでRuby on Rails開発環境作ってみた

[エイチームライフスタイルアドベントカレンダー2017](https://qiita.com/advent-calendar/2017/ateam-lifestyle)、10日目は[株式会社エイチームライフスタイル](http://life.a-tm.co.jp/)のエンジニア @otama が担当します。

最近、弊社にて集計基盤を実現するため([Yellowfin導入事例](https://yellowfin.co.jp/blog/2017/11/10_casestudy))SQLばかりかいていましたが現場で各監視ツール等の導入時にdocker採用例が盛んになってきましたので @otama も使ってみて置いていかれないようにと触れてみました。
手始めにDockerを利用してRailsが動く環境を作成してみようと思います:point_up_tone2:
Qiitaにたくさん記事はあると思いますが。。。
また今回作成に利用したファイルは[コチラ](https://github.com/mst0403/empty-rails-app-template)にあります。

## 対象
Dockerって聞いたことあるけどまだ利用したことがないけど使ってみたい方

## ゴール
この記事を読んでMacでdocker　image内にbundle installしてRuby on Railsを新規作成、ファイル編集はローカルで行うことが出来る環境を作成する
※ 今回試したバージョン

```
ruby2.4.1
Ruby on Rails v5.1.4
```

※ 私の環境

```
MacBook Pro (Retina, 13-inch, Early 2015)
macOS 10.12.5
Docker Version 17.09.0-ce-mac35 (19611)
```

## Docker とは
[Docker](https://www.docker.com/)が開発した基盤ソフトウェアでアプリやOSの開発を簡単に行える、らしいです。
メリットとしてコンテナはオーバーヘッド(余計な処理)が少なくて軽いという点が上げられます。

## 事前準備
1. Dockerのインストール<br>
[Mac用ダウンロードページ](https://store.docker.com/editions/community/docker-ce-desktop-mac)<br>
[Windows用ダウンロードページ](https://store.docker.com/editions/community/docker-ce-desktop-windows)※Windowsでの動作確認は出来ておりません。。。
2. 今回の作業ディレクトリは`$WORKDIR`とし基本的にこのディレクトリからは移動しません。

    ```shell-session:作業ディレクトリ作成
    $ mkdir ~/docker-practice
    $ cd ~/docker-practice
    ```

## ステップ
1. ファイルの準備
1. dockerイメージの作成 + 開発準備
    1. docker build
    1. rails new
    1. dockerコンテナの起動
1. 開発開始
    1. トップページの作成

## 実践
### 1. ファイルの準備 
適当なディレクトリを作成しDockerfile,Gemfile,Gemfile.lockを作成します。

```shell-session:ファイルの準備
$ touch Dockerfile
$ touch Gemfile
$ touch Gemfile.lock
```

#### 中身は以下

Gemfile.lockは空

```Gemfile:$WORKDIR/Gemfile
source 'https://rubygems.org'
gem 'rails', '5.1.4'
```

```Dockerfile:$WORKDIR/Dockerfile
FROM ruby:2.4.1
ENV LANG C.UTF-8

ENV APP_ROOT /app

WORKDIR $APP_ROOT

# 最低限のものをinstall
RUN apt-get update && \
    apt-get install -y nodejs sqlite3 --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

# image内にbundle installするためGemfileをコピーする
COPY Gemfile $WORKDIR
COPY Gemfile.lock $WORKDIR

# docker image内にbundle install
RUN \
  echo 'gem: --no-document' > ~/.gemrc && \
  cp ~/.gemrc /etc/gemrc && \
  chmod uog+r /etc/gemrc && \
  bundle config --global build.nokogiri --use-system-libraries && \
  bundle config --global jobs 4 && \
  bundle install && \
  rm -rf ~/.gem

# ポートのエクスポート
EXPOSE  3000

CMD ["rails", "server", "-b", "0.0.0.0"]

## ----- memo -----
# bundle config --global jobs 4でbundle install 高速化
```

### 2. dockerイメージの作成 + 開発準備
#### 2-1 docker build
`$ docker build -t otama/rails-app .`　を叩いてイメージを作成する

必要なものは自動的にインストールされ準備が着々と進みます。。。

`$ docker images` を叩いてイメージが作成されていればOK

```shell-session:結果
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
otama/rails-app     latest              fc495a1258a8        About a minute ago   759MB
ruby                2.4.1               e7ca4a0b5b6d        2 months ago         684MB
```

#### 2-2. rails new
`$ docker run --rm -it -v "$PWD":/app otama/rails-app rails new . -BT`

```shell-session:オプションの補足
-B bundle installを行わない
-T test::unitを組み込まない
```

1. rails new するとGemfileを書き換えていいか聞かれるので Y を入力して進める
    $WORKDIR/src 内に必要なファイルが整います
2. Gemfileが書き換わったので再度イメージ化

    `$ docker build -t otama/rails-app .`

### 2-3. dockerコンテナの起動
`$ docker run -d -p 3000:3000 -v "$PWD":/app otama/rails-app`
-vのオプションでローカルのディレクトリをイメージ上にマウントしています

ここでブラウザを開き`localhost:3000`にアクセスしてみる

<img src="https://qiita-image-store.s3.amazonaws.com/0/46384/28f3398b-6062-2c86-3b18-b68b8c095af5.png" width="50%" alt="Yay! You're on Rails!">

### 3. 開発開始
#### 3-1. トップページの作成 rails g controller
1. topコントローラー作ってindexのページを作成してみようと思います。<br>

    ```
    $ docker ps
    $ docker exec -it <コンテナID> rails g controller top index
    ```
※コンテナIDは `$ docker ps`で調べます
2. ファイルが幾つか作成されました。変更してみましょう。<br>
`$WORKDIR/app/views/top/index.html.erb`のファイルを編集して保存。
3. ブラウザで`localhost:3000/top/index`へアクセスすると変更が反映されていますね！

### その他こんな時どうする？のメモ
+ db:create, db:migrateしたい
    + `$ docker run -it <コンテナID> rails db:create`
    + `$ docker run -it <コンテナID> rails db:migrate`
+ rails cしたい
    + `$ docker run -it <コンテナID> rails c`
    + `Ctrl` + `D`で抜ける
+ config系のファイル変えたので反映したい
    + `$ docker restart <コンテナID>`


## 今回利用したコマンド
```shell-session
// Dockerfileからイメージの作成docker build
$ docker build -t devloper_name/pjt_name .
// -t:タグ・名前をつける

// buildしたイメージをコンテナ化
$ docker run --rm -i -t devloper_name/pjt_name -v <ローカルパス>:<マウント先パス>
// --rm:コンテナ停止時に自動的に削除
// -p:コンテナ外からのアクセス:コンテナ側のポート番号
// -i:ホストの入力をコンテナの標準出力をつなげる
// -t:コンテナの標準出力とホストの出力をつなげる
// -v:volumeをマウントする場合につける

// イメージの確認
$ docker images

// コンテナの確認
$ docker ps -a # -aをつけると停止しているコンテナも表示する

// コンテナの停止
$ docker stop <コンテナID>

// ゴミを削除
$ docker rm <コンテナID> <コンテナID> .... # コンテナを削除、複数指定可
$ docker rmi <イメージID> <イメージID>　.... # イメージを削除、複数指定可
```

## 最後に
今回はひとまずRailsが動作する環境が出来ました。今後はdocker-composeを活かして好みの環境を作って行きたいと思います。
[エイチームライフスタイルアドベントカレンダー2017](https://qiita.com/advent-calendar/2017/ateam-lifestyle)、明日はVisual Studio Code使いの @matsu06 さんがVimについて書いてくれるらしいので、お楽しみに。

## お知らせ
[株式会社エイチームライフスタイル](http://life.a-tm.co.jp/)では、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
http://www.a-tm.co.jp/recruit/