【環境構築】docker(docker-syncも) + Vue.js + Webpack + Rails + MySQL + Nginx をエラー地獄切り抜け、構築した方法

#はじめに
色々なサイトを見ながら、まる三日かけてついに構築できましたので、スムーズに解決できた構築方法をご紹介したいと思います。

・Ruby 2.5.8 (x86_64-linux)
・Ruby on Rails 5.2.4.5

![スクリーンショット 2021-02-26 1.09.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/229746d3-b6a7-6fe1-8855-2716dc9d1158.png)

#初めに、ファイル作成

```$ cd 作業するディレクトリ```

作業ディレクトリに移動後。

```$ touch Gemfile Gemfile.lock docker-compose.yml Dockerfile```

```$ mkdir containers```

```$ mkdir containers/nginx```

```$ touch containers/nginx/Dockerfile containers/nginx/nginx.conf```

ファイル構成はこちら

```
[project_name]
├── docker-compose.yml
│── Dockerfile
│── Gemfile
├── Gemfile.lock
├── containers
    ├── nginx
        ├── Dockerfile
        ├── nginx.conf
```

#ファイルの中身を編集していきます

・Gemfile↓

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

```docker-compose.yml
version: '3.8'
services:
  db:
    image: mysql:5.7.19
    environment:
      - MYSQL_ROOT_PASSWORD=root
    ports:
      - "3307:3306"
    volumes:
      - db-data:/var/lib/mysql
  app:
    build: .
    environment:
      RAILS_ENV: development
    command: bundle exec puma -C config/puma.rb
    volumes:
      - .:/myapp
      - bundle-data:/usr/local/bundle
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
      - log-data:/myapp/log
      - vendor-store:/myapp/vendor
    depends_on:
      - db
  web:
    build:
      context: containers/nginx
    volumes:
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
      - node_modules-store:/myapp/node_modules
    ports:
      - 80:80
    depends_on:
      - app
volumes:
  bundle-data:
  public-data:
  tmp-data:
  log-data:
  db-data:
  node_modules-store:
  vendor-store:
  node_modules:
    driver: local
```

db（データベース用）、webpacker、アプリケーション用、それぞれのコンテナを作成します。

・Dockerfile↓

```
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev mariadb-client

RUN curl -sL https://deb.nodesource.com/setup_10.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

RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

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

RUN mkdir -p tmp/sockets
```

##Nginx用

* nginx/Dockerfile

``` nginx
FROM nginx:1.15.8

# インクルード用のディレクトリ内を削除
RUN rm -f /etc/nginx/conf.d/*

# Nginxの設定ファイルをコンテナにコピー
ADD nginx.conf /etc/nginx/conf.d/myapp.conf

# ビルド完了後にNginxを起動
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
```


```nginx/nginx.conf
# プロキシ先の指定
# Nginxが受け取ったリクエストをバックエンドのpumaに送信
upstream myapp {
  # ソケット通信したいのでpuma.sockを指定
  server unix:///myapp/tmp/sockets/puma.sock;
}

server {
  listen 80;
  # ドメインもしくはIPを指定
  server_name localhost 127.0.0.1;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  # ドキュメントルートの指定
  root /myapp/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @myapp;
  keepalive_timeout 5;

  # リバースプロキシ関連の設定
  location @myapp {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://myapp;
  }
}
```

#Railsの初期画面を表示させる

まず、rails newでプロジェクトの作成をします。

```
$ docker-compose run --rm app rails new . --force --database=mysql --skip-coffee
```

・```--skip-coffee```：CoffeeScriptのセットアップをスキップ。

##puma.rbの編集

```config/puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count

port        ENV.fetch("PORT") { 3000 }

environment ENV.fetch("RAILS_ENV") { "development" }

pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true
```

##buildでイメージの構築

```
$ docker-compose build
```

config/datebase.ymlを編集します。

```config/datebase.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root

# ここからした２行
  password: # ここには、datebase-compose.ymlの、- MYSQL_ROOT_PASSWORD=ここを入力
  host: db

development:
  <<: *default
  database: myapp_development
```

webコンテナ上で、データベースの作成をします。

```
$ docker-compose run --rm app rails db:create
```

イメージ構築〜コンテナ起動までをバックグラウンド（-d）で行います

```
$ docker-compose up -d
```

[localhost](http://localhost/)、もしくは、[127.0.0.1](http://127.0.0.1/)にアクセスすると、yey!Railsの初期画面が表示されたのではないでしょうか？

#webpackを導入する

この記事の、「DBのパスワードの設定」の手前までを参考に導入して下さい。
[RailsにWebpack+Vue.jsを、出来るだけ気楽に導入してみる](https://qiita.com/okabee326/items/014c282a24b0886c814e)

上記記事の場合は、```/sample```にアクセスすると、```aaa```が表示されます。

これで、RailsとVueの連携完了です。

#追記
2021/02/28：docker-syncの導入を追記しました。

docker for macをお使いの方なら陥ると考えられるlocalhostを開くのが以上に遅い問題を解決していきます。

まだ、これからrailsでアプリを作成する方は是非とも見ていただきたいです。

##localhostが遅くなる原因と解決法

###【原因】
* **MacのファイルIOが以上に遅いため**

つまり、docker for macを使用することによった、ホストとコンテナ間での大量のファイルの同期処理の遅さが原因です。

僕の場合は、1文字変更しただけでもコンパイルに1分以上かかっていました。
もはや、開発どころではありません笑

###【解決方法】
* **docker-syncを使用して解決**

解決方法は、調べればわかると思いますが解決方法が複数あります。
どれも賛否両論です。

下記にも記載のある、volumeのマウントや、バインドマウントオプションを使用する、名前解決。
それぞれ試してみましたが、僕の場合効果なしでした。

docker-syncを使用した解決方法が最も効果があったため紹介いたします。

他にも、

* Virtual Box（仮想マシン）上でdockerを使用する
* バインドマウントオプションを使用する
* volumeのマウント
* NFSボリュームシェアリング
* （DNSで、名前解決）

などなど、様々ありますのでググってみてください。

##docker-syncを導入

【参考】
[docker-syncでホスト-コンテナ間を爆速で同期する](https://qiita.com/pocari/items/0340049742927f3a94b7)

この記事の通り進めればOKです。

お疲れ様でした😃

#参考
[Rails世渡り2【docker × Ruby on Rails × Vue.js】](https://www.koatech.info/blog/rails-docker-webpacker/)

[Docker + Rails + Puma + Nginx + MySQL](https://qiita.com/eighty8/items/0288ab9c127ddb683315)

[RailsにWebpack+Vue.jsを、出来るだけ気楽に導入してみる](https://qiita.com/okabee326/items/014c282a24b0886c814e)