systemdのserviceユニットを作る(基本的な設定)

以下のコマンドは、基本的にroot権限で実行するものとする。
# 1.最小限のユニットファイル
## 1.1 ユニットファイルを作成
コマンドで```systemctl edit --full --force <作成するユニット名>.service```を実行すると、エディタが自動で開く。
エディタで以下のように入力し、エディタを閉じれば、最低限のユニットファイルができあがる。(ここでは仮に、tcpdumpでパケットキャプチャをするサービスを作ってみる)
```systemd
[Unit]
Description=systemdユニットのテスト
[Service]
ExecStart=/usr/bin/tcpdump -w /var/log/capture.pcap
```
「Description」はユニットの説明、「ExecStart」は```systemctl start <ユニット名>.service```で実行される、ユニットの処理を開始するコマンドを指定する。

これを設定することで、```systemctl status <ユニット名>```でユニットの情報表示、```systemctl start <ユニット名>```でユニットの起動、```systemctl stop <ユニット名>```でユニットの停止ができるようになる。


## 1.2 解説
systemdのユニットファイルは、```/usr/lib/systemd/system/```(```/lib/systemd/system/```の場合もある)の下、もしくは```/etc/systemd/system/```の下に配置される。```/usr/lib/systemd/system/```はパッケージマネージャが管理するので、基本的に編集するのは```/etc/systemd/system/```下のファイルになる。
```systemctl edit```コマンドを使うと、```/etc/systemd/system```下のファイルを操作できる。オプションによって以下のように動作が変わる。

- ```systemctl edit <ユニット名>.service```: 既存のユニットファイルの設定の一部をオーバーライドする。ファイルは```/etc/systemd/system/<ユニット名>.d/```下に保存される。
- ```systemctl edit --full <ユニット名>.service```: 上のように別ディレクトリでオーバーライドするのではなく、```/etc/systemd/system/<ユニット名>.service```を直接書き換える。
- ```systemctl edit --full --force <ユニット名>.service```: 指定したユニットが存在しない場合、```/etc/systemd/system/<ユニット名>.service```を新規作成する。

エディタなどで直接```/etc/systemd/system/```の下にファイルを作ってもよい。ただし、その場合は編集後に、設定を反映するために```systemctl daemon-reload```を実行する必要がある。
# 2.serviceの動作を変更する
1で作ったシンプルなユニットファイルでも機能するが、もう少し細かい設定をしてみたい。
以下の設定は[Service]の下で設定する。
※ここでは一部の設定項目しか紹介していない。他の設定項目については、systemd.unit(5)、systemd.service(5)、systemd.exec(5)、systemd-kill(5)、systemd.resource-control(5)などを参照のこと。
## Type=
serviceのタイプを指定する。
Type=simple
　デフォルト。基本的にはこれを使えば問題ない。
Type=forking
　親プロセスがすぐに終了し、子プロセスを起動するようなコマンドの場合、このタイプを使う。
Type=oneshot
　設定の変更やある種の起動コマンドのような、一瞬で処理が終了する(裏で長時間プロセスを動かさない)コマンドに使う。このタイプでは、一緒に```RemainAfterExit=true```（プロセスが終了しても、サービスはActive状態として扱われる）を設定することがある。
## Restart=
プロセスが終了したときに、プロセスを自動でもう一度開始するかどうかを設定できる。(```systemctl stop```などで明示的に停止した場合は再開されない)
Restart=no
　再開しない(デフォルト)
Restart=on-failure
　異常終了した場合は再開する。(終了コード0以外の場合に異常終了とみなす。)
Restart=always
　必ず再開する。

## RestartSec=
Restart=の設定で再開するまでの間隔を指定できる。
デフォルトは100ms(100ミリ秒)

## StartLimitBurst=, StartLimitIntervalSec=
```StartLimitIntervalSec```秒以内に```StartLimitBurst```回以上、サービスを開始しようとすると無効になる。
```Restart=```と組み合わせて、何度も繰り返し再開を試みるのを抑止できる。
デフォルトは10秒、5回

## SuccessExitStatus=
デフォルトで正常終了扱いになる「0」以外に、正常終了扱いにする終了コードを指定できる。

## User=,Group=
コマンドの実行ユーザ、実行グループを指定できる。(デフォルトではroot)

## ExecStop=
```systemctl stop```などでサービスを停止するときに実行するコマンドを指定できる。（デフォルトではSIGTERMを送ってプロセスを終了する）

## ExecStopPost=
プロセスが終了した後に、後処理として実行するコマンドを指定できる。
プロセスが異常終了し、Restart=on-failureの設定などで再起動される場合にも実行される。

## CPUQuota=
CPUの最大使用率を制限する。単位として「%」をつけて指定する。
topコマンドなどのCPU使用率の表示と同じように、1コアをすべて使った場合に100%となるので、マルチコアのシステムでは100%以上を指定してもよい。
## MemoryHigh=
最大使用メモリを指定する。単位としてK, M, G, Tが使える。
メモリ制限を超過してもプロセスは停止しないが、実行が非常に遅くなる。

## MemoryMax=
上のMemoryHighと同様だが、メモリ制限を超過するとプロセスが停止する。

## 1.1のユニットファイルの改善
上で紹介した設定項目を使用して、1.1のユニットファイルを改善してみた。

・改善点
- 異常終了時に自動で再開する
- プロセス終了時にキャプチャファイルの名前を変更し、上書きされないようにする
```systemd
[Unit]
Description=systemdユニットのテスト
[Service]
Type=simple
ExecStart=/usr/bin/tcpdump -w /var/log/capture.pcap
Restart=on-failure
ExecStopPost=/usr/local/bin/mv_capture.sh
```
また、以下のようなスクリプト```/usr/local/bin/mv_capture.sh```を作成しておく。(```ExecStopPost=```で直接コマンドを書かないのは、systemdはシェルを通さずにコマンドを実行するため、コマンド置換が使えないから)
```bash
#!/bin/bash
mv /var/log/capture.pcap /var/log/capture_$(date '+%Y%m%d%H%M%S').pcap
```

# 参考リンク
<https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html>
<https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html>
<https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html>
<https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html>