tjinjin's blog

インフラ要素多めの個人メモ

systemd経由でのmackerel-agentのrestart時の挙動を調べた

About

mackerel-agentのinitファイルを見てて??ってなったので、わかる範囲で調べました。間違っているところあればぜひご教示いただきたいです。

環境

  • centos 7.3.1611(VM
  • mackerel-agent 0.39.2

経緯

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

github.com

退役の処理は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を使っているのは変数周りが面倒だったからです。

参考