systemd経由でのmackerel-agentのrestart時の挙動を調べた
About
mackerel-agentのinitファイルを見てて??ってなったので、わかる範囲で調べました。間違っているところあればぜひご教示いただきたいです。
環境
経緯
mackerelをAutoScaling環境に導入するときには/etc/sysconfig/mackerel-agent内の設定でAUTO_RETIREMENT=1を設定すればサーバ停止時に退役処理が走るという挙動になっています。
この設定をした際にはstop時に退役処理が走ってしまうので、reloadを使うようにというようにドキュメントに記載があります。
エージェントをstop/startさせたい場合には、 /etc/init.d/mackerel-agent reload を使うようにして下さい。
https://mackerel.io/ja/docs/entry/howto/auto-scaling
じゃあrestart時はどうなるんだろう?と思ったわけです。
起動・停止スクリプトを確認する
mackerelのコードを見るとsysVinitのinitスクリプトが用意されていたので、現在の最新バージョンで確認すると下記のようになっています。
...
retire() {
echo -n $"Retiring the Host:"
$BIN retire -force ${APIBASE:+--apibase=$APIBASE} ${APIKEY:+--apikey=$APIKEY} --root=$ROOT $OTHER_OPTS >>$LOGFILE 2>&1
retval=$?
if [ $retval -ne 0 ]; then
failure
echo
return $retval
fi
success
echo
}
...
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
retval=$?
[ "$AUTO_RETIREMENT" != "" ] && [ "$AUTO_RETIREMENT" != "0" ] && retire
exit $retval
;;
reload)
configtest_q || exit 1
restart
;;
restart)
$1
;;
status)
rh_status
;;
configtest)
configtest
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status|configtest}"
exit 2
esac
退役の処理はretire()というfunctionで定義されており、上記スクリプトを見るとAUTO_RETIREMENTが設定されているかつ、stopが呼ばれた場合のみ実行されるようです。あれ?restart時に退役したような覚えあるぞ...?
挙動の確認
initスクリプトさらっとみる限り退役はしないんじゃないかな?と思ったので詳しく調べました。
確認方法は/var/lib/mackerel-agent/idというファイルを見て、ここのidが変化するかとしています。変化していなければ退役しない、変化していれば退役すると判断しています。
# /etc/init.d/mackerel-agent restart # /etc/init.d/mackerel-agent reload
- reload 退役しない
- restart 退役する
やはり退役してしまっている。。。うーんということで更に調べます。
initのスクリプトの問題?
/etc/init.d/mackerel-agentのファイルをいろいろ弄ったりしてみましたがよくわからずでした。case文のところでrestartの定義を消しても動いたので、systemd経由でのスクリプト実行が想定と違うのかなと思い始めました。
initスクリプトを眺める
/etc/init.d/mackerel-agentを確認すると外部ファイルを参照しています。
# Source function library. . /etc/rc.d/init.d/functions
その中身を見ると、centos7では$SYSTEMCTL_SKIP_REDIRECTが空の場合はsystemdでコマンドを実行するようになるようです。
if [ $PPID -ne 1 -a -z "$SYSTEMCTL_SKIP_REDIRECT" ] && \
( /bin/mountpoint -q /cgroup/systemd || /bin/mountpoint -q /sys/fs/cgroup/systemd ) ; then
case "$0" in
/etc/init.d/*|/etc/rc.d/init.d/*)
_use_systemctl=1
;;
esac
fi
systemctl_redirect () {
...
}
if [ "$_use_systemctl" = "1" ]; then
if [ "x$1" = xstart -o \
"x$1" = xstop -o \
"x$1" = xrestart -o \
"x$1" = xreload -o \
"x$1" = xtry-restart -o \
"x$1" = xforce-reload -o \
"x$1" = xcondrestart ] ; then
systemctl_redirect $0 $1
exit $?
fi
fi
実際に変数を指定してrestartしてみます。
# systemctl restart mackerel-agent -> 退役する # service mackerel-agent restart -> 退役する # /etc/init.d/mackerel-agent restart -> 退役する # SYSTEMCTL_SKIP_REDIRECT=1 service mackerel-agent restart -> 退役しない # SYSTEMCTL_SKIP_REDIRECT=1 /etc/init.d/mackerel-agent restart -> 退役しない
systemdを経由しないように実行すれば退役処理が走らなくなりました。どうやらsystemdを経由すると動作が変わるっぽいことが確認できました。
systemdでsysVinitのファイルの取扱
この時点まででsystemdを使わない場合と使う場合の挙動の違いは、前者の場合はrestartがcase文に渡されていて、後者の場合はstop,startがそれぞれ1回ずつ呼ばれているのではという仮説を立てていました。
なので、systemd経由の場合は何らかのunitファイルがスクリプトを呼び出しているはず、、、と調べていてsystemd-sysv-generatorの存在を知りました。
/lib/systemd/system-generators/systemd-sysv-generator
これを使って動的にがunitファイルに変換された結果が下記です。
[vagrant@localhost ~]$ cat /run/systemd/generator.late/mackerel-agent.service # Automatically generated by systemd-sysv-generator [Unit] Documentation=man:systemd-sysv-generator(8) SourcePath=/etc/rc.d/init.d/mackerel-agent Description=LSB: start and stop mackerel-agent Before=runlevel2.target Before=runlevel3.target Before=runlevel4.target Before=runlevel5.target Before=shutdown.target After=network-online.target Conflicts=shutdown.target [Service] Type=forking Restart=no TimeoutSec=5min IgnoreSIGPIPE=no KillMode=process GuessMainPID=no RemainAfterExit=yes ExecStart=/etc/rc.d/init.d/mackerel-agent start ExecStop=/etc/rc.d/init.d/mackerel-agent stop ExecReload=/etc/rc.d/init.d/mackerel-agent reload
自動で生成されたっぽいコメントある!ということでこのファイルからinitスクリプトが実行されていたようです。このファイルのgenerateタイミングはわかってないですが、起動時にどこかのタイミングで呼ばれてるんでしょうか。
従ってcentos7では/etc/init.d/mackerel-agent restartを実行したとしても、initスクリプト内のrestartが実行されているのではなく、ExecStop -> ExecStartが実行されていると思われます。
まとめ
systemdは奥が深いですね。。。多少は理解が少し進んだ気がします!あんまりmackerel関係なかったかもしれない。ちなみにコンソールでrootを使っているのは変数周りが面倒だったからです。