systemd サービス mysqld.service の小ネタ紹介

目次

はじめに

今回は Linux システムにインストールした MySQL をサービスとして起動・停止管理する systemd にまつわる小ネタをご紹介します。

systemd が登場したころの一昔前は、 SysVinit ベース(一時 Upstart もありました)の OS との混在で mysqld サービスの起動や制御方法が異なるため、バージョンアップや運用で systemd そのものの理解や取り扱いに戸惑った方も多かったのではと思います。

現在は systemd ベースの OS が主流になっているかと思いますので systemctl コマンドもだいぶ浸透してきたのではないでしょうか。

systemd ベースへの RPM インストール時や systemd サービス mysqld.service の起動時の、あまり他では触れられていない内容を集めてみましたので、

『systemd を用いた MySQL Server の管理』に関しての基本的な内容は、公式マニュアルページに分かり易く書かれていますので、これから内容を知りたい方はまずは以下のリンクからご一読ください。

MySQL :: MySQL 8.4 Reference Manual :: 2.5.9 Managing MySQL Server with systemd

使用環境など

本記事は MySQL 8.4 LTS バージョンをメインに取り扱っていきます。

また、OS は Rocky Linux 8 (RHELディストリビューション) を使用しました。

RPM パッケージインストール時に実行される scriptlet の処理内容について

RPM にはパッケージのインストールや削除、アップグレードの前後でコードを実行することができる scriptlet という機能があります。

MySQL Server(mysql-community-server) のパッケージに仕込まれている scriptlet の処理内容を確認してみましょう。

  • ① パッケージインストール前に実行される処理です。

    • 起動プロセスやファイルのオーナとなる、mysql という名前のグループ・ユーザがここで作成されています。
    • グループIDとユーザIDは 27 でハードコードされています。
  • ② パッケージインストール後に実行される処理です。

    • /var/log/mysqld.log(エラーログファイル) が存在し無かったらファイルが作成されます。
    • scriptlet の第一引数は規定値になっていて、postinstall の場合、$1 == 1 ならインストールを意味しています。
    • systemctl preset コマンドでまずはベンダーデフォルトの自動起動設定を行っておいて、
      改めて systemctl enable コマンドを追加実行して、OS 起動時の自動起動を有効にしています。
  • ③ パッケージのアンインストール前に実行される処理です。

    • preuninstall の場合の第一引数ですが、$1 == 0 はアンインストールという意味です。
    • ここでは systemctl disable コマンドで OS 起動時の自動起動を無効にしています。
  • ④ パッケージのアンインストール後に実行される処理です。

    • postuninstall の場合の第一引数 $1 == 1 はアップグレードを意味しています。
    • systemctl try-restart は実行中なら再起動します(停止中の場合は何もしません)

というように、パッケージのインストール/アンインストール前後で上記の処理が行われているのでした。

これらの説明は実はマニュアルに記載はありますがあっさりとしてた説明になっています。

MySQL :: MySQL 8.4 Reference Manual :: 2.5.4 Installing MySQL on Linux Using RPM Packages from Oracle

The installation also creates a user named mysql and a group named mysql on the system.

(…)

If the operating system is systemd enabled, standard systemctl (or alternatively, service with the arguments reversed) commands such as stop, start, status, and restart should be used to manage the MySQL server service. The mysqld service is enabled by default, and it starts at system reboot. Notice that certain things might work differently on systemd platforms: for example, changing the location of the data directory might cause issues. See Section 2.5.9, “Managing MySQL Server with systemd” for additional information.

During an upgrade installation using RPM and DEB packages, if the MySQL server is running when the upgrade occurs then the MySQL server is stopped, the upgrade occurs, and the MySQL server is restarted. One exception: if the edition also changes during an upgrade (such as community to commercial, or vice-versa), then MySQL server is not restarted.

サービスの自動起動設定や OS の mysql ユーザーが作成されるタイミングやその設定内容が具体的になったかと思います。

systemd ユニットファイル内で実行される mysqld_pre_systemd の処理内容について

RPM パッケージをインストールすると、 MySQL Server 用の systemd ユニットファイルが以下の場所に配置されます。

mysqld.service はシングルインスタンス用、 mysqld@.service はマルチインスタンス用のユニットファイルです。

※マルチインスタンス構成については以下のマニュアルページをご参照ください。
MySQL :: MySQL 8.4 Reference Manual :: 2.5.9 Managing MySQL Server with systemd

ユニットファイルの中身を見てみましょう。

以下は今回説明する関連箇所の抜粋です。

ExecStart/usr/sbin/mysqld を実行しています。notify タイプのバックグラウンドサービスとして起動する設定です。

今回取り上げるポイントは ExecStartPre で設定されている /usr/bin/mysqld_pre_systemd スクリプトです。

