この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、臼田です。
みなさん、ユーザーデータ活用してますか?(挨拶
今回はちょっとした検証でユーザーデータを使ったMySQL(のつもりで使ってるけど実際はMariaDB)のセットアップでハマったのでその対応について共有します。
まえおき
ユーザーデータを使ってEC2上にMySQLをセットアップするのは通常あまりやるべきではありません。というかユーザーデータじゃなくてもEC2ではなくRDSなどを利用すべきです。
が、今回はちょっとした検証のために手抜きをしてユーザーデータを使っています。オススメしないのでそこのとこお願いします。
背景
ちょっとした検証のためにEC2の環境をセットアップするCloudFormationのテンプレートを作ることにしました。MySQLの環境も必要だったのですが、ローカルのMySQLに接続するプログラムが用意されていたので、ユーザーデータの中で必要なパッケージを入れつつデータベースの作成やテーブルの作成などを行うことにしました。
実際に構築されたEC2を確認していると、プログラムが適切に動作しないことに気づきました。
原因調査
ユーザーデータでセットアップしていた内容は大体以下の通りです。細かいところは突っ込まないでください。
#!/bin/bash
yum update -y
yum install -y httpd mysql perl-DBI perl-DBD-MySQL mariadb-server
systemctl start mariadb
systemctl enable mariadb
mysql -u root <<EOF
CREATE DATABASE aaaaa;
CREATE USER 'aaaaa_ro'@'localhost' IDENTIFIED BY '******************';
SHOW GRANTS for aaaaa_ro@localhost;
USE 'aaaaa'
CREATE TABLE \`☹☺☻\`(id int, name varchar(256), pass varchar(256));
INSERT INTO \`☹☺☻\` VALUES (1, 'admin', '12345');
GRANT SELECT ON aaaaa.\`☹☺☻\` to aaaaa_ro@localhost;
EOF
ここで大事なところは、テーブル名がマルチバイトであることです。本来は絶対やりたくないことですが、要件がこうなっていたので仕方なくやっています。
試行錯誤しながら無事セットアップできるところまで作り込んだのですが、いざ動かしてみるとデータベースとのやり取りでエラーが発生しました。どうもテーブルが存在していないようでした。
そこで様子を見に行くと以下のようになっていました。
MariaDB [aaaaa]> show tables;
+--------------------+
| Tables_in_aaaaa |
+--------------------+
| ☹☺☻ |
+--------------------+
1 row in set (0.00 sec)
テーブル名が文字化けしていました。検証中、該当のセットアップコマンドはユーザーデータではなく事前に直接シェルでアクセスして動作確認しており、そのときには問題なくマルチバイトの文字列でテーブルが作成・表示されていました。
したがって文字コードの問題であると認識しました。
試しにユーザーデータでmysqlクライアントから接続した後に文字コードを確認してみます。
#!/bin/bash
…省略…
echo "chara設定なし"
mysql -u root -e "show variables like 'chara%';"
この結果の確認は/var/log/cloud-init-output.log
で可能です。適当にechoしておくと探しやすくて便利です。
chara設定なし
Variable_name Value
character_set_client latin1
character_set_connection latin1
character_set_database latin1
character_set_filesystem binary
character_set_results latin1
character_set_server latin1
character_set_system utf8
character_sets_dir /usr/share/mysql/charsets/
ほとんどのcharacter_set
がlatin1
になっています。テーブル作成のクエリが適切な文字コードで発行されていないことが原因でした。
対策を調べたところ、mysqlクライアントで接続時に文字コードを指定する--default-character-set=utf8mb4
オプションをつけてあげれば解決できそうでした。
試してみましょう。
#!/bin/bash
…省略…
echo "chara設定あり"
mysql -u root --default-character-set=utf8mb4 -e "show variables like 'chara%';"
chara設定あり
Variable_name Value
character_set_client utf8mb4
character_set_connection utf8mb4
character_set_database latin1
character_set_filesystem binary
character_set_results utf8mb4
character_set_server latin1
character_set_system utf8
character_sets_dir /usr/share/mysql/charsets/
これでutf8mb4
が適切に利用されました。
これを設定したユーザーデータでテーブルを作成します。
#!/bin/bash
yum update -y
yum install -y httpd mysql perl-DBI perl-DBD-MySQL mariadb-server
systemctl start mariadb
systemctl enable mariadb
mysql -u root --default-character-set=utf8mb4 <<EOF
CREATE DATABASE aaaaa;
CREATE USER 'aaaaa_ro'@'localhost' IDENTIFIED BY '******************';
SHOW GRANTS for aaaaa_ro@localhost;
USE 'aaaaa'
CREATE TABLE \`☹☺☻\`(id int, name varchar(256), pass varchar(256));
INSERT INTO \`☹☺☻\` VALUES (1, 'admin', '12345');
GRANT SELECT ON aaaaa.\`☹☺☻\` to aaaaa_ro@localhost;
EOF
動作を確認してみます。
MariaDB [aaaaa]> show tables;
+-----------------+
| Tables_in_aaaaa |
+-----------------+
| ☹☺☻ |
+-----------------+
1 row in set (0.00 sec)
これで無事動作しました。
まとめ
ユーザーデータを使ってMySQL(MariaDB)のセットアップをマルチバイトで行うと文字化けしてしまうので、文字コードの状態には注意しましょう。
まあでも、そんなことよりもマルチバイトのテーブル名ダメ、絶対。