Docker-composeを使ってRails6 + MySQL8.0のプロジェクトの環境作成

Dockerを使ってRails6+MySQL8.0のコンテナを作ろうとしたところ、エラーでまくったので
作り方とエラー時の対応策の備忘録です

ここをベースにしています。ただし、MySQLは8.0系です。これが曲者です。

qiita.com

環境

2019年11月現在の安定verを使用しています

  • Mac OS
  • Ruby2.6.5
  • Rails6.0.1
  • MySQL8.0

ホスト側のフォルダ構成

owner% tree -L 2 
.
├── Dockerfile
├── docker-compose.yml
└── src
    ├── Gemfile
    ├── Gemfile.lock
    ├── README.md
    ├── Rakefile
    ├── app
    ├── babel.config.js
    ├── bin
    ├── config
    ├── config.ru
    ├── db
    ├── lib
    ├── log
    ├── node_modules
    ├── package.json
    ├── postcss.config.js
    ├── public
    ├── storage
    ├── test
    ├── tmp
    ├── vendor
    └── yarn.lock

作業

こっから実作業です

0 Docker for Mac インストール

ここからDocker for Mac を入れます。Docker hubのアカウントを作り、Docker for Macをダウンロードします。 ただし、容量が大きいのでストレージに注意してください(docker.app(2GB)+コンテナの容量が加わります)

docs.docker.com

1 プロジェクト作成

プロジェクトを作ります。プロジェクト名はなんでもいいです

$ mkdir sampleRails
$ cd sampleRails

2 Dockerfile

次にDockerfile をこの階層に作成し、下記をコピペします

FROM ruby:2.6.5

# railsコンソール中で日本語入力するための設定
ENV LANG C.UTF-8

# yarn install(webpack用。これがないとrails起動しない))

# RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
# /var/lib/apt/lists配下のキャッシュを削除し容量を小さくできる
RUN apt-get update -qq && \
    apt-get install -y build-essential \
    libpq-dev \
    nodejs \
    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 && \
    rm -rf /var/lib/apt/lists/*

# 作業ディレクトリの設定
RUN mkdir /app_name
ENV APP_ROOT /app_name
WORKDIR $APP_ROOT

# gemfileを追加する
ADD ./src/Gemfile $APP_ROOT/Gemfile
ADD ./src/Gemfile.lock $APP_ROOT/Gemfile.lock

# gemfileのinstall
RUN bundle install
ADD ./src/ $APP_ROOT

注)Rails6でwebpackerが標準になったことにより、Railsアプリの開発環境にyarnのインストールが必要です
curl -sS 〜 apt-get install -y yarnあたりがyarnのインストールです

3 docker-compose.yml

次にdocker-compose.ymlをこの階層に作成します。(version3で作成しています)
注)簡易的にユーザアカウントをuser名,pass共にrootにしていますが、アカウントは適時変えてください。

version: '3'
services:
  db:
    image: mysql:8.0
    volumes: #ホスト側 : コンテナ にコピー
      - ./src/db/mysql_data:/var/lib/mysql
      - ./src/config/mysql/my.cnf:/etc/mysql/my.cnf
    environment:
      MYSQL_ROOT_PASSWORD: root #パスワード
      c: root #ユーザ名
    ports:
      - "3306:3306"

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - ./src:/app_name
    ports:
      - "3000:3000"
    links:
      - db

4 Gemfile作成

次にGemfileをsrcフォルダを作成し、その下に配備します

$ cd src
$ touch Gemfile

Gemfileのなかはひとまず下記でOKです(この後rails newした時に自動で追記されます) (railsのバージョンを変えたい場合はhttps://rubygems.orgrailsから参考にしてください)

source 'https://rubygems.org'
gem 'rails', '~> 6.0', '>= 6.0.1'

5 Gemfile.lock作成

次に空のGemfile.lockを作成します $ touch Gemfile.lock

6 Railsプロジェクト作成

プロジェクトフォルダに戻って、rails newを行なって、ひとまずRailsプロジェクトを作成します

$ cd ..
$ docker-compose run web rails new . --force --database=mysql --skip-bundle

7 database.yml

このままだとMySQLコンテナ設定不足のため、コンテナーを立ち上げようとしてもエラーになります
まず、/sampleApp/config/database.ymlを修正します

# MySQL. Versions 5.5.8 and up are supported.
#
# Install the MySQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root # docker-compose.ymlのMYSQL_ROOT_PASSWORD
  password: root # docker-compose.ymlのMYSQL_DATABASE
  host: db

development:
  <<: *default
  database: sample_database # (後にこのDBについての権限設定時に使用。)

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: app_name_test 

# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
#   DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
#   production:
#     url: <%= ENV['DATABASE_URL'] %>
#
production:
  <<: *default
  database: app_name_production
  username: app_name
  password: <%= ENV['APP_NAME_DATABASE_PASSWORD'] %>

9 my.cnf設定

MySQLの設定ファイルを編集します。src/config/mysql/my.cnfを作成します

$touch src/config/mysql/my.cnf

下記をコピペします(コメントは削除していいです)

# デフォルト認証プラグインの設定
[mysqld]
default_authentication_plugin= mysql_native_password      # MySQL8.0対応。Ruby_v2.6.5「caching_sha2_password」認証プラグイン未対応のため
secure-file-priv = ""      # secure-file-privにアクセスできず、mysqlコンテナが落ちるときは、これつける
skip-name-resolve      # 接続を受けた際に、認証の目的でクライアントのIPアドレスを逆引きする機能を無効にする設定

10 コンテナをビルドと起動

ここでMySQLとWebコンテナを作成します。docker-compose.ymlのある親フォルダーに移動し、
$docker-compose build コマンドでコンテナをビルドします

$cd ..
(docker-compose.ymlまで移動)
 
$docker-compose build #コンテナをビルド

~~build中~~

$ docker-compose up # コンテナの起動

11 MySQLの権限を付与

コンテナをビルドできました。ただし、このままだとMySQLの権限がなく、railsをデプロイしても権限なしエラーでデプロイできないです。
MySQLコンテナからMySQLのDatabaseに権限を付与します

新規ターミナルを開き、プロジェクトのカーレントフォルダまで辿ります。
'$docker ps'からMySQLのIMAGE名を調べます

$docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                               NAMES
0fc0305e78d7        js_sample_date_web   "bundle exec rails s…"   33 minutes ago      Up 33 minutes       0.0.0.0:3000->3000/tcp              js_sample_date_web_1
e25683e6bed5        mysql:8.0            "docker-entrypoint.s…"   47 hours ago        Up 33 minutes       0.0.0.0:3306->3306/tcp, 33060/tcp   js_sample_date_db_1

この環境ではe25683e6bed5ですので、$ docker exec -it e25683e6bed5 bashとすることでコンテナの中に入ることができます。
そこからmysqlに接続して、データベースの権限を付与します

$ docker exec -it e25683e6bed5 bash

#mysqlに接続
$ root@e25683e6bed5:/# mysql -u root -p

#rootユーザを作成(IDENTIFIED BY ''は docker-compose.xmlで定義したMYSQL_ROOT_PASSWORDの値です)
#'root'@'%'で全てのホストから接続可能なユーザー「root」を作成していますが、セキュリティ状よくないので実運用では’%’はホストIPを指定してください
# GRANT ALL PRIVILEGES ON *.* として全てのDBに権限を与えていますが、これもDBを指定してください

mysql> CREATE USER 'root'@'%' IDENTIFIED BY 'root';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';

# 設定を反映します
mysql> FLUSH PRIVILEGES;

12 DB作成

新しいターミナルを開き、rails db:createrailsプロジェクトが参照するデータベースを作成します

$ cd (projectフォルダ)
$ docker-compose run web rails db:create

13 http://localhost:3000/作成

お待たせしました。ブラウザからhttp://localhost:3000/をアクセスして、いつものrailsプロジェクト作成したぜ画面が出れば成功です

rails作成画面
rails作成

終わりに

MySQL8.0はつまづきポイントが多いように思います。エラーでまくって大変でした。