ExecStartPre はその名の通り ExecStart を実行する前に実行するコマンドやスクリプトを設定します。

以下はマルチインスタンス用 (mysqld@.service) の設定ですが、インスタンス識別子が引数として渡される設定になっています。

mysqld_pre_systemd スクリプトで実行される内容も、実は公式マニュアルにさらっと記載があります。

MySQL :: MySQL 8.4 Reference Manual :: 2.5.4 Installing MySQL on Linux Using RPM Packages from Oracle

At the initial start up of the server, the following happens, given that the data directory of the server is empty:

  • The server is initialized.

  • An SSL certificate and key files are generated in the data directory.

  • validate_password is installed and enabled.

An SSL certificate and key files are generated in the data directory. については 8.4 からは削除されたのですが、ドキュメントがまだ直っていないようです。(これについては後述)

あとここの説明もですね。

MySQL :: MySQL 8.4 Reference Manual :: 2.5.9 Managing MySQL Server with systemd

For platforms that use systemd, the data directory is initialized if empty at server startup. This might be a problem if the data directory is a remote mount that has temporarily disappeared: The mount point would appear to be an empty data directory, which then would be initialized as a new data directory. To suppress this automatic initialization behavior, specify the following line in the /etc/sysconfig/mysql file (create the file if it does not exist):

今回はスクリプト自体を穿って見てみましょう。

※ソースコードの所在を載せておきます。
mysql-server/scripts/systemd/mysqld_pre_systemd.in at 8.4 · mysql/mysql-server · GitHub

説明の都合上、スクリプトの処理順に細切れに見ていきます。(左端はコード行番号)

install_db が引数付きで実行されます。
$1はマルチインスタンス用のユニットファイルから呼び出される場合はインスタンス識別子が渡されます。

まずは mysql_upgrade_history ファイルのオーナ設定(&SELinux有効時のコンテキスト一時変更)が行われます。

8.0 では mysql_upgrade_info というファイル名でした(8.0.17 で非推奨となりました)が、8.4 では mysql_upgrade_history という JSON形式のファイルでインストール情報が記録されるようになりました。

※インストール日などの情報が記録されています。

以下の部分は、前述のマニュアル記載の紹介にあった内容です。

/etc/sysconfig/mysql ファイルに NO_INIT=true と設定しておくと、このスクリプトの処理自体がここで終了します。(つまりこの処理をスキップするという意味です)

次に、データディレクトリとエラーログが作成されるパートになります。

get_option という関数で my_print_defaults ツールを使ってオプションファイル(my.cnfなど)からパラメータ値を取得します。

オプションファイルで datadirlog_error の指定がない場合は、デフォルト(/var/lib/mysql,/var/log/mysql.log)が作成されます。(いずれも存在し無い場合)

マルチインスタンスの場合は、インスタンス識別子がデータディレクトリ名やログファイル名のサフィックスに設定されるようになっています。

SELinux が有効な環境では作成したデータディレクトリとエラーログファイルにコンテキストの設定も行われています。

※MySQL の SELinux コンテキストについては弊社過去ブログ記事をご覧ください。
MySQLのSELinuxでエラーになった際の対処法4つ | スマートスタイル TECH BLOG

そして、ようやくデータディレクトリの初期化を行うセクションです。

ポイントとしては、既に {datadir}/mysql ディレクトリ、つまり データディレクトリ内に mysql システムデータベース用ディレクトリが存在する(既にデータディレクトリが初期化済みと見做す)場合は、再度初期化を行わず処理終了となります。

逆の見方をすると、{datadir}/mysql ディレクトリが無い場合はデータディレクトリの初期化が行われてしまうことになります。

なので、例えば以下のような都合によりこのスクリプトによるデータディレクトリの自動初期化が行われないようにしたい場合は、前述の NO_INIT=true/etc/sysconfig/mysql に設定しておいてスキップするのが役に立ちます。

  • データディレクトリの初期化を行う場合は手動で明示的に実施する運用ルールとしている
  • (マニュアルに記載の通り)一時的にデータディレクトリのマウントが外れてしまった状態で誤って自動的に初期化が行われないようにしたい、など。

そして、データディレクトリの初期化の際、validate_password コンポーネントが同時にインストールされます。

※インストールで一時的に生成するファイル名が昔の名残で plugin になっていますが…

初回起動を行う前に手動で mysqld --initialize を行ってしまった場合は、(必要に応じて)別途手動で validate_password コンポーネントをインストールしてください。

MySQL :: MySQL 8.4 Reference Manual :: 8.4.3.1 Password Validation Component Installation and Uninstallation

以上が mysqld_pre_systemd スクリプトの処理内容でした。

普段何気なく実行している systemd start mysqld コマンドは、実はこのようなスクリプトが(サービス起動前に)実行されるようになっていたのでした。

