Rails で DB をデフォルトの SQLite から MySQL に変更する記録 (WSL, Debian 9)
Rails をやることになって入門してます。 Rails アプリで DB をデフォルトの SQLite から MySQL に変えようとして色々困った記録。 MySQL もあんまり触れたことなかったのでついでにインストールから。 環境はタイトルにも書いた通り Windows on Subsystem Linux (WSL) の Debian 9 です。
作業ログも兼ねたメモなので非常に冗長な書き方になっています。作業手順の記事を求めてる人は他の記事見た方がいいです。 あと日記形式になってるため口調もアレで技術文書の体はまったくなしていないので注意。
Debian 9 (Stretch) からは apt install mysql-server
で MariaDB が入る
デフォルトで MariaDB が入るようになったらしい。 次の手順で無事 MySQL が入る。
# echo -e "deb http://repo.mysql.com/apt/debian/ stretch mysql-5.7\ndeb-src http://repo.mysql.com/apt/debian/ stretch mysql-5.7" > /etc/apt/sources.list.d/mysql.list # wget -O /tmp/RPM-GPG-KEY-mysql https://repo.mysql.com/RPM-GPG-KEY-mysql # apt-key add /tmp/RPM-GPG-KEY-mysql # apt update # apt install mysql-server
引用元: How to install MySQL Server on Debian Stretch – I used to be a MySQL DBA for Hire
認証でつまずく
mysqld_safe --skip-grant-tables
でセーフモードで mysql を起動することにより、認証をスキップできるらしい。
$ sudo service mysql stop $ sudo mysqld_safe --skip-grant-tables & $ mysql -u root
入れた。 そして上記記事によると次の SQL 文を実行するとうまく行くらしい。 調べたら1個目は念のためパスワードを再設定する手順。 2個目は認証方法をパスワード認証に変える方法らしい。
> update user set password=PASSWORD("mynewpassword") where User='root'; > update user set plugin="mysql_native_password";
デフォルトだと user.plugin
には unix_socket
が設定されていた。
mysql> select plugin from user; +-------------+ | plugin | +-------------+ | unix_socket | +-------------+ 1 row in set (0.00 sec)
上記手順でうまく行くらしいことは分かったけど、(1カラムとはいえ) テーブルを書き換えるので念のため事前に mysql
テーブルをバックアップしたい。
ただ mysqldump
コマンドを実行してみたらエラーになった。
-h localhost
付けなくても同じ。
$ mysqldump -u root -h localhost mysql -- MySQL dump 10.13 Distrib 5.7.22, for Linux (x86_64) -- -- Host: localhost Database: mysql -- ------------------------------------------------------ -- Server version 5.7.22 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; mysqldump: Couldn't execute 'SHOW VARIABLES LIKE 'gtid\_mode'': Table 'performance_schema.session_variables' doesn't exist (1146)
エラーメッセージでググったらどうやら mysql_upgrade
で直るらしい。
$ sudo mysql_upgrade -u root Checking if update is needed. Checking server version. Running queries to upgrade MySQL server. mysql_upgrade: (non fatal) [ERROR] 1728: Cannot load from mysql.proc. The table is probably corrupted mysql_upgrade: (non fatal) [ERROR] 1545: Failed to open mysql.event mysql_upgrade: [ERROR] 1136: Column count doesn't match value count at row 1
これもエラー。
うーん…もういっそ select * from mysql;
の結果を (プライベートな日記ブログ) に貼り付けとくか… と思って再度接続しようとしてみた。
あれ?繋がらない。
しかも Ctrl-C (SIGINT) でも Ctrl-\ (SIGQUIT) でもセーフモードで立ち上げた MySQL が停止しない。
$ mysql -u root mysql ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded $ mysql -u root ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded $ jobs [1]+ Running sudo mysqld_safe --skip-grant-tables & $ fg sudo mysqld_safe --skip-grant-tables ^C ^C^C^C^C^C^C^C ^\^\^\
わからん…何も…となったので別の WSL の端末を立ち上げてそっちから pkill mysqld
したら停止した。何なんだ。
気を取り直して MySQL をセーフモードで立ち上げなおして接続、先ほどの SQL 文を実行する。
mysql> update user set password=PASSWORD("hogeramypassword") where User='root'; ERROR 1054 (42S22): Unknown column 'password' in 'field list'
カラムがないと言われた。確かにない。 どうもパスワードを設定する方法を再度ググったら次の SQL 文でいけるっぽい (さっきのは古い?)。
mysql> SET PASSWORD FOR root = PASSWORD('hogeramypassword'); ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement
ヌン!!!!!!!!
まぁさっきインストールの時にパスワード設定したばっかりだしまた再設定することもないでしょ… MySQL 初心者なのでここで再設定したパスワードとさっきのパスワードの意味が違うとかないよね?とか思いつつ、まぁ普通に root ユーザのパスワードだろうと思い気にしないことにする。 なので無視して次の SQL 文を実行。
update user set plugin="mysql_native_password";
今度は成功した。
セーフモードで起動していた MySQL を停止し…また Ctrl-C で停止しなくなっていたので pkill
でぶち殺した後、 service mysql start
で通常起動しなおす。
そしてクライアントからログイン。
$ mysql -u root -p Enter password: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
往々にして悪い予感は当たるもので、どうやらパスワードが空になっていたらしい。
なのでパスワードを打ち込む代わりに空エンターしてログイン。
そして SET PASSWORD FOR root = PASSWORD('hogeramypassword');
でパスワードの再設定をしようとした。
(最初インストール時に設定したパスワードはなんだったんだろう…)
mysql> SET PASSWORD FOR root = PASSWORD('hogeramypassword'); ERROR 1805 (HY000): Column count of mysql.user is wrong. Expected 45, found 48. The table is probably corrupted
ンーーーーー!!!
(ググりつつ) これか!
…って mysql_upgrade --force -uroot -p
ってさっき試したやんけ!!
ん? --force
付いとるな?あとさっきはセーフモードで起動した状態だったな?
試しに実行。
$ mysql_upgrade --force -uroot -p Enter password: Checking server version. Running queries to upgrade MySQL server. mysql_upgrade: [ERROR] 1136: Column count doesn't match value count at row 1 Checking system database. mysql.column_stats OK mysql.columns_priv OK mysql.db OK mysql.engine_cost OK mysql.event OK mysql.func OK mysql.general_log OK mysql.gtid_executed OK mysql.gtid_slave_pos OK mysql.help_category OK mysql.help_keyword OK mysql.help_relation OK mysql.help_topic OK mysql.host OK mysql.index_stats OK mysql.innodb_index_stats OK mysql.innodb_table_stats OK mysql.ndb_binlog_index OK mysql.plugin OK mysql.proc OK mysql.procs_priv OK mysql.proxies_priv OK mysql.roles_mapping OK mysql.server_cost OK mysql.servers OK mysql.slave_master_info OK mysql.slave_relay_log_info OK mysql.slave_worker_info OK mysql.slow_log OK mysql.table_stats OK mysql.tables_priv OK mysql.time_zone OK mysql.time_zone_leap_second OK mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK Upgrading the sys schema. mysql_upgrade: [ERROR] 1136: Column count doesn't match value count at row 1 Checking databases. sys.sys_config OK Upgrade process completed successfully. Could not create the upgrade info file '/var/lib/mysql/mysql_upgrade_info' in the MySQL Servers datadir, errno: 13
Upgrade process completed successfully.
と出ていたなんとなくいけたっぽい雰囲気がある。
なんか最後エラー出てるけど。
ので再度 SET PASSWORD FOR root = PASSWORD('hogeramypassword')
を実行してみる。
さっきと全く同じエラー。
mysql> SET PASSWORD FOR root = PASSWORD('hogeramypassword'); ERROR 1805 (HY000): Column count of mysql.user is wrong. Expected 45, found 48. The table is probably corrupted
create user myapp identified by 'hogeramypassword'
とかでもこれが出る。
うーん… もう一旦空パスワードで運用するか…
とりあえず MySQL の設定だけで休日が終わりそうな気がしたので一旦そういうことにした。
Rails の DB 設定を変更
まず MySQL の adapter をインストールする必要があるので、 コンパイルのためにヘッダーをインストールする。
$ sudo apt install libmysqlclient-dev
次に Gemfile の
gem 'sqlite3'
の部分を
gem 'mysql2'
に変更。
そして
bundle install
する。
無事インストールできたら、次に DB 接続設定を変えるため、 config/database.yml
を変更。
Before
# SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' # default: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: *default database: db/development.sqlite3 # 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: db/test.sqlite3 production: <<: *default database: db/production.sqlite3
After
# MySQL version 2.x # gem install mysql2 # # Ensure the MySQL 2 gem is defined in your Gemfile # gem 'mysql2' # default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: socket: /var/run/mysqld/mysqld.sock development: <<: *default database: myapp_development # 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: myapp_test production: <<: *default database: myapp_production
接続試験も兼ねて rails db:create
, rails db:migrate
を実行してデータベースとテーブルを作成させてみる。
実行した後テーブルが作成されているのを確認するのと、
わざと mysql サービスを落として rails db:migrate
して参照先が間違ってないかのチェック。
無事うまく行ってるっぽい。