テックブログ

不正終了するApacheを自動で起動させる

はじめに

こんにちは、技術部のTUです!

Apacheが夜間に勝手に不正終了してしまう、コマンドで起動は出来るし設定も間違っていないに・・・
という事は無いでしょうか?

そんな時に役立つsystemdサービスの小技を紹介いたします。

Apache不正終了時の状況

実際に発生していたApacheの不正終了ですが、以下の様な状況でした。

・夜間のlogrotate、Reload発生のタイミングでApacheが停止する
・停止後でも手動でApacheの起動は可能
・セグメンテーション違反のエラーが出ているが、詳細が不明
・発生する状況は不定期で、数十回に一回程度で発生する

# systemctl status httpd
-------------------------------------------------------------
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since Sun 2023-09-17 03:01:45 JST; 18min ago
     Docs: man:httpd.service(8)
  Process: 52527 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited, status=1/FAILURE)
  Process: 52526 ExecReload=/usr/sbin/httpd $OPTIONS -k graceful (code=exited, status=0/SUCCESS)
  Process: 50022 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=killed, signal=ABRT)
 Main PID: 50022 (code=killed, signal=ABRT)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
-------------------------------------------------------------
# tail /var/log/httpd/error_log
-------------------------------------------------------------
[Sun Sep 17 03:01:45.273421 2023] [core:notice] [pid 50022] AH00060: seg fault or similar nasty error detected in the parent process
httpd: threads.c:xxx: xxxxxx: xxxxxxxx[xxxxxx] == 1' failed.
httpd: threads.c:xxx: xxxxxx: xxxxxxxx[xxxxxx] == 1' failed.
httpd: threads.c:xxx: xxxxxx: xxxxxxxx[xxxxxx] == 1' failed.
httpd: threads.c:xxx: xxxxxx: xxxxxxxx[xxxxxx] == 1' failed.
-------------------------------------------------------------

コアダンプを吐かせて調査して改善という事も出来ると思いますが、今回はsystemdサービスの機能を利用し、不正終了したApacheを蘇らせようと思います。

systemdサービス、Restart=で指定可能な値

systemdサービスのマニュアルを見てみると、systemdの操作以外でプロセスやサービスが終了した時に、Restart=で再起動動作の指定が出来ると記載があります。

Restart=
サービス・プロセスが終了したとき、強制終了されたとき、またはタイムアウトに達したときに、サービスを再起動するかどうかを設定します。
サービス・プロセスは、メインのサービス・プロセスである場合もありますが、ExecStartPre=、ExecStartPost=、ExecStop=、ExecStopPost=、またはExecReload=で指定されたプロセスの1つである場合もあります。
プロセスの死が systemd の操作(サービスの停止や再起動など)の結果である場合、サービスは再起動されません。
※DeepLでマニュアル一部を翻訳※

また更に読み進めると、Restart=で指定可能な値についても詳細な表が確認出来ます。

# LANG=C man systemd.service 
~略
Restart=
    Configures whether the service shall be restarted when the service process exits, is killed, or a timeout is reached. The service process may be
    the main service process, but it may also be one of the processes specified with ExecStartPre=, ExecStartPost=, ExecStop=, ExecStopPost=, or
    ExecReload=. When the death of the process is a result of systemd operation (e.g. service stop or restart), the service will not be restarted.
    Timeouts include missing the watchdog "keep-alive ping" deadline and a service start, reload, and stop operation timeouts.

    Takes one of no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, or always. If set to no (the default), the service will not be
    restarted. If set to on-success, it will be restarted only when the service process exits cleanly. In this context, a clean exit means any of the
    following:
