Nginx+Rails6.0+MySQL8.0+Adminer:docker-compose で rails new

14 min read読了の目安(約13400字

Docker の仕組みの解説や rails new や webpacker の詳しい話はしません。

TL;DR

今回の構成

  • Nginx
    • Railsサーバへのリバースプロキシ
    • 静的コンテンツ(JavaScript/CSS/画像ファイルなど)の配信
      • フロントエンドの環境整備は今回はやりません
  • Rails(Puma)
    • アプリケーションサーバ
    • Webpacker はいったんそのままで
      • simpacker を使う構築は別記事でまた上げる予定です
  • MySQL
    • データベース
    • PostgreSQL でないのは本番環境で Amazon RDS for MySQL を利用する予定のため
    • というか私が PostgreSQL あまり得意ではないから💦
    • Heroku の無料枠にデプロイする予定もない
  • Adminer
    • 簡易MySQLGUIクライアント
    • phpMyAdmin よりも機能が少なくて扱いやすい
    • MySQL Workbench あれば別に使わなくても良いけどあったらあったで便利
    • 使ってみてね

ローカル ruby で作業はしない

コンテナ立ち上げずにローカルruby使って "bundle install" とかすると楽なんですが
コンテナ立ち上げてる意味が(私は)ないと思ったのでそれはやらないことにします

なるべく Dockerfile を書きたくない

  • ダルい
  • 特殊なことをやってないないなら docker-compose から設定できるもので基本十分なはず

でも Rails サーバは Dockerfile を書く

Rails の公式imageは現在はなく、
標準 Ruby image を優先するとしてサポートされなくなっていますので、
Docker docks にあるように Dockerfile を書きます。ぴえん。
ruby のバージョンは2.6にしました。
ruby2.7は3.0previewへの移行対応が色々入っており、worning出るgemがそこそこあるみたい。

手順

  1. rails new する用の Dockerfile を作成
  2. Dockerfile で使う forDocker/rails/entrypoint.sh を作成
  3. mysql 用の設定ファイルを作成
  4. Rails と MySQL のみの docker-compose.yml を作成
  5. docker-compose run して rails new とか実施
  6. root ではないユーザを mysql に作成
  7. いったんコンテナ類を落とす
  8. nginx 用の設定ファイルを作成
  9. docker-compose.yml に Nginx, Adminer を追加
  10. 起動!

最終的に作成する設定ファイル類は以下です。それ以外は rails new コマンドなどで生成されます。

  • Dockerfile
  • docker-compose.yml
  • forDocker/mysql/conf.d/mysql.cnf
  • forDocker/nginx/default.conf
  • forDocker/rails/entrypoint.sh

最低限の状態で rails new をする

rails 用の Dockerfile を作成(あとで改変します)

FROM ruby:2.6
RUN set -x && curl -sL https://deb.nodesource.com/setup_14.x | bash -

RUN set -x && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list

RUN set -x && apt-get update -qq && apt-get install -yq nodejs yarn vim default-mysql-client

RUN mkdir /app
WORKDIR /app
# ※ここのコメントはあとで外す
# COPY Gemfile /app/Gemfile
# COPY Gemfile.lock /app/Gemfile.lock
# RUN bundle install
COPY . /app

# Add a script to be executed every time the container starts.
COPY ./forDocker/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
  • Rails6.0以上はwebpackerが必要なので最新のyarnが入るように Dockerfile を書く必要があります
  • Ruby:2.6 のdockerコンテナでrails6.0を入れようとしたらyarnがコケた | 北山淳也 | zenn

また、Dockerfile で指定している entrypoint.sh も作成しておきます。
forDocker/rails/entrypoint.sh

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

mysql 用の設定ファイルを作成
forDocker/mysql/conf.d/mysql.cnf

[mysqld]
default_authentication_plugin = mysql_native_password
skip-host-cache
skip-name-resolve

character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init-connect = SET NAMES utf8mb4
skip-character-set-client-handshake

[client]
default-character-set = utf8mb4

[mysqldump]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

mysql8.0 移行から認証形式が chacing_sha2_password になっているので
mysql_native_password(パスワード認証)に変更してやるのを忘れないように

docker-compose.yml

version: '3.7'

services:
  app:
    container_name: app
    build: .
    tty: true
    stdin_open: true
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    depends_on:
      - db

  db:
    image: mysql:8.0
    container_name: db
    restart: always
    volumes:
      - ./forDocker/mysql/conf.d:/etc/mysql/conf.d
      - dbvol:/var/lib/mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
      TZ: "Asia/Tokyo"

volumes:
  dbvol:

この状態で docker-compose run --rm app bash して db に接続できてるか、
バージョンは 8.0 かを確認してみます。
Dockerfile を読んでもらうとわかるのですが、
apt-get install vim default-mysql-client してるので
コンテナ内で vimmysql コマンドが使えます。

docker-compose run --rm app bash
# bashログインできてもちょっと待つ(MySQLが立ち上がってくるのを待つ)
mysql -u root -h db -e 'select version();'
Enter password: 
+-----------+
| version() |
+-----------+
| 8.0.22    |
+-----------+
  • mysql -u ユーザ名 -h ホスト -e "select 文とか"
  • MYSQL_ALLOW_EMPTY_PASSWORD=1 してるので root にパスワードはないです
  • (あまりよくはないが開発環境なので……)
  • mysql コマンドオプション | Qiita

OK ですね。じゃあいったんbashを抜けます。

exit
docker-compose down

再度 --service-ports つきで docker-compose run して
app の bash にログインします。

docker-compose run --rm --service-ports app bash
# Gemfile 作成
bundle init
# Rails を入れる
bundle add rails --version "~> 6.0"
# rails new
rails new . -d mysql --skip-test --force
# 依存ライブラリのインストール
bundle
yarn
rails webpacker:install

config/database.yml の編集

vim config/database.yml

config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  url: mysql2://root:@db:3306
  # username: root
  # password:
  # host: localhost

config/database.yml の編集を行ったら、データベースの準備をしてrailsを起動してみます。

rails db:create
rails db:migrate
rails s -b "0.0.0.0"

いつものアレが表示されました

Ctrl-c でいったん停止します。

root 以外のユーザーを作成する

Adminer はパスワードなしユーザーでのログインに対応していないので
パスワードなしroot以外のユーザーを作成します。
上記までの作業で app コンテナに入ってるのでそのまま作業を続けましょう。

# mysql client に接続
mysql -u root -h db
# id user pass user のユーザーを作成
MySQL [(none)]> CREATE user 'user'@'%' IDENTIFIED BY 'user';
Query OK, 0 rows affected (0.054 sec)
# 権限を確認。作っただけなので USAGE でありなんの権限もない
MySQL [(none)]> SHOW GRANTS for 'user'@'%';
+----------------------------------+
| Grants for user@%                |
+----------------------------------+
| GRANT USAGE ON *.* TO `user`@`%` |
+----------------------------------+
1 row in set (0.001 sec)
# user にフル権限を追加
MySQL [(none)]> GRANT ALL ON *.* TO 'user'@'%';
Query OK, 0 rows affected (0.025 sec)
# mysql client を抜ける
MySQL [(none)]> exit
Bye

ではいったんコンテナから抜けて全てのコンテナを落とします

exit
docker-compose down

rails new 後の Dockerfile

bundle init したことにより Gemfile などが生成されたので
rails(app) コンテナの Dockerfile のコメントを外します。

Dockerfile

FROM ruby:2.6
RUN set -x && curl -sL https://deb.nodesource.com/setup_14.x | bash -

RUN set -x && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list

RUN set -x && apt-get update -qq && apt-get install -yq nodejs yarn vim default-mysql-client

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

# Add a script to be executed every time the container starts.
COPY ./forDocker/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

設定ファイルの作成

mysql の設定ファイル forDocker/mysql/conf.d/mysql.cnf はもういじりません。

今度は Nginx も立ち上げるので設定ファイルを用意します。
forDocker/nginx/default.conf

upstream puma {
    server app:3000;
  }

server {
    listen 80;
    server_name localhost;

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

    root /app/public;

    location @puma {
      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://puma;
    }

    location / {
      try_files $uri @puma;
    }

    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;
    }

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /500.html {
    }
}

