21
15

More than 3 years have passed since last update.

丁寧にNginx + MySql + Rails6 (Using Webpacker) on Dockerな開発環境を構築します。

Last updated at Posted at 2020-05-25

Nginx + MySql + Rails6 (Using Webpacker) on Dockerな開発環境を構築します。
新しくプロジェクトから作成する機会なんてそうそうないので、以下手順をできるだけ要点を抑えつつまとめました。

今回しないこと。

プロジェクトの立ち上げにコミットするために以下についてはしない。

  • 実際のコーディングはしない。1
  • RSpec, Rubocopのようなコードの品質を上げるための設定はしない。
  • 開発効率を上げるためのgem登録などは設定しない。
  • i18nのような初期に設定するようなものも今回は設定しない。

asset pipelineの代わりにWebpackerを使用しています。なので、Webpackerについてはこの辺をざっと見ておくとよいです。

各バージョンについて

name version
Ruby(on docker) 2.6.5
Ruby on Rails 6.0.3
node 10.19.0
yarn 1.22.4
bundler 2.1.4
webpacker 5.1
docker 19.03.8
docker-compose 1.25.5
MySQL(on docker) 5.7
nginx(on docker) 1.17.3

※ (on docker)は、Dockerfileで指定しているバージョンです。

Rails6ではyarnを利用するので、事前にインストールしておく。

brew install yarn

1. プロジェクト構築手順

1-1. Githubにプロジェクトを作成し、git cloneしておく。

# githubでプロジェクトを作成しておく。
$ git clone git@github.com:{github_acount}/{project_name}.git
$ cd {project_name}

1-2. ruby,nodeのバージョンを指定する。

rubyとnodeのバージョンをしているするために.*-versionファイルを作成します。
※ anyenvを事前にbrew install anyenvしておくとよい。

また、rbenv, nodenvの設定については公式を参考にするとよい。

- 参考:GitHub - anyenv/anyenv: All in one for **env

1-2-1. Rubyバージョン指定

ruby : 2.6.5を指定

# インストールできるバージョンをの一覧を確認する。
$ rbenv install -l 
$ rbenv install 2.6.5
$ rbenv local 2.6.5
$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]

1-2-2. Nodeバージョン指定

node : v10.19.0を指定

# インストールできるバージョンをの一覧を確認する。
$ nodenv install -l
$ nodenv install 10.19.0
$ nodenv local 10.19.0
$ node -v
v10.19.0

1-3 不要なファイルをコミットできないように.gitignoreを作成する。

.gitignoreを作成し、git commitしておく。
※ .gitignoreを作成するために事前にbrew install giboしておくとよい。

# .gitignoreを作成
$ gibo dump macOS Node Ruby Rails VisualStudioCode > .gitignore

1-4. GemfileとGemfile.lockを作成する。

$ gem install bundler
Successfully installed bundler-2.1.4
Parsing documentation for bundler-2.1.4
Done installing documentation for bundler after 1 seconds
1 gem installed

次に、Gemfileを作成する。

# Gemfileを作成する。
$ bundle init

Gemfileファイルを開きrailsのgemを登録します。
バージョンについてはrails | RubyGems.orgを確認する。

  • ./Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

- # gem "rails"
+ gem 'rails', '~> 6.0', '>= 6.0.3'

bundle installを実行しGemfile.lockファイルを作成します。

$ bundle install
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 13.0.1
Using concurrent-ruby 1.1.6
...
Using rails 6.0.3
Bundle complete! 1 Gemfile dependency, 43 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

Ruby on Railsプロジェクトを作成するための準備が完了しました。

2. Ruby on Railsアプリケーションを構築する。

Ruby on Railsのアプリケーションを作る。

$ bundle exec rails new . --database=mysql --skip-git --skip-test-unit --skip-sprockets

...
├─ webpack-dev-server@3.11.0
└─ ws@6.2.1
✨  Done in 3.19s.
Webpacker successfully installed
オプション 説明
. カレントディレクトリ名がプロジェクト名
--database=mysql databaseはmysql
--skip-git .gitignoreを組み込まない(事前に作成済み)
--skip-test-uni Test::Unitを組み込まない
--skip-sprockets sprocketsを利用しない

2-1 Ruby on Railsの設定する。

2-1-1 webpackerのバージョンを最新にする。

  • ./Gemfile
- gem 'webpacker', '~> 4.0'
+ gem 'webpacker', '~> 5.1', '>= 5.1.1'

2-1-2 MySQLを利用するためにdocker-composeを用意する。

