😊

rake db:create時のMySQLのエラー対応

2021/06/01に公開

はじめに

Ruby on RailsとMySQLの環境構築時にrake db:createでMySQLのエラーに何度か遭遇することがありました。今後どこかで同じエラーに遭遇しそうなので、備忘録として残します。

使用バージョン

  • Ruby: 2.4.10
  • Ruby on Rails: 4.2.10
  • MySQL: 5.7
  • Docker Desktop for Mac: 3.3.1

MySQLのエラー

Mysql2::Error: Access denied for user

条件

Ruby on Railsのdatabase.yml、MySQLのDockerfile、docker-compose.ymlは以下のとおりです。

database.yml
default: &default
  adapter: mysql2
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: mysql_user
  password: mysql_user
  host: mysql
  database: sampledb
  socket: /tmp/mysql.sock
  timeout: 5000

development:
  <<: *default

test:
  <<: *default
  database: sampledb_test
Dockerfile
FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD password
ENV MYSQL_USER mysql_user
ENV MYSQL_PASSWORD mysql_user
ENV TZ 'Asia/Tokyo'

ADD ./my.cnf /etc/mysql/conf.d/my.cnf

CMD ["mysqld"]
docker-compose.yml
version: '3'

services:
  mysql:
    build:
      context: ./db
      dockerfile: Dockerfile
    volumes:
      - ./db/data:/var/lib/mysql
    ports:
      - 3306:3306

  rails:
    build:
      context: ./rails
      dockerfile: Dockerfile.alpine
    volumes:
      - ./rails:/app/
    ports:
      - '3000:3000'
    depends_on:
      - mysql

このコードを使用して、docker-compose -f docker-compose.yml run --rm rails bashを行い、railsコンテナ内でbundle exec rake db:createを行います。

現象

Mysql2::Error: Access deniedが発生しました。

bash-5.0# bundle exec rake db:create
Mysql2::Error: Access denied for user 'mysql_user'@'%' to database 'sampledb': CREATE DATABASE `sampledb` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `_query'
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `block in query'
・・・略・・・
Couldn't create database for {"adapter"=>"mysql2", "pool"=>5, "username"=>"mysql_user", "password"=>"mysql_user", "host"=>"mysql", "database"=>"sampledb", "socket"=>"/tmp/mysql.sock", "timeout"=>5000}
Mysql2::Error: Access denied for user 'mysql_user'@'%' to database 'sampledb_test': CREATE DATABASE `sampledb_test` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `_query'
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `block in query'
・・・略・・・

原因

Ruby on Railsのdatabase.ymlにある、データベースへの接続情報が間違っているためです。ここではMySQLのMYSQL_USERとMYSQL_PASSWORDの値を、Ruby on Railsのユーザ名とパスワードにセットしていました。
そのため、database.ymlのユーザ名をrootとし、パスワードをMYSQL_ROOT_PASSWORDの値(password)に変更することで解決できます。

補足:なぜユーザをrootに変えることで解決できるのか
今回のMySQLコンテナではroot以外のユーザに権限を与えていません。
そのため、MySQLコンテナでデータベースを作成できる権限を持つのはrootのみとなります。
実際にMySQLコンテナにrootユーザで入って、権限を確認してみると、rootのみ権限が付与されていることが分かります。

$ mysql -h 127.0.0.1 -u root -p
mysql> show grants;
+-------------------------------------------------------------+
| Grants for root@%                                           |
+-------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION |
+-------------------------------------------------------------+
1 row in set (0.00 sec)

Mysql2::Error: Can't create database

条件

Ruby on Railsのdatabase.yml、MySQLのDockerfile、docker-compose.ymlは、上記「Mysql2::Error: Access denied for user」項目と同じになります。
ただし、database.ymlのユーザ名はroot、パスワードはrootユーザのパスワードとなります。

現象

Mysql2::Error: Can't create databaseが発生しました。

bash-5.0# bundle exec rake db:create
Mysql2::Error: Can't create database 'sampledb' (errno: 1777999232): CREATE DATABASE `sampledb` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `_query'
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `block in query'
・・・略・・・
Couldn't create database for {"adapter"=>"mysql2", "pool"=>5, "username"=>"root", "password"=>"password", "host"=>"mysql", "database"=>"sampledb", "socket"=>"/tmp/mysql.sock", "timeout"=>5000}
Mysql2::Error: Can't create database 'sampledb_test' (errno: 1777999232): CREATE DATABASE `sampledb_test` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `_query'
/usr/local/bundle/gems/mysql2-0.4.10/lib/mysql2/client.rb:120:in `block in query'
・・・略・・・
Couldn't create database for {"adapter"=>"mysql2", "pool"=>5, "username"=>"root", "password"=>"password", "host"=>"mysql", "database"=>"sampledb_test", "socket"=>"/tmp/mysql.sock", "timeout"=>5000}

原因

MySQLへの接続はできているようですが、データベースの作成ができていないようです。
作成できない原因の1つとして、作成するスペースがないためです。
docker volumeコマンドで確かめてみると、不要なvolumeが大量に残っていました。

$ docker volume ls
DRIVER    VOLUME NAME
local     2a75c2409d8d2ef9c66d276e75bbd3d4338d6b77719378e17d4e992c4df132cc
local     2d3fa031084aa6630d92279e1992d222a41590c2993fc26378e7b5081b80aade
local     3c60f74d1f9989c23a87ab30d76eaebcc8d91515bad77bf93d0d8acd8948f1d4
・・・略・・・

またMySQLコンテナに入りファイルを作ろうとしても、スペースがないため作成できないエラーが出ていました。

$ docker-compose -f docker-compose.yml exec mysql bash 
root@b62c2fa99375:/# dd if=/dev/zero of="sample_file.yml" bs=1 count=1
dd: error writing 'sample_file.yml': No space left on device
1+0 records in
0+0 records out
0 bytes copied, 0.0002786 s, 0.0 kB/s

そのため、不要なvolumeを削除することで解決できます。

$ docker volume rm 2a75c2409d8d2ef9c66d276e75bbd3d4338d6b77719378e17d4e992c4df132cc                                                 
2a75c2409d8d2ef9c66d276e75bbd3d4338d6b77719378e17d4e992c4df132cc

おわりに

この記事では、db:create時のMySQLエラーと原因をまとめました。
基本的なところですが、記事を書いて再確認できたので良かったと思います。
また、この現象を発生させるにあたり、dockerのvolumeを意図的に増やすこともできるようになったので良かったと思います。
この記事が誰かのお役に立てれば幸いです。

Discussion