Ubuntu(18.04 LTS)でmysql-serverをmariadb-serverで置き換えるとsystemd経由でmariadbが起動できない。
追記
この記事には一部誤りがあります。 以下の記事も合わせてご覧ください。
トラブル
タイトルの通りです。 Ubuntu 18.04で発生したトラブルですが、他のバージョンでも起こり得そうな予感がします。おそらく。
$ sudo apt install mysql-server
$ sudo apt purge mysql-server
$ sudo apt install mariadb-server
とすると、最後のapt install
が妙に遅い事に気が付きます。 コレは、aptがインストール後におせっかいでmariadbを起動してくれるのですが、何らかの原因でしばらく経ってもmariadbが起動しないためです。
その後、systemctl start mariadb
を試しても、しばらくした後に起動失敗します。
$ sudo systemctl start mariadb
Job for mariadb.service failed because a timeout was exceeded.
See "systemctl status mariadb.service" and "journalctl -xe" for details.
調査
systemdのログ
$ sudo systemctl status mariadb
● mariadb.service - MariaDB database server
Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
Active: failed (Result: timeout) since Tue 2018-07-10 01:20:10 JST; 36s ago
Main PID: 2404 (code=exited, status=0/SUCCESS)
Jul 10 01:18:38 localhost systemd[1]: Starting MariaDB database server...
Jul 10 01:18:38 localhost mysqld[2404]: 2018-07-10 1:18:38 139689982721152 [Note] /usr/sbin/mysqld (mysqld 10.1.29-MariaDB-6) starting as process 2404 ...
Jul 10 01:20:08 localhost systemd[1]: mariadb.service: Start operation timed out. Terminating.
Jul 10 01:20:10 localhost systemd[1]: mariadb.service: Failed with result 'timeout'.
Jul 10 01:20:10 localhost systemd[1]: Failed to start MariaDB database server.
timeoutしているようです。 しかしながら、mysqld[2404]: ...
から始まる行を見ると、どうやら起動できているようにも見えますが……?
接続してみる
systemctl start mariadb
を実行後、シェルが待機中に別のシェルからMariaDBに接続してみると、普通に接続できます。
$ mysql -u root
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 10.1.29-MariaDB-6 Ubuntu 18.04
Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
やはり、DBサーバーの起動自体はできているようですが、systemd
が起動に成功したことを検知できていないようです。
systemd unit定義の確認
systemdでプロセスを起動するための設定ファイルを確認してみます。 /lib/systemd/system/mariadb.service
にあります。
注目すべきは、以下の設定です。
[Service]
Type=notify
これは、sd_notifyを使ってプロセスの起動完了をsystemdへ通知する設定であることを表しています。 mariadbは起動できているのに、systemdがそれを認識していない、ということはどうやらこのsd_notify
が正しく送信されていないのではないか?と疑われます。
auditログ
sd_notify
はUNIXドメインソケット(/run/systemd/notify
)を介してsystemdに通知を送信しますが、パーミッションも特に問題なく、アクセスできそうですが……? 次に疑うのはSELinuxやAppArmorといった強制アクセス制御機能です。UbuntuはデフォルトでAppArmorが有効なので、怪しいです。
auditログを確認します
$ journalctl -n 1 _TRANSPORT=audit
Jul 10 01:42:59 localhost audit[3057]: AVC apparmor="DENIED" operation="sendmsg" info="Failed name lookup - disconnected path" error=-13 profile="/usr/sbin/mysqld" name="run/systemd/notify" pid=3057 comm="mysqld" requested_mask="w" denied_mask="w" fsuid=112 ouid=0
AppArmorによって、sd_notify
の送信が拒否されているのが発見できました。 ようやく尻尾を掴みましたね……
原因
mysql-server
をインストールすると、AppArmorプロファイルが同時にインストールされ、有効化されます。 このプロファイルは/etc/apparmor.d/usr.sbin.mysqld
に設置されます。
このプロファイルでは、限られたディレクトリへのアクセスのみを許可しており、sd_notify
で使うソケットへはアクセスできません。 しかしながら、mysql-server
では、プロセス起動検知にType=simple
を使用しているため、これは問題になりません。
mysql-server
をアンインストールし、mariadb-server
をインストールすると、/etc/apparmor.d/usr.sbin.mysqld
は空のファイルで上書きされますが、AppArmorがすでに読み込んでいるプロファイルは削除されません。 また、systemctl reload apparmor
しても、OSを再起動しても、一度読み込まれたプロファイルが勝手に削除されることはありません。
……なので、プロセス起動検知にType=notify
を使うmariadb-server
にもこのプロファイルが適用されてしまい、sd_notify
が失敗してsystemdがタイムアウトする、というオチでした。
解決法
Ubuntuでは、削除されたプロファイルをアンロードするコマンドaa-remove-unknown
が用意されています。 mariadb-server
をインストールした後、これを実行すれば良いです。
$ sudo aa-remove-unknown
Removing '/usr/sbin/mysqld'
コレで正常に起動できるようになります。
$ sudo systemctl start mariadb
$ sudo systemctl status mariadb
● mariadb.service - MariaDB database server
Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2018-07-10 01:55:56 JST; 15s ago
Main PID: 4753 (mysqld)
Status: "Taking your SQL requests now..."
Tasks: 27 (limit: 1112)
CGroup: /system.slice/mariadb.service
└─4753 /usr/sbin/mysqld
おしまい
traPで部内ISUCONをしていて、とりあえずmysqlを入れている人が多かったので、なんとなく**「mariadbに替えた方がいいよ!」**と言ったら起動できなくなる人が続出して阿鼻叫喚でした。
ICTSCみたいですね。
おわり。