# mysqlのDockerfileとmy.cnfを用意する。
# docker-compose.ymlを用意する。
$ mkdir -p ./docker/mysql
$ touch ./docker/mysql/{Dockerfile, my.cnf}
$ touch ./docker-compose.yml

各ファイルの記述はこちら。

  • ./docker/mysql/Dockerfile
FROM mysql:5.7

RUN touch /var/log/mysql/mysqld.log
  • ./docker/mysql/my.cnf
[mysqld]
collation-server=utf8mb4_general_ci
character-set-server=utf8mb4
skip-character-set-client-handshake
init-connect = SET NAMES utf8mb4
default-time-zone=+9:00
explicit-defaults-for-timestamp=1
general-log-file=/var/log/mysql/mysqld.log

[client]
default-character-set=utf8mb4
  • ./docker-compose.yml
version: '3.3'
services:
  database:
    build:
      context: .
      dockerfile: ./docker/mysql/Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: {project_name}_development
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./log/mysql:/var/log/mysql

mysqlアカウントでrootを利用する場合は、MYSQL_ROOT_PASSWORDを設定するだけでよい。
MYSQL_DATABASEは開発で利用するデータベース名にする。

2-1-3 Ruby on Railsのdatabase.ymlを修正する。

database.ymlを修正してrailsからmysql on dockerに接続できるようにする。

  • ./config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  charset: utf8mb4
  collation: utf8mb4_general_ci
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: 127.0.0.1

development:
  <<: *default
  database: {project_name}_development

logを取得するために2

# Nginx用のlog吐き出し用
$ mkdir ./log/mysql
$ touch ./log/mysql/mysqld.log

2-1-4 Ruby on Railsのディレクトリ構成を修正する。

Webpackerを利用してJS,CSS,Image等を扱うための構成にします。

$ mkdir -p ./app/javascript/{stylesheets, images}
$ touch ./app/javascript/stylesheets/application.scss

2-1-5 [S]CSSファイル、ImageをWebpackerで扱う

  • ./app/javascript/packs/application.js
- // const images = require.context('../images', true)
- // const imagePath = (name) => images(name, true)
+ const images = require.context('../images', true)
+ const imagePath = (name) => images(name, true)
+ import "../stylesheets/application";

2-1-6 stylesheet_pack_tagに切り替える。

  • ./app/views/layouts/application.html.erb
-    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
+    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

2-1-7 check_yarn_integrityの設定をfalseにする。

  • config/webpacker.yml
development:
  <<: *default
  compile: true

  # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
-  check_yarn_integrity: true
+  check_yarn_integrity: false

2-1-8 extract_css: false -> trueにする。

開発中でもCSSファイルを作成してほしいのでextract_cssをtrueにします。

- config/webpacker.yml

# Extract and emit a css file
- extract_css: false
+ extract_css: true

2-1-8 assetsを生成しないようにする

  • ./config/initializers/generators.rb
Rails.application.config.generators do |g|
  g.assets false
  g.test_framework false
end

2-2 MySQL on Dockerを起動する。

# mysqlを起動する。
$ docker-compose -d up database

mysqlを起動したらmysqlの照合順序を確認する。

mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

2-3 ローカルPCからRuby on Railsを起動する。

# railsを起動する。
$ bin/rails s --port=3000 -b 0.0.0.0

以下の画面が表示されればOK。



3. Ruby on Rails on Dockerを構築する。

3-1. Dockerfileを作成する。

  • ./Dockerfile
FROM ruby:2.6.5

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y \
    build-essential \
    nodejs \
    yarn \
    default-mysql-client \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

ENV LANG ja_JP.UTF-8

RUN mkdir -p /app
WORKDIR /app

COPY Gemfile Gemfile.lock ./

RUN gem update bundler && bundle install

COPY . .

RUN yarn install --check-files
RUN yarn webpack --config ./config/webpack/development.js

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

3-2. docker-compose.ymlにapp:を追加する。

environmentで環境変数[RAILS_HOST]にdatabaseを指定します。
- ./docker-compose.yml

version: '3.3'
services:
+  app:
+    build: .
+    command: bundle exec rails s -b 0.0.0.0
+    volumes:
+      - .:/app:cached
+    ports:
+      - 3000:3000
+    depends_on:
+      - database
+    tty: true
+    stdin_open: true
+    environment:
+      RAILS_HOST: database
  database:
    build:
      context: .
      dockerfile: ./docker/mysql/Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: nginx_rails_with_webpacker_mysql_on_docker_development
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./log/mysql:/var/log/mysql

docker-composeで立ち上げる場合は環境変数hostを指定し、ローカル上で起動する場合は127.0.0.1を指定する。

  • config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
