systemdのめっちゃ嬉しい機能をダラダラと説明する
2018/06/07〜2018/06/08 あたりにtwitterでつぶやいたsystemdのうれしいシーンまとめ
Package管理と相性がよい
- sysvinitのスクリプトちょっといじってulimit文足したあとにパッケージupdateしたら消えたりしたことがある人はsystemdならその不幸はもう起きない
- systemdは設定ファイルが /usr, /etc, /run くらいにバラけて配置されるのでパッケージが提供するのをカスタマイズで変更するのは簡単にできるしパッケージシステムの更新などと相性もいい。
- バラバラだと作業が煩雑になりがちなので関連コマンドが充実
- パッケージのデフォルト、/etc/での設定、/run/の自動生成された設定などをまとめてunitを表示してくれる systemctl cat
- unitをカスタマイズするときに適切なファイルを編集してくれる systemctl edit などのコマンドも便利
- 現在の設定を評価してデフォルトからどう変更されたかをまとめて表示してくれる systemd-delta コマンドもあるよ。
sysvinit等でありがちだった罠にハマりにくい
- /etc/init.d/hoge を直接実行してserviceコマンド経由での起動時と環境変数やらが違うからハマった人、systemdならその不幸はもう起きない
- 同じサービスを1システム内で複数インスタンス構築してpidファイル被ったりログがどれがどれやら混乱したり、そういうことはsystemdをちゃんと使えば回避できる(残念ながら対応したパッケージは少ない)
- 設定ファイルのunit名を @で終わらせると複数インスタンスに対応。たとえばgetty@tty1.service というunitはtty1用のgettyで、仮想端末にあわせてgettyをいくつも作成する。この場合設定ファイルはgetty@.serviceになる。
- /etc/init.d以下のスクリプトがしれっとタイムアウトしてるくせにexit 0してて「フザケンナ」ってなったことがある人、残念ながらsystemdでも敢えてやればできちゃうけど普通の使い方ならちゃんと失敗したらnon zeroなexit code返すよ
- systemctl status で指定したunit(のどこかで)失敗が発生しているとexit codeがnon zeroになる
- systemdのunitではサービス実行前のチェック、サービス実行直前の準備コマンド、サービスそのもの、サービス実行直後に実行するコマンドなど細かくフェーズを分けてコマンドを記述できる。設定は面倒かもしれないが実際にどこかで失敗が発生したときにどのコマンドで問題が発生したか、exit codeは何かなどを細かくレポートしてくれて素敵。
Linuxの新しい機能などを上手くサポートしてくれる
- 一時ファイルを/tmpに作って置き換え可能なタイミングが発生する典型的なセキュリティホール作っちゃった人、systemdならそのサービス専用の/tmpをbind mountして分離する緩和策が1行書くだけで実施できるよ
- PrivateTmp=true と指定するだけ
- mount namespaceとbind mountを使ってunitに特有の/tmp を作ってくれる
- 他にもいろいろ制限をかける仕組みがあるので systemd.exec(5) のSandboxingを見るとよい
- 「linuxはcgroupでリソース制限かけてメモリ+swapの上限とか設定できる」それどうやって使うんだろうと思った人、systemdならサービス毎にcgroup作ってるから設定1行書くだけでできるよ
- MemoryMax=10G とか書く
- 詳しくは systemd.resource-control(5) にある
サービスの管理や追跡の機能が豊富 (いくつかはcgroup統合のおかげ)
- なぜか時々死ぬサービスを再起動するためにdaemontools入れたことある人、systemdならそれ最初からあるよ
- Restart=always とか。どういう条件でプロセス終了した場合に再起動するかなどをRestart=の設定で細かく指定できたり、再起動前の待ち時間をRestartSec=で指定できたりするよ。
- 「ん、このサービスいつ起動したっけ、先週月曜だっけ……?」ってログ漁ったことある人、systemdなら各サービス毎にいつ起動したかちゃんと覚えてるよ
- 謎のbashが動いてて「え、これ何から呼ばれてるの」と思ったけどpstreeで見たらinitの子になってて「なんだろー」ってなったことある人、systemdならどのサービスか、それともユーザーセッションから出てきたプロセスか即わかるよ
- "systemctl status" だけ打つと各サービスやユーザセッションとの関係もでてきます
- libvirtが起動するdnsmasqがサービス終了しても継続して動作してて、killall -9 dnsmasqしてNetworkManagerが呼んでる関係ないdnsmasqまで殺したことがある人、systemdならlibvirt関連の全プロセスだけを一発でkillできるよ
- "systemctl kill <サービス名>" で、 サービスに関連した全プロセスにkillを送れる
- systemdはサービス毎にcgroupで追跡してるから、「このサービスどのくらいメモリやCPUつかってるのかな」って思ったらsystemctl statusやるだけでわかるよ
systemctl statusの例。起動時刻、CPUおよびメモリ消費、関連プロセス、最近のログ10行などがまとめて表示される |
bus activationなどが素敵
- systemdは「ooがされたらxxを起動する」みたいな奴に色々(dbus, mount, デバイス, ファイル, socket等)対応してるから、cockpitみたいな「どこでも使えてほしいけど使わないときはリソース節約のため落ちていてほしい」サービスとかを設定しておくとリソースあまり使わずに待ちうけできるよ
- udevがsystemdと連携して動作するので検出されたデバイスを依存関係に簡単に書ける。特定のデバイスが存在する場合にだけ有益なbluetoothdとか、lvmで必要なサービスを非同期で起動させるとか、ストレージの暗号化などで大活躍。
systemdの管理と統合されたsystemd-journaldによるログ管理素敵
- 複数台の/var/log/messagesを見比べて「何で時間が秒単位なん!どっちが先か後かわからん! (>_<)」ってなったことがある人、systemd-journaldならマイクロ秒まで保持してるよ
- journalctl -o short-precise で時刻を細かくした出力が得られる
- トラブルシューティングでsyslogでためてるメッセージを解析する時に"warning"とかで検索してcriticalなメッセージ見逃したことがある人、systemd-journaldならログレベル保持してるからあらかじめ分けておかなくても「warn以上」とかですぐ絞りこめるよ
- journalctl -p 3 で error以上、など。
- 全然ログらしいの吐かないデーモンについて詳しい人に聞いたら「daemonizeさせずにforegroundで動かしてstderr見ればいいんだよ」とか言われて「そんなん知らんがな」と思ったことがある人、systemd + systemd-journaldならサービスのstdout,stderrもきっちりログに収集するよ
- systemdはサービス管理とロギングが統合されてるから journalctl -u サービス名 で特定のサービスに関連するプロセスが出したログだけ出してくれて便利。特に子プロセスの名前がメインのプロセスと違う時に見逃しがない。
- journaldはtimestampをUTCで保持しているのでシステムのTZに依存せず簡単にログを比較できるよ
- 各システムにユニークなmachine-idがついて、そのmachine-idのディレクトリにログが保存されるので複数システムのログを同じところにまとめやすいし、まとめたログファイル群をマージして読めるよ
- /var/log/journal/b1cb7fb826fe490da1e256a4300f4c2f/system.journal みたいなファイルになります
- machine-idは /etc/machine-id に保存されている。このファイルを削除して再起動するか systemd-machine-id-setup コマンドで作り直しされる。
こまかい便利機能
- systemdは競合するサービスをConflict=で明示的に定義できるからntpd動いてるのにchrony動かそうとすると実際に競合する前に検出して失敗してくれるよ
- systemd、電源断や再起動だけでなくサスペンドやハイバネートもやるよ
systemdに興味を持った人むけリンク
- systemd - Arch wiki
- #きょうのsystemd: (翻訳)PID 1 を考え直す systemdの作者Lennert のblog翻訳
- http://popopopoon.hatenadiary.jp/search?q=systemd 他にもいくつか翻訳なさっています