systemdで特定のサービスと連動して他のプロセス・サービスを起動・停止させる

※2016/01/26 13:00
そもそも、systemdだったら依存関係についてAfterやBefore、Requestがあることに気づいた。こんな回りくどいことしなくてもよさそうなので、2016/01/27に追記・修正を行っている。


仕事で、特定のプロセスが落ちたら強制的にそのプロセスを前提として動作しているサービスも落とす必要が出てきたので、どうにか実現できないか調べてみた。
そしたらCentOS7で採用されているsystemdでは、プロセスの依存関係について記述出来るようなので、それで実現することにした。

基本的には、「.service」ファイルの[UNIT]項目に、以下の項目で依存関係のあるサービス名やターゲット名を記述する。

  1. Requires… ここで指定したUNITが動作していない場合、このUNITを起動させない。指定したUNITが停止した場合はこのUNITも停止させる。(並行起動させることができるので、通常は後述するBefore/Afterと組み合わせる)
  2. Conflicts… このUNITが動作中は、ここで指定したUNITは起動させない。起動している場合は停止処理を実施する。
  3. Wants… UNITが起動する際、ここで指定したUNITも起動させる(強制力なし)
  4. Before… このUNITが起動した後に、ここで指定したUNITを起動させる
  5. After… このUNITが起動する前に、ここで指定したUNITが起動されている必要がある
  6. Condition*… 指定した条件を満たした場合のみ起動する

これで、連動してサービスの起動・停止を実施できる。

対象のプロセスのデフォルトがGracefulの場合

対象のプロセスがスグ落ちるプロセスならいいんだけど、Gracefulで停止するプロセスの場合だとうまくいかない事がある。

そんな場合は、systemdでサービスを管理させるファイル「/usr/lib/systemd/system/サービス名.service」に、ExecStopPostとしてコマンドを記述する事で、異常終了を含むサービス停止時にそのコマンドを流す事が出来る。
つまり、この項目にkillコマンドを記述すればよい。

例えば、maxscale.service(上がってないといけないプロセス)に以下のように記述することで、プロセス停止時にhttpd(maxscaleを前提として動作するプロセス)サービスを停止させることが出来る。
(ここではsystemctlから停止させているけど、すぐにでも停止させるなら「kill -KILL $(pgrep プロセス名)」で指定したほうがいいこともある。状況に応じて使い分けるとよいだろう。)

●/usr/lib/systemd/system/maxscale.service

[Unit]
Description=MariaDB MaxScale Database Proxy
After=network.target

[Service]
Type=forking
Restart=on-failure
PIDFile=/var/run/maxscale/maxscale.pid
ExecStart=/usr/bin/maxscale --user=maxscale
ExecStopPost=/bin/sh -c 'systemctl stop httpd'

[Install]
WantedBy=multi-user.target

さて、それでは実際に動作をみてみよう。

[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
root     26540     1  0 18:12 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26541 26540  0 18:12 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26542 26540  0 18:12 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26543 26540  0 18:12 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26544 26540  0 18:12 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26545 26540  0 18:12 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
maxscale 26552     1  0 18:13 ?        00:00:00 /usr/bin/maxscale --user=maxscale
[root@localhost ~]#
[root@localhost ~]# kill $(pgrep maxscale)
[root@localhost ~]#
[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
[root@localhost ~]#

確かに、無事停止する事が出来た。
killで落としても動作するので、プロセスが落ちる等の障害時に使えるだろう。

ただ、一つ注意点が。。。

[root@localhost ~]# systemctl start httpd
[root@localhost ~]# systemctl start maxscale
[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
root     26748     1  1 18:19 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26749 26748  0 18:19 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26750 26748  0 18:19 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26751 26748  0 18:19 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26752 26748  0 18:19 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   26753 26748  0 18:19 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
maxscale 26760     1  2 18:19 ?        00:00:00 /usr/bin/maxscale --user=maxscale
[root@localhost ~]#
[root@localhost ~]# systemctl restart maxscale
[root@localhost ~]#
[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
maxscale 26795     1  1 18:20 ?        00:00:00 /usr/bin/maxscale --user=maxscale
[root@localhost ~]#

restartすると落ちます!
なので、必要ならば「ExecStartPost」でプロセス起動の記述も書いてあげると良いだろう。この辺は運用時のコマンドによると思うので環境に合わせて。

●/usr/lib/systemd/system/maxscale.service

[Unit]
Description=MariaDB MaxScale Database Proxy
After=network.target

[Service]
Type=forking
Restart=on-failure
PIDFile=/var/run/maxscale/maxscale.pid
ExecStart=/usr/bin/maxscale --user=maxscale
ExecStartPost=/bin/sh -c 'systemctl start httpd'
ExecStopPost=/bin/sh -c 'systemctl stop httpd'

[Install]
WantedBy=multi-user.target

[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
maxscale 27007     1  0 18:23 ?        00:00:00 /usr/bin/maxscale --user=maxscale
root     27009     1  1 18:23 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27013 27009  0 18:23 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27014 27009  0 18:23 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27015 27009  0 18:23 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27016 27009  0 18:23 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27017 27009  0 18:23 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
[root@localhost ~]#
[root@localhost ~]# systemctl stop maxscale
[root@localhost ~]#
[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
[root@localhost ~]#
[root@localhost ~]# systemctl start maxscale
[root@localhost ~]#
[root@localhost ~]# ps -ef | grep -e [h]ttpd -e [m]axscale
maxscale 27067     1  0 18:24 ?        00:00:00 /usr/bin/maxscale --user=maxscale
root     27069     1  1 18:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27072 27069  0 18:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27073 27069  0 18:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27075 27069  0 18:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27076 27069  0 18:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache   27077 27069  0 18:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND

…まぁ、停止させたいのがアプリケーションサーバ用のプロセスだったりして、LBとかが手前にいるんだったらヘルスチェックで対処させた方が良さそうな気もするけど。