Nginx + MySql + Rails6 (Using Webpacker) on Dockerな開発環境を構築します。
新しくプロジェクトから作成する機会なんてそうそうないので、以下手順をできるだけ要点を抑えつつまとめました。
今回しないこと。
プロジェクトの立ち上げにコミットするために以下についてはしない。
- 実際のコーディングはしない。1
- RSpec, Rubocopのようなコードの品質を上げるための設定はしない。
- 開発効率を上げるためのgem登録などは設定しない。
- i18nのような初期に設定するようなものも今回は設定しない。
asset pipelineの代わりにWebpackerを使用しています。なので、Webpackerについてはこの辺をざっと見ておくとよいです。
- 参考:webpacker/blob/master/docs/docker.md
- 参考:webpacker/blob/master/docs/deployment.md
- 参考:Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)
- 参考:Webpacker使うなら最低限これだけは知っておいてほしいこと
- 参考: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の設定については公式を参考にするとよい。
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'"
- 参考:How to safely stop the images #989
- 参考:When closing a container with a rails app, rails doesn't delete /tmp/pids/server.pid #1393
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の利用を選択することがあると思うのでそこは適宜この手順と照らし合わせながら進めればいいと思う。