Nginx の設定ファイルはちょっと苦戦したんですがこちらにまとめました。

docker-compose.yml を完成させる

では docker-compose.yml に Nginx や Adminer を追加しましょう。
Rails 以外は Dockerfile なしでイケます。

docker-compose.yml

version: '3.7'

services:
  web:
    image: nginx:1.18
    container_name: web
    ports:
      - "8080:80"
    volumes:
      - ./forDocker/nginx/default.conf:/etc/nginx/conf.d/default.conf 
      - ./public:/app/public
    depends_on:
      - app

  app:
    container_name: app
    build: .
    tty: true
    stdin_open: true
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    depends_on:
      - db

  db:
    image: mysql:8.0
    container_name: db
    restart: always
    volumes:
      - ./forDocker/mysql/conf.d:/etc/mysql/conf.d
      - dbvol:/var/lib/mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
      TZ: "Asia/Tokyo"

  adminer:
    image: adminer:latest
    container_name: adminer
    ports:
      - "9000:8080"
    depends_on:
      - db

volumes:
  dbvol:

config/webpacker.yml の編集

私はこれをやらないと app コンテナが起動しませんでした。

check_yarn_integrity: false # ここを true から false に変更する

実行

docker-compose up -d

Nginxがリバースプロキシしてくれるので今度からは
localhost:8080 へアクセスして動作確認します。見れたはずです。OKですね。

いつものアレが表示されましたはずです

Adminer を使ってみる

localhost:9000 で Adminer が待ち受けています。
先ほど作成した user アカウントでログインしてみます。

ログインするとこんな感じです。
左上の「DB」を選択(SELECTするならとりあえず app_development ですかね)し、
「SQLコマンド」をクリックします。

こんな感じでちょっとSELECT文打つぐらいなら便利に使えると思います。

コンテナを停止

docker-compose down

今回の手順が全て終わったリポジトリはこちらです。

https://github.com/JUNKI555/rails_erb_practice01

その他の参考リンク