- host: 127.0.0.1
+ host: <%= ENV.fetch("RAILS_HOST") { '127.0.0.1' } %>

3-3. Ruby on Rails on Dockerを起動する。


# Ruby on Rails + MySQL on Dockerで起動する。
$ docker-compose up -d --build

ブラウザでhttp://localhost:3000にアクセスします。

改めて、Yay! You’re on Rails!の画面が表示されればOK.

4. nginx on Dockerを用意する。

Nginx(webサーバー)を用意します。

Nginx用のDockerfileとnginx.confを用意します。


# nginx用のファイルを作成する。
$ mkdir -p ./docker/nginx
$ touch ./docker/nginx/{Dockerfile, nginx.conf}

各ファイルの記述はこちら。

  • ./docker/nginx/Dockerfile

FROM nginx:1.17.3

RUN mkdir -p /usr/share/nginx/public

COPY ./docker/nginx/nginx.conf /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
  • ./docker/nginx/nginx.conf
server {
  listen       80;
  server_name  web;
  root /usr/share/nginx/public;

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

  location @app {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_pass http://app:3000;
  }

  location / {
      try_files $uri @app;
  }

  location ~ ^/(assets|packs)/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  location = /favicon.ico { access_log off; log_not_found off; }
  location = /robots.txt  { access_log off; log_not_found off; }

  location ~ /\.(?!well-known).* {
    deny all;
  }
}

logを取得するために

# Nginx用のlog吐き出し用
$ mkdir ./log/nginx
$ touch ./log/nginx/{access.log, error.log}
  • ./docker-compose.yml
version: '3.3'
services:
+  web:
+   build:
+     context: .
+     dockerfile: ./docker/nginx/Dockerfile
+   volumes:
+     - ./public:/usr/share/nginx/public:cached
+     - ./log/nginx:/var/log/nginx
+   ports:
+     - 80:80
+   depends_on:
+     - app
  app:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app:cached
    ports:
      - 3000:3000
    depends_on:
      - database
    tty: true
    stdin_open: true
    environment:
      RAILS_HOST: database
  database:
    build:
      context: .
      dockerfile: ./docker/mysql/Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: nginx_rails_with_webpacker_mysql_on_docker_development
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./log/mysql:/var/log/mysql

docker-compose up --buildを実行します。

ブラウザでhttp://localhostにアクセスします。
改めて、Yay! You’re on Rails!の画面が表示されればOK.

5. プロジェクトをちょっとだけカスタマイズ

こちらは、やったほうがいいと思われるが任意なあれこれです。

5-1. Add SplitChunks (Webpack V4)

SplitChunksPluginとは、共通で使用するpackageのJavaScriptファイルを纏める機能のことです。
デフォルトの設定を例としてあげておきます。チューニングする場合は公式を確認する。

  • ./config/webpack/environment.js

const { environment } = require('@rails/webpacker')
+ environment.splitChunks()

module.exports = environment

splitChunksを利用する場合は、JavaScriptファイルを読み込むヘルパーメソッドはjavascript_packs_with_chunks_tagになる。


- <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
+ <%= javascript_packs_with_chunks_tag 'application', 'data-turbolinks-track': 'reload' %>

5-2. app/assetsを削除する。

でも、app/assets/config/manifest.jsがないと怒らせる。


Expected to find a manifest file in `app/assets/config/manifest.js` (Sprockets::Railtie::ManifestNeededError)

プロジェクト作成時に-–skip-sprocketsを実行してもsprocketsのgemはインストールされプロジェクト内部ではまだ利用しているようです。そのため、app/assets配下のManifestファイルを削除してしまうとSprockets::Railtie::ManifestNeededErrorが発生します。

対策としては、Gemfileにgem 'sprockets', '< 4'を追加し、bundle update sprocketsすると良いようです。(2020/05時点)

$ bundle update sprockets
Using sprockets 3.7.2 (was 4.0.0)

5-3. app/javascriptをapp/frontendにする。

app/javascriptからapp/frontendに変更するという記事が多いように感じます。

./config/webpacker.ymlでsource_entry_pathを指定できるのでお好みで。

  • ./config/webpacker.yml
default: &default
- source_path: app/javascript
+ source_path: app/frontend
  source_entry_path: packs
  public_root_path: public
  public_output_path: packs
  cache_path: tmp/cache/webpacker
  check_yarn_integrity: false
  webpack_compile_output: true

5-4. ブラウザにlocalhostとか127.0.0.1とか0.0.0.0と入れるのはちょっと。

sudo vi /etc/hostsを実行し、HOST DATABASEにお好みのドメイン名を追加する。

保存してブラウザでdev-application.localhostと入力してみよう。

