うおの知識倉庫

ゆるーくアウトプットしてます。

systemdにサービス登録したときの備忘録

概要

CTFdの自動起動のため、systemdにサービス登録した際に若干困った話。

CTFdについて github.com

※経過を書いているので、参考にしたい際はこの記事の最後まで読んで参考にした方がいいかもです。

目次

言いたいこと

serviceファイルの[Service]"WorkingDirectory"の項目に実行ディレクトリを指定しても、[Service]"ExecStart"の項目に相対パスでのファイル指定は出来ないぞい

うまくActiveに出来たファイル

ファイル名: hoge.service

[Unit]
Description = hoge daemon    #サービスの説明文です。内容は自由です。systemctl statusで見た際に1行目のサービス名の横に出る文章。

[Service]
User = hogeuser    #スクリプト実行時のユーザを指定します。
Group = hogeuser    #スクリプト実行時のグループを指定します。(必須ではない)
WorkingDirectory = /home/hogeuser/CTFd/    #スクリプト実行時の環境変数を記述したファイルのパスです。
ExecStart = /home/hogeuser/CTFd/serve.py     #systemctl start [サービス名] を実行すると、ここに設定されたスクリプトをsystemdが実行します。
Restart = always    #サービスが停止した際の動作を指定します。alwaysで常に再起動を実施します。
Type = simple    #起動完了の判定方法です。simpleでコマンド実行時に起動完了と判断します。simple(フォアグラウンド処理。)、forking(起動後バックグラウンド処理)。

[Install]
WantedBy = multi-user.target    #enableでスタートアップ(?)に登録するときのrunlevel。(runlevel 5)

やったこと

まずはこちらのサイトを参考にserviceファイルを作ってみた。

[CentOS7] systemdにサービスを登録して、サーバ起動時に自動でサービスを立ち上げる – RE:ENGINES

以下抜粋

[Unit]
# サービスの説明文です。内容は自由です。
Description = puma as service
 
[Service]
# スクリプト実行時のユーザを指定します。
User = testuser
# スクリプト実行時の環境変数を記述したファイルのパスです。次項で説明します。
EnvironmentFile=/etc/systemd/env
# systemctl start [サービス名] を実行すると、ここに設定されたスクリプトをsystemdが実行します。
ExecStart = /home/testuser/puma.sh
# サービスが停止した際の動作を指定します。alwaysで常に再起動を実施します。
Restart = always
# 起動完了の判定方法です。simpleでコマンド実行時に起動完了と判断します。
Type = simple
 
[Install]
WantedBy=multi-user.target

この項目だけの記載では

$ sudo systemctl daemon-reload
$ sudo systemctl stop hoge
$ sudo systemctl start hoge
$ sudo systemctl status hoge

とした時、

* hoge.service - hoge daemon
   Loaded: loaded (/etc/systemd/system/hoge.service; enabled; vendor preset: enabled)
   Active: failed (Result: start-limit-hit) since Thu 2019-06-20 09:52:06 JST; 6s ago
  Process: 2979 ExecStart=/home/hoge/CTFd/serve.py (code=exited, status=1/FAILURE)
 Main PID: 2979 (code=exited, status=1/FAILURE)


Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Main process exited, code=exited, status=1/FAILURE
Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Unit entered failed state.
Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Failed with result 'exit-code'.
Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Service hold-off time over, scheduling restart.
Jun 20 09:52:06 ctfd systemd[1]: Stopped hoge daemon.
Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Start request repeated too quickly.
Jun 20 09:52:06 ctfd systemd[1]: Failed to start hoge daemon.
Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Unit entered failed state.
Jun 20 09:52:06 ctfd systemd[1]: hoge.service: Failed with result 'start-limit-hit'.

のようなエラーが出力されるので、 別のサイトとも組み合わせてみる。

いい感じの記事 qiita.com を見つけたので、組み合わせる。

以下抜粋 ※【】はコメントです

# original write【コメント行なので適当です】

[Unit]
Documentation=man:systemd-sysv-generator(8)   【systemctl statusで見た際にDocs: で表示される文章】
Description=Celery Service   【systemctl statusで見た際に1行目のサービス名の横に出る文章】
After=network.target 【このサービス起動時に事前にnetwork.targetが起動中であることを確認(Networkが上がってないとだめ。)】

[Service]
User=celery    【サービスを起動するユーザの指定】
Group=celery  【サービスを起動するグループの指定】
WorkingDirectory=/var/www/celery 【実行ディレクトリの指定】
Type=forking 【Type=simple(フォアグラウンド処理。)、forking(起動後バックグラウンド処理)】
Restart=no
TimeoutSec=5min
IgnoreSIGPIPE=no
KillMode=process
GuessMainPID=no
RemainAfterExit=yes
ExecStart=/usr/local/bin/celery multi start w1 -A celery -l info --time-limit=300 --concurrency=8 --pidfile=/var/run/celery/%n.pid --logfile=/var/log/celery/%n.log 【起動コマンド】
ExecStop=/usr/local/bin/celery multi stopwait w1 --pidfile=/var/run/celery/%n.pid 【停止コマンド】
ExecReload=/usr/local/bin/celery multi restart w1 -A celery -l info --time-limit=300 --concurrency=8 --pidfile=/var/run/celery/%n.pid --logfile=/var/log/celery/%n.log 【restart時のコマンド】