(そもそも ExecStartPre をオーバーライドするかコメントアウトなりでこのスクリプトを実行しないことも可能ですが…)

ちなみに 8.0 の mysqld_pre_systemd スクリプト にはデータディレクトリ初期化の後に SSL/RSA 証明書を生成するコードがありますが、8.4 では mysql_ssl_rsa_setup が廃止されました(※)ので該当コードは削除されています。

WL#16205: Remove the deprecated mysql_ssl_rsa_setup · mysql/mysql-server@b75bcb6 · GitHub

※詳細については、先日公開した以下の弊社ブログ記事をご一読ください。
MySQL 8.4 におけるSSL および RSA 証明書とキーの作成 | スマートスタイル TECH BLOG

MySQL 8.2 以降で強化された systemd 通知について

最後に、MySQL 8.2 で追加された機能の紹介です。

mysqld.servicenotify タイプのサービスとして起動されることを上述しました。

MySQL 8.2 (Innovation release) では、systemd 通知が強化され systemctl status mysqld.service を実行したときの詳細状況が表示されるようになりました。(勿論、それ以降のバージョンでも表示されます)

Oracle 社の以下ブログ記事で詳細がアナウンスされていますのでこちらをご一読いただくことをお勧めいたします。

MySQLのsystemd通知が機能強化されました | The Oracle MySQL Japan Blog
(※原文ページはこちら)

具体的にどこに表示されるかというと、下記出力の Status: "Server is operational" の箇所です。

Oracle社のブログ記事を元に、分かり易くまとめてみました。

青字が 8.2 以降で追加された通知メッセージになります。

ワークフロー 通知メッセージ
初期化中の通知 Server Initialization in progress
InnoDB Initialization in progress
InnoDB Initialization [unsuccessful/successful]
Initialization of MySQL system tables in progress
Initialization of MySQL system tables [unsuccessful/successful]
Execution of SQL Commands from Init-file in progress
Execution of SQL Commands from Init-file [unsucccessful/successful]
Server Initialization complete [1/0]
起動中の通知 Server startup in progress
InnoDB Initialization in progress
InnoDB Initialization [unsuccessful/successful]
InnoDB crash recovery in progress
InnoDB crash recovery [unsuccessful/successful]
Initialization of dynamic plugins in progress
Initialization of dynamic plugins [unsuccessful/successful]
Server upgrade in progress
Server upgrade complete
Components initialization in progress
Components initialization [unsuccessful/successful]
Server is operational
シャットダウン中の通知 Server shutdown in progress
Graceful shutdown of connections in progress
Shutdown of replica threads in progress
Forceful shutdown of connections in progress
Connection shutdown complete
Shutdown of plugins in progress
Shutdown of plugins complete
Shutdown of components in progress
Shutdown of components complete
Server shutdown complete

追加されたメッセージの数から分かる通り、非常に細やかな状態遷移を通知してくれるようになりました。

具体的なフローチャートが記事中で公開されていて分かり易いので、こちらも確認してみてください。

[ 引用:Enhancing systemd notifications in MySQL | The Oracle MySQL Blog]

そして、このステータスの遷移状況はエラーログにも記録されるようになりました。

本機能自体の有効化などの追加設定は不要ですが、 systemd 通知メッセージは INFOMATION レベル(Note) で出力されるので log_error_verbosity をデフォルトの 2 から 3 に変更する必要があります。

MySQL エラー番号 MY-013930 で出力されるようになります。以下は正常に起動した場合の出力内容です。

メッセージの先頭に systemd notify と付いていますので分かり易いです。

パフォーマンススキーマの error_log テーブルにも同一内容が記録されています。

デフォルトよりもログ出力量が多少増えてしまいますが、起動や停止が通常よりも時間がかかっている、なかなか終わらないような状況に陥ったときのようなトラブルシューティングに非常に有益な情報となります。
ログ監視しておくのも良いでしょう。

ちなみに…

標準バイナリ(tarball)パッケージでも以下の MySQL Secure Deployment Guide の手順に沿って systemd が利用可能なようにセットアップすることも可能ですが、

MySQL :: MySQL Secure Deployment Guide :: 5 Post Installation Setup

今回ご紹介した systemd 通知は、確認したところ標準バイナリパッケージでも表示されましたのでご安心ください。

まとめ

ちょっと細かい内容でしたが、意外と知っていると役立つかもしれない systemd mysqld サービスの小ネタ紹介でした。

インストール作業や運用で気になったときやトラブルシューティングのときなどに、ふと思い出してもらえたら幸いです。

スマートスタイルTECHブログについて

スマートスタイルTECHブログでは、日頃MySQLのサポート業務に従事している有資格者で構成された技術サポートチームがMySQLに関する技術情報を発信しています。データベースのお困りごとはお気軽にご相談下さい。

よかったらシェアしてね!
  • URLをコピーしました!
目次