~略
Table 2. Exit causes and the effect of the Restart= settings on them
+------------------+----+--------+------------+------------+-------------+----------+-------------+
|Restart           | no | always | on-success | on-failure | on-abnormal | on-abort | on-watchdog |
|settings/Exit     |    |        |            |            |             |          |             |
|causes            |    |        |            |            |             |          |             |
+------------------+----+--------+------------+------------+-------------+----------+-------------+
|Clean exit code   |    | X      | X          |            |             |          |             |
|or signal         |    |        |            |            |             |          |             |
+------------------+----+--------+------------+------------+-------------+----------+-------------+
|Unclean exit code |    | X      |            | X          |             |          |             |
+------------------+----+--------+------------+------------+-------------+----------+-------------+
|Unclean signal    |    | X      |            | X          | X           | X        |             |
+------------------+----+--------+------------+------------+-------------+----------+-------------+
|Timeout           |    | X      |            | X          | X           |          |             |
+------------------+----+--------+------------+------------+-------------+----------+-------------+
|Watchdog          |    | X      |            | X          | X           |          | X           |
+------------------+----+--------+------------+------------+-------------+----------+-------------+

自動起動させたくないならno、常に自動起動させるならalwaysとなる様です。

今回は不正終了以外の問題が出た際でも起動させたく、また万が一systemdで停止出来ない際にはkillで終了もさせたいので、on-failureを指定する事にします。

systemdスクリプト、追加設定の作り方

Apacheを制御するsystemdスクリプトはこんな内容になっています。
[Service]には、Restart=の指定が無い事が分かります。

# less /usr/lib/systemd/system/httpd.service
-------------------------------------------------------------
[Unit]
Description=The Apache HTTP Server
Wants=httpd-init.service
After=network.target remote-fs.target nss-lookup.target httpd-init.service
Documentation=man:httpd.service(8)

[Service]
Type=notify
Environment=LANG=C

ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
# Send SIGWINCH for graceful stop
KillSignal=SIGWINCH
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target
-------------------------------------------------------------

このスクリプトに直接Restart=を追記する事も出来ますが、パッケージの更新等で設定が上書きされる可能性もある為、追加設定を作成します。

# systemctl edit httpd
-------------------------------------------------------------
[Service]
Restart=on-failure
-------------------------------------------------------------

# cat /etc/systemd/system/httpd.service.d/override.conf
[Service]
Restart=on-failure

これで準備は整いました!

Apache不正終了の再現と動作確認

では早速、Apacheの不正終了を再現して動作確認をしてみます。
本来なら同じエラーを再現したいところですが、発生が不定期で確実な確認が出来ない事から、killコマンドでエラー時と同じシグナルを指定して再現を行います。

# systemctl status httpd
-------------------------------------------------------------
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/httpd.service.d
           mqoverride.conf
   Active: active (running) since Sun 2023-09-17 01:01:45 JST; 46min ago
     Docs: man:httpd.service(8)
 Main PID: 266140 (httpd)
-------------------------------------------------------------

今回発生した不正終了と同様、シグナルSIGABRT(プログラムの異常終了)を指定、Main PID をkillします。

# kill -s SIGABRT 266140

これでMain PIDの番号が変わり、Active状態が「active (running)」になっていたら成功です。

# systemctl status httpd
-------------------------------------------------------------
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/httpd.service.d
           mqoverride.conf
   Active: active (running) since Sun 2023-09-17 01:50:28 JST; 1s ago
     Docs: man:httpd.service(8)
 Main PID: 266629 (httpd)
-------------------------------------------------------------

再起動しています!想定通りの動きをしてくれた様です。

更に、通常の終了命令では起動しない事も見ておきます。
オプションをつけず、そのままMain PIDを終了させてみます。

# kill 266629 

# systemctl status httpd
-------------------------------------------------------------
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/httpd.service.d
           mqoverride.conf
   Active: inactive (dead)
     Docs: man:httpd.service(8)
-------------------------------------------------------------

想定通りActive状態が「inactive (dead)」に変わり、再起動せず終了してくれました。

最後に

systemdサービスの小技、いかがだったでしょうか。

同時に起動するサービスの指定や、サービスの起動順序も設定が出来たりと、他にもsystemdサービスでは様々な機能があるので、改めて記事にさせていただければと思っています。

それでは最後まで読んでいただき、ありがとうございました!

この記事をシェアする

  • facebook
  • twitter
  • hatena
  • line
URLとタイトルをコピーする

実績数30,000件!
サーバーやネットワークなど
ITインフラのことならネットアシストへ、
お気軽にご相談ください