[Install]
WantedBy=multi-user.target 【enableでスタートアップ(?)に登録するときのrunlevel。(runlevel 5)】

この設定を反映したつもりが、実行に失敗した。 失敗したファイル名: hoge.service ExecStartの指定方法が間違っていた。相対パスではなく絶対パスで書く必要がある。

[Unit]
Description = hoge daemon    #サービスの説明文です。内容は自由です。systemctl statusで見た際に1行目のサービス名の横に出る文章。

[Service]
User = hogeuser
Group = hogeuser
WorkingDirectory = /home/hogeuser/CTFd/
ExecStart = ./serve.py     # ←この指定方法が間違い。ここは相対パスではなく、絶対パスで書く必要がある。
Restart = always
Type = simple

[Install]
WantedBy = multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl stop hoge
$ sudo systemctl start hoge
$ sudo systemctl status hoge

を実行すると、

sudo: unable to resolve host ctfd
* hoge.service - hoge daemon
   Loaded: error (Reason: Invalid argument)
   Active: inactive (dead) since Thu 2019-06-20 10:56:20 JST; 10s ago
 Main PID: 3072 (code=exited, status=0/SUCCESS)

Jun 20 10:11:27 ctfd serve.py[3072]:  * Debugger PIN: 170-688-146
Jun 20 10:55:01 ctfd systemd[1]: [/etc/systemd/system/hoge.service:8] Executable path is not absolute, ignoring: ./
Jun 20 10:55:01 ctfd systemd[1]: hoge.service: Service lacks both ExecStart= and ExecStop= setting. Refusing.
Jun 20 10:56:12 ctfd systemd[1]: [/etc/systemd/system/hoge.service:8] Executable path is not absolute, ignoring: ./
Jun 20 10:56:12 ctfd systemd[1]: hoge.service: Service lacks both ExecStart= and ExecStop= setting. Refusing.
Jun 20 10:56:20 ctfd systemd[1]: Stopping hoge daemon...
Jun 20 10:56:20 ctfd serve.py[3072]:  * Loaded module, <module 'CTFd.plugins.challenges' from '/home/hogeuser/CT
Jun 20 10:56:20 ctfd serve.py[3072]:  * Loaded module, <module 'CTFd.plugins.dynamic_challenges' from '/home/hogeuser/
Jun 20 10:56:20 ctfd serve.py[3072]:  * Loaded module, <module 'CTFd.plugins.flags' from '/home/hogeuser/CTFd/CT
Jun 20 10:56:20 ctfd systemd[1]: Stopped hoge daemon.

の様にエラーが吐かれる。 先のファイルを修正すると

* hoge.service - hoge daemon
   Loaded: loaded (/etc/systemd/system/hoge.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2019-06-20 11:05:12 JST; 15s ago
 Main PID: 3264 (serve.py)
   CGroup: /system.slice/hoge.service
           |-3264 /usr/bin/python /home/hogeuser/CTFd/serve.py
           `-3269 /usr/bin/python /home/hogeuser/CTFd/serve.py

Jun 20 11:05:13 ctfd serve.py[3264]:  * Loaded module, <module 'CTFd.plugins.challenges' from '/home/hogeuser/CT
Jun 20 11:05:13 ctfd serve.py[3264]:  * Loaded module, <module 'CTFd.plugins.dynamic_challenges' from '/home/hogeuser/
Jun 20 11:05:13 ctfd serve.py[3264]:  * Loaded module, <module 'CTFd.plugins.flags' from '/home/hogeuser/CTFd/CT
Jun 20 11:05:13 ctfd serve.py[3264]:  * Serving Flask app "CTFd" (lazy loading)
Jun 20 11:05:13 ctfd serve.py[3264]:  * Environment: development
Jun 20 11:05:13 ctfd serve.py[3264]:  * Debug mode: on
Jun 20 11:05:13 ctfd serve.py[3264]:  * Running on http://0.0.0.0:4000/ (Press CTRL+C to quit)
Jun 20 11:05:13 ctfd serve.py[3264]:  * Restarting with stat
Jun 20 11:05:14 ctfd serve.py[3264]:  * Debugger is active!
Jun 20 11:05:14 ctfd serve.py[3264]:  * Debugger PIN: 170-688-146

という具合に正常に起動できる。

まとめ

エラーログ大事。

答えられる範囲であれば答えますので、質問などや間違ってるよ!等があればコメントにお書きください。

参考になった記事様

qiita.com

https://re-engines.com/2018/07/23/centos7-systemd%E3%81%AB%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%97%E3%81%A6%E3%80%81%E3%82%B5%E3%83%BC%E3%83%90%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AB%E8%87%AA%E5%8B%95/