127.0.0.1       dev-application.localhost

5-5. docker-compose upで、A server is already running. Check /app/tmp/pids/server.pid.と言われて起動できない。

今回環境構築するために何度かdocker-compose upを実行しました。その時に当該事象が発生しました。
これはdocker-composeのバグないそうですが、よく起きている事象のようです。
対策は、調べた限りですが2つあります。4

5-5-1. 対処方法 1

docker-compose.ymlのcommandでbundle exec rails s..の前に削除コマンドを仕込む方法です。

command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"

5-5-1. 対処方法 2

DockerのCMDにスクリプトを登録しておく。
対応していることはtmp/pids/server.pidを削除するということは一緒ですが、スクリプトにすることで実行時に事前に行いたい処理を追加していくことができます。ワンライナーなスクリプトよりも見通しがいいのでこちらもおすすめです。

# Docker
CMD [foreground]
# foreground.sh
#!/bin/bash
set -e

rm -f tmp/pids/server.pid

bin/rails s -b 0.0.0.0 -p 3000

5-6. webpack-dev-server on Dockerを用意する。

webpack-dev-serverをDockerで構築します。5
Dockerで構築するほうがいい理由についてはまだ腹落ちしていないため任意

# ./docker-compose.yml
version: '3.3'
services:
  web:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile
    volumes:
      - ./public:/usr/share/nginx/public:cached
      - ./log/nginx:/var/log/nginx
    ports:
      - 80:80
    depends_on:
      - app
  app:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app:cached
    ports:
      - 3000:3000
    depends_on:
      - database
    tty: true
    stdin_open: true
    environment:
      RAILS_HOST: database
+     WEBPACKER_DEV_SERVER_HOST: webpacker
+ webpacker:
+   build: .
+   command: ./bin/webpack-dev-server
+   volumes:
+     - .:/webpacker-example-app
+   ports:
+     - '3035:3035'
+   tty: true
+   stdin_open: true
+   environment:
+     - NODE_ENV=development
+     - RAILS_ENV=development
+     - WEBPACKER_DEV_SERVER_HOST=0.0.0.0
+   depends_on:
+     - app
  database:
    build:
      context: .
      dockerfile: ./docker/mysql/Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: nginx_rails_with_webpacker_mysql_on_docker_development
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./log/mysql:/var/log/mysql
  • ./docker/nginx/nginx.conf
server {
  listen       80;
  server_name  web;
  root /usr/share/nginx/public;

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


  location @app {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_pass http://app:3000;
  }

  location / {
      try_files $uri @app;
  }

  location ~ ^/(assets|packs)/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;`v
  }

  location = /favicon.ico { access_log off; log_not_found off; }
  location = /robots.txt  { access_log off; log_not_found off; }

+  # Proxy webpack dev server websocket requests
+  location /sockjs-node {
+      proxy_redirect off;
+      proxy_http_version 1.1;
+      proxy_set_header Upgrade $http_upgrade;
+      proxy_set_header Connection "upgrade";
+      proxy_pass http://127.0.0.1:3035; # change to match your +webpack-dev-server host
+  }

  location ~ /\.(?!well-known).* {
    deny all;
  }
}

docker-compose up --buildを実行します。

ブラウザでhttp://localhostにアクセスします。
改めて、Yay! You’re on Rails!の画面が表示されればOK.

まとめ

  • rails/webpackarには情報がちゃんと記載されている。(webpacker/doc)
  • webpackerはおすすめしないという記事もあるが、みなさん共通して利用するならちゃんと考えましょう。とおっしゃっているのでちゃんと考えるために一度導入してみて感触を掴んだほうがいい。(逆に導入しない方法も構築してみるといいと思う。)
  • 開発環境のセットアップだけでも時間が掛かる。しかし、はじめにいろいろ検討しておくと開発がしやすくなる。
  • それぞれの設定についてもなぜ、そうしたのか。をまとめておけると後から再検討や情報共有する時に役に立つ。
  • rails6のセットアップと注意点を一通り学習することができた。
  • 実際は、rails new のタイミングで react や veuの利用を選択することがあると思うのでそこは適宜この手順と照らし合わせながら進めればいいと思う。

  1. ただ、scaffoldぐらいは実施しています。載せていないだけ。 

  2. 設定はしましたが、ログが吐き出されたかは未確認だったりします。。 

  3. location ~ /\.(?!well-known).*についてはもう少し学習しないと... 

  4. /app/tmp/pids/server.pid.については、対処方法1を採用しました。 

  5. この方法でうまくwebpack-dev-serverが動いているかはまだ、未確認です。 

21
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
15