daemontools管理サービスに対してTERMシグナルが効かなくなった時の対応

Overview

  • TERMシグナル を送ってもpidが変わらない場合は、Killシグナルをpidに送ってプロセス自体を落とす。
  • サービス自体はdaemontoolsで管理しているためkillされたサービスは自動で上げてくれるため再起動となる。

内容

daemontoolsに対してTERMシグナルを送っても効かなかったためその対応の記録です。

strace コマンドを利用し、特定プロセスのシステムコールレベルの処理をトレースしてみる

# strace -p 18043
Process 18043 attached - interrupt to quit
clock_gettime(CLOCK_MONOTONIC, {21942263, 214411873}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942263, 214454654}) = 0
epoll_wait(17, {}, 64, 9)               = 0
clock_gettime(CLOCK_MONOTONIC, {21942263, 223633781}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942263, 223668174}) = 0
epoll_wait(17, {}, 64, 1)               = 0
clock_gettime(CLOCK_MONOTONIC, {21942263, 224836558}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942263, 224875851}) = 0
epoll_wait(17, {}, 64, 999)             = 0
clock_gettime(CLOCK_MONOTONIC, {21942264, 225003708}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942264, 225060544}) = 0
epoll_wait(17, {}, 64, 999)             = 0
clock_gettime(CLOCK_MONOTONIC, {21942265, 225225110}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942265, 225266000}) = 0
epoll_wait(17, {}, 64, 999)             = 0
clock_gettime(CLOCK_MONOTONIC, {21942266, 225429915}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942266, 225469449}) = 0
epoll_wait(17, {}, 64, 998)             = 0
clock_gettime(CLOCK_MONOTONIC, {21942267, 224646569}) = 0
clock_gettime(CLOCK_MONOTONIC, {21942267, 224699790}) = 0
futex(0x7ff830810644, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7ff830810640, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x7ff83081067c, FUTEX_WAIT_PRIVATE, 5703703, NULL) = -1 EAGAIN (Resource temporarily unavailable)
write(6, "!", 1)                        = 1

EAGAIN (Resource temporarily unavailable) なので、システムのプロセステーブルが多くなり fork(2) システムコールが失敗した、あるいはメモリーまたはスワップ空間が足りないためにシステムコールが失敗した可能性が高い。 svc -du を行なったも同様の結果になる。

そのためTERMシグナルを送ってもpidが同様の場合は、daemontools管理のサービスpidを終了させる対応を入れる。

対象サービスは親プロセスに紐づいて子プロセスがいる。

$ pstree -A
init-+-abrtd
        |-svscanboot(1681)-+-readproctitle(1713)
        |                                 |-supervise(1724)---ruby(26456)-+-ruby(26473)-+-{ruby}(26475)
        |                                 |                               |             |-{ruby}(26483)
        |                                 |                               |             |-{ruby}(26485)
        |                                 |                               |             |-{ruby}(26487)
        |                                 |                               |             `-{ruby}(27879)
        |                                 |                               `-{ruby}(26474)

親プロセス(26456) だけをkillすると子プロセスがゾンビ化してしまう。

$ kill -9 26456
$ pstree -A
  |-ruby(26473)-+-{ruby}(26475)
        |             |-{ruby}(26483)
        |             |-{ruby}(26485)
        |             |-{ruby}(26487)
        |             `-{ruby}(27879)

親プロセスと子プロセスを一括で終了してくれるコマンドを探してみたが良さそうなのは見つけられなかった。

morningcoffee.io

kill -SIGTERM -- -<PID>

=> 子は死なずにゾンビプロセスとなる。ルートに移行されるので利用できない。

pgrep を利用すると子プロセス一覧を取得できるため

$ sudo ps auxf | grep fluentd
root      1724  0.0  0.0   3992   476 ?        S    Jun17   0:01  |   \_ supervise fluentd-audit
root     11923  0.4  0.6 103484 23944 ?        Sl   13:51   0:00  |   |   \_ /opt/td-agent/embedded/bin/ruby /usr/sbin/td-agent --use-v1-config -c /data/daemon/fluentd-audit/td-agent.conf -p /data/daemon/fluentd-audit/plugin
root     11944  0.9  1.2 188112 51708 ?        Sl   13:51   0:00  |   |       \_ /opt/td-agent/embedded/bin/ruby /usr/sbin/td-agent --use-v1-config -c /data/daemon/fluentd-audit/td-agent.conf -p /data/daemon/fluentd-audit/plugin
root    12560  0.0  0.0 103304  1992 pts/1    S+   13:52   0:00              \_ grep fluentd

親プロセスから子プロセス一覧を取得(pgrep -P <親プロセス>)させ、svc -t でも子プロセスが死なない場合は、子プロセスをkillする実装方針でコーディングを行い対応した。