dockerでrails+vueの環境を作ったので解説

[DockerでRails+Webpackerの開発環境を構築するテンプレート](https://qiita.com/kawasin73/items/b8b092e9b763387c6ba8)
[開発しやすいRails on Docker環境の作り方](https://qiita.com/joker1007/items/9f54e763ae640f757cfb)

を参考にして作りました。

[DockerでRails+Webpackerの開発環境を構築するテンプレート](https://qiita.com/kawasin73/items/b8b092e9b763387c6ba8)の記事を参考にすれば、環境構築できると思うので、個人的に勉強したところを解説します。

## 

```dockerfile:dockerfile
FROM ruby:2.4.1

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev

RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \
  && apt-get install -y nodejs

RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
  curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
  echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
  apt-get update && apt-get install -y yarn

ENV ENTRYKIT_VERSION 0.4.0

RUN wget https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
  && tar -xvzf entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
  && rm entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
  && mv entrykit /bin/entrykit \
  && chmod +x /bin/entrykit \
  && entrykit --symlink

RUN mkdir /myapp
WORKDIR /myapp

ENTRYPOINT [ \
  "prehook", "ruby -v", "--", \
  "prehook", "bundle install -j3 --quiet", "--", \
  "prehook", "yarn install", "--"]

ADD . /myapp
```

```yml:docker-compose.yml
version: '2'
services:
  db:
    container_name: db
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: pass
    volumes_from:
      - data
  webpacker:
    container_name: webpacker
    build: .
    command: bundle exec bin/webpack-dev-server
    ports:
      - "3035:3035"
    depends_on:
      - web
    volumes:
      - .:/myapp
  web:
    container_name: rails
    build: .
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    ports:
      - "3000:3000"
    depends_on:
      - db
    volumes:
      - .:/myapp
    volumes_from:
      - data
    tty: true
    stdin_open: true
  data:
    image: busybox
    volumes:
      - datavol:/var/lib/mysql
      - bundle:/usr/local/bundle
      - node_modules:/myapp/node_modules
volumes:
  datavol:
    driver: local
  bundle:
    driver: local
  node_modules:
    driver: local
```

## webpackerについて

上の2ファイルでwebpackerに関する記述を抜き出すと

```dockerfile:dockerfile
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \
  && apt-get install -y nodejs

中略

RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
  curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
  echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
  apt-get update && apt-get install -y yarn

中略

ENTRYPOINT [ \
  "prehook", "ruby -v", "--", \
  "prehook", "bundle install -j3 --quiet", "--", \
  "prehook", "yarn install", "--"]
```

上の方はnodeとかyarnのインストールです。
ENTRYPOINTを使って```yarn install```しています。（下に続く）

```yml:docker-compose.yml
version: '2'
services:
中略
  webpacker:
    container_name: webpacker
    build: .
    command: bundle exec bin/webpack-dev-server
    ports:
      - "3035:3035"
    depends_on:
      - web
    volumes:
      - .:/myapp
中略
  data:
    image: busybox
    volumes:
      - datavol:/var/lib/mysql
      - bundle:/usr/local/bundle
      - node_modules:/myapp/node_modules
volumes:
中略
  node_modules:
    driver: local
```

### dataコンテナを使ったnode_modulesのマウント
dataコンテナを使ってnode_modulesをマウントしています。
gemと同じで、ライブラリをDockerfileの中でインストールしてしまうと、1こ追加するだけで全部インストールし直す手間ができてしまいます。
それをdataコンテナを作ってマウントしてあげることで、ローカルの時と同じように追加したものだけをインストールするようにしています。

### webpackerコンテナ

webpackerコンテナで```bin/webpack-dev-server```を実行することでvueのファイルをコンパイルすることができます。
vue関係のファイルが更新されると自動的にコンパイルしてくれます。

## bundle install問題の解消
dockerで公式チュートリアル通りにrailsを構築するとgemを一個追加しただけなのに```docker-compose build```で全てのgemがインストールし直されるというめんどくささがあります。

アプリの規模が大きくなってくると```docker-compose build```し直すのに10分くらいかかってしますので、解消しておくべきです。

基本的な仕組みとしては

- dataコンテナをbusyboxイメージ（2.5mbくらいしかないlinuxコマンドの詰め合わせのようなもの)を使って作る
- gem用のボリュームを作成
- rails用のコンテナ側とそのボリュームを接続する
- Dockerfileの方ではENTRYPOINTを使って```bundle install```することでイメージに含まれないようになっている

こうすることでrailsコンテナの中でいつものように```bundle install```することでgemのインストールがいつも通り走るようになります。

## ```rails c```と```binding.pry```を使えるようにする

何もせずにrailsを使うと上の2つが使えないです。
どちらも開発する上ではめちゃくちゃ便利なので使えるようにしました。
これは簡単で、

```yml:docker-compose.yml
  web:
    container_name: rails
    build: .
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    ports:
      - "3000:3000"
    depends_on:
      - db
    volumes:
      - .:/myapp
    volumes_from:
      - data
    tty: true
    stdin_open: true
```

の```tty```と```stdin_open```を```true```としてあげるだけです。

### ```rails c```を使いたいときは

```shell
$ docker exec -it rails(ここはコンテナ名) /bin/bash
```
として上で```rails c```してあげれば使うことができます。

### ```binding.pry```を使いたいときは

```shell
$ docker attach rails(ここはコンテナ名)
```

で使うことができます。
attachの方を使っていることに注意してください。

### execとattachの違い

attachはPID=1つまりすでにあるプロセスのbashに入るのが違います。
詳しくはこちらの記事を参考にしてください

[Dockerコンテナ内で操作 attachとexecの違い](https://qiita.com/RyoMa_0923/items/9b5d2c4a97205692a560)

## 参考記事

[DockerでRails+Webpackerの開発環境を構築するテンプレート](https://qiita.com/kawasin73/items/b8b092e9b763387c6ba8)
[開発しやすいRails on Docker環境の作り方](https://qiita.com/joker1007/items/9f54e763ae640f757cfb)
[Dockerコンテナ内で操作 attachとexecの違い](https://qiita.com/RyoMa_0923/items/9b5d2c4a97205692a560)