Debian系で標準インストールされるパッケージ自動更新サービスであるunattended-upgradesが電源断を遅延させる問題に遭遇しそれを解決しました。それについて発見に至った経緯や対応について記したいと思います。
発見に至る経緯
弊社ではGCEのSpotVMを扱っており、VMがプリエンプティブ(強制停止)される際にシグナルを適切に処理しアプリケーションが安全に停止できるようにしています。
具体的には以下のような流れで停止シグナルを処理します。(OSはubuntu-minimal-2204です。)
- 停止シグナル(ACPI G2信号)を受信
- logindが電源断(poweroff)を実行
- google-shutdown-scripts.serviceがシャットダウンスクリプトを起動
google-shutdown-scripts.serviceはGCE Agentが用意するsystemdサービスです。 - アプリケーションが必要なクリーンアップ処理を実行
クリーンアップ処理完了後メール通知しています。
GCEの仕様では、停止シグナル送信後最大30秒以内に停止しなければ、VMは強制停止されます。つまり30秒以内にアプリケーションを停止する必要があります。
しかし先日、プリエンプティブされたにも関わらずクリーンアップ完了メールが届かないことがあることに気づきました。ログを確認するとシャットダウンスクリプト起動の行がない。シャットダウンスクリプト起動していない?あるいはその部分がアップロードされていない?いずれにしても正しくクリーンアップが行われていないケースがあるようでした。
30秒の遅延を発見
いろいろ調査・試行錯誤の後、VMを手動で強制停止してシミュレートしてみるとsyslogに以下のようなログが記録されました。
Oct 15 10:14:34 worker-qd9w systemd-logind[677]: Power key pressed.
Oct 15 10:14:34 worker-qd9w systemd-logind[677]: Powering Off...
Oct 15 10:15:04 worker-qd9w systemd-logind[677]: Delay lock is active (UID 0/root, PID 472/unattended-upgr) but inhibitor timeout is reached.
Oct 15 10:15:04 worker-qd9w systemd-logind[677]: System is powering down.
電源断イベントが発生してから電源断処理が始まるまでになにかロック待ちのようなもので30秒かかっています。なんだこの30秒は。ロック待ちで30秒かかりシャットダウンスクリプトの起動が遅れているとすれば、強制停止まで30秒という期限がある中でこれは致命的な30秒です。
抑制ロックとは
そもそもlogindのDelay lockとはなにか。これは「抑制ロック」といいシステムのシャットダウンやスリープを抑止するための仕組みらしいです。たとえばパッケージのインストール中に電源断をさせないようにするために利用されるようです。詳細は Inhibitor Locksを参照ください。
抑制ロックには2つのロックモードがありDelay lockはその一つでロック取得中に一定期間まで電源断等の操作を遅延させることができます。
Delay lockの最大遅延時間はlogind.confの InhibitDelayMaxSecで設定できます。この既定値は5秒です。
unattended-upgradesとは
この抑制ロックを取得していたunattended-upgrとはなにか。これはDebian系で標準インストールされるパッケージ自動更新サービスで、パッケージの新しいバージョンを自動インストールするためのサービスです。詳細は PeriodicUpdatesを参照ください。
問題の原因
抑制ロックとunattended-upgradesの理解が深まると今回の遅延の原因が明らかになりました。
まずunattended-upgradesがなぜか常に起動しており、抑制ロックを取得し続けています。抑制ロックの取得状況はsystemd-inhibit --list
で確認できます。さらにunattended-upgradesは/usr/lib/systemd/logind.conf.d/unattended-upgrades-logind-maxdelay.conf
ファイルを配置しInhibitDelayMaxSecを30秒に上書きしています。
これによりlogindで電源断が発生してもunattended-upgradesにより抑制ロックが取得中であるため電源断操作を遅延することになります。最終的に30秒でタイムアウトし電源断操作が続行します。これが今回の遅延の原因です。
クリーンアップ処理が完了するケースとしないケースがあるのはその時のアプリケーションの負荷状況による可能性があります。アイドル状態のときはほぼ瞬時にクリーンアップが終わるため正常終了し、そうでないときは最後まで処理できず強制停止していたと考えられます。
unattended-upgradesの問題点
原因が判明するとともにunattended-upgradesの問題点が見えてきました。
問題点1) パッケージ更新中でないにも関わらず抑制ロックを取得し続ける
unattended-upgradesのプロセスは常に起動しているように見えます。詳しい調査は行っていませんが何らかの理由で長時間起動しており抑制ロックを取得し続けたままになっています。今回は必要がないため調査しませんが、原因が何であれ、この動作自体が行儀のよいものではありません。印象はよくないです。
問題点2) logindの設定ファイル名が作法に則っていない
logindの設定ファイルはファイル名によって優先順が決まります。後の方が優先度が高いです。つまりa.conf
よりもz.conf
のほうが優先度が高いということになります。
unattended-upgradesはunattended-upgrades-logind-maxdelay.conf
のファイル名で設定ファイルを配置します。これはlogindの以下の作法に従っていません。
When packages need to customize the configuration, they can install drop-ins under /usr/. Files in /etc/ are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. Drop-ins have to be used to override package drop-ins, since the main configuration file has lower precedence. It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering. This also defines a concept of drop-in priorities to allow OS vendors to ship drop-ins within a specific range lower than the range used by users. This should lower the risk of package drop-ins overriding accidentally drop-ins defined by users. It is recommended to use the range 10-40 for drop-ins in /usr/ and the range 60-90 for drop-ins in /etc/ and /run/, to make sure that local and transient drop-ins take priority over drop-ins shipped by the OS vendor.
https://www.freedesktop.org/software/systemd/man/latest/logind.conf.html より引用
本来であれば10-unattended-upgrades-logind-maxdelay.conf
などとすべきです。しかしそうなっていないために作法に従っている他の設定ファイルよりも優先するようなファイル名になっています。印象よくないです。
対応
このようにunattended-upgradesの影響で電源断が遅延することが分かりました。
対応としては今回のVMは長期間稼働し続けるVMではないため、そもそもパッケージ自動更新サービスは必要ないことからunattended-upgradesをアンインストールすることにしました。
具体的にはVM開始時に以下コマンドを実行します。
systemctl stop unattended-upgrades
apt-get purge -y unattended-upgrades
ヒント
unattended-upgradesアンインストール後にaptで何かのパッケージをインストールするとSuggestで再度unattended-upgradesがインストールされてしまうことがあるため、アンインストールはすべてのパッケージをインストールした後に行うようにしたほうがよいです。
所感
原因が分かるとそうなのかという感じですが、分かる前はそもそも電源断シグナルが来ていないとかの可能性も考えたり、logindや抑制ロックについて理解する必要があったり時間が取られました。
この問題はSpotVMとDebian系OSというかなりメジャーな組み合わせで問題になる可能性が高いので、GCEの公式ドキュメントに記載してよいレベルの話だと思う。
あとMinimal Ubuntuにパッケージ自動更新サービスは必要ないのでは?と思う。