#きょうのsystemd : サービスを停止させる (systemd for Administrators, Part 4)

概要

これは

0pointer.de

の翻訳。

サービスを停止させる

システムデーモンを停止させるのは簡単、本当?

確かに、デーモンが単一のプロセスで構成されている限り、これは確かにある程度は正しいだろう。 killall rsyslogdとタイプすれば、syslogデーモンはどこかへ行く。 しかし、このようにプロセスを止めるのはちょっと汚いやりかただ。 というのも、このように呼び出されることになったプロセスをこれはすべて停止させ、そこには偶然そのような名前を付けてしまった不幸なユーザーのプロセスも含まれるかもしれないからだ。 ほんの少し正しいバージョンは.pidファイルを読み込む方法で、例えば

kill `cat /var/run/syslogd.pid`

というものだ。 この時点ですでにかなり進むことができたが、それでもまだ、これが本当に我々のやりたいことなのだろうか?

多くの場合で、実際にはそうではない。 Apacheやcrondあるいはatdといったサービスを考えよう。これらはたいていの操作の一部として、子プロセスをスポーンさせる。 任意の、ユーザー設定可能な子サービスであり、例えば、cronやatのジョブ、CGIスクリプト、完全なアプリケーションサーバーといった場合もある。 apache、crond、atdのメインプロセスを停止させると、子プロセスも一緒に落ちるかもしれなければ、そうでないこともあり、残り続けるか停止するかはそれらのプロセス次第なのである。 基本的に、Apacheをターミネートさせることは、そのCGIスクリプトを残留させ、initの子として再割り当てをし、追跡を困難なものにするのである。

systemdはこれをレスキューする。 systemctl killであるサービスのすべてのプロセスに対し、簡単にシグナルを送ることができる。 例:

# systemctl kill crond.service

これはSIGTERMがcrondサービスのメインプロセスのみならず、すべてのプロセスに届けられることを保証する。 もちろん、望むなら違うシグナルを送ることも可能である。 例えば、あなたのお行儀が悪いなら、SIGKILLをすぐに送ってしまおうと思うだろう。

# systemctl kill -s SIGKILL crond.service

これで望み通りに、サービスが何回フォークしようと、ダブルフォークやフォークボミングで監視下から逃れようと、サービスはその全体が虐殺される。

ときどき、サービスのメインプロセスに特定のシグナルを送ることだけが必要となることがある。例えば、SIGHUP経由でリロードをトリガーしたいといった理由によるものだ。 PIDファイル経由でおこなう代わりに、もっと簡単な方法がある。

# systemctl kill -s HUP --kill-who=main crond.service

そして再び、systemdでサービスを停止させることについて何がそんなに新しくてファンシーなのか? Linuxで初めて、我々がそれを実際、適切におこなうことができている。 以前のソリューションは常にデーモン頼みであり、デーモンが自分自身がターミネートするときに自分がスポーンしたすべてのものを停止させるよう実際に協力してくれるかに頼っていた。 しかし、普通、SIGTERMやSIGKILLを使いたい場合に、そのようにすることになる。それはデーモンが実際に適切に協力してくれないからなのだ。

これがsystemctl stopとどのように関係してくるのか? killはグループにあるすべてのプロセスに直行し、シグナルを送る。 しかし、stopはサービスをシャットダウンする公式の設定を通過する。例えば、サービスファイルのExecStop=で設定された停止コマンドを実行する。 通常はstopで十分なはずである。 killはより荒っぽいバージョンであり、実行するサービスの公式のシャットダウンコマンドを使いたくなかったり、サービスを他の方法できれいにしたりハングさせたりする場合に使われる。

(ところで、人に寄ってはSIGプレフィックスを-sスイッチに付けたり付けなかったりするが、どちらでも動く。)

Linuxでサービスを適切に停止させる方法なしでここまでやってきたのにはちょっと驚く。 systemdはこれを適切におこなうことを、初めて可能にするものなのである。