自作したシェルスクリプトを Linux の systemd サービスとして起動する方法

Bash,CentOS,Linux,Ubuntu

はじめに

最近は Kubernetesサーバレス なしくみを用いたサービス運用が進んでいるため、Linux の Systemd を触る機会はほぼありません。

利用機会は今後どんどん減っていくとは思いますが、
担当しているサービスの一部で Google Compute Engine を利用しており、
Systemd を使ってシェルをサービス化する事があったので、エントリにまとめることにしました。

概要

当エントリでは、
Systemd をつかった Linux サーバー上が起動してたタイミングで、シェルスクリプトを自動的に実行する方法 について紹介します。

Systemd とは?

本当にかんたんに Systemd についてお話します。

Systemd は、 OS 起動後に起動する起動プロセスの 1 つです。
Systemd は 複数のアプリケーションを 子プロセス として起動します。
Systemd は常にプロセス ID が 1( PID=1 )となります。

古い Linux ディストリビューションではinitd という起動プラセスが担当していました、最近のディストリビューションではこれが Systemd に置きなおしされています。

とあるサーバで、 pstree コマンドで PID=1 のプロセスの情報を表示してみます。

$ sudo pstree 1
systemd─┬─accounts-daemon─┬─{gdbus}
        │                 └─{gmain}
        ├─acpid
        ├─2*[agetty]
        ├─apache2───12*[apache2]
        ├─containerd─┬─containerd-shim─┬─mysqld───27*[{mysqld}]
        │            │                 └─10*[{containerd-shim}]
        │            ├─2*[containerd-shim─┬─apache2───10*[apache2]]
        │            │                    └─10*[{containerd-shim}]]
        │            ├─3*[containerd-shim─┬─httpd───4*[httpd───26*[{httpd}]]]
        │            │                    └─10*[{containerd-shim}]]
        │            ├─4*[containerd-shim─┬─mysqld───35*[{mysqld}]]
        │            │                    └─10*[{containerd-shim}]]
        │            ├─containerd-shim─┬─httpd───10*[httpd]
        │            │                 └─10*[{containerd-shim}]
        │            └─25*[{containerd}]
        ├─cron
        ├─dbus-daemon
        ...
        ├─systemd───(sd-pam)
        ├─systemd-journal
        ├─systemd-logind
        ├─systemd-udevd
        └─unattended-upgr───{gmain}

systemd は Linux オペレーションシステムでアプリケーションをサービスとして起動し、有効・無効を管理するためのアプリケーションです。

シェルスクリプトを systemd にサービスとして認識させる

まずはサービスとして登録したいシェルスクリプトを作成

早速自作のシェルスクリプトを systemd にサービスとして登録してみます。

今回作成するシェルスクリプトは、ディスクの使用情報のサマリ情報を定期的にログとして書き出すというものにします。

「監視日時」と「ディスク使用状況のサマリ」をそれぞれ 別の行で出力し、120 秒スリープしたら、まだ最初から処理を開始し直します。

#!/usr/bin/env bash

while :; do
  date >>/var/log/storage-monitor.log
  du --exclude=/proc -sch / >>/var/log/storage-monitor.log
  sleep 120
done

このスクリプトをファイルに書き出し、実行権限を付与しておきます。

$ cat <<EOF >/usr/bin/script.sh
#!/usr/bin/env bash

while :; do
  date >>/var/log/storage-monitor.log
  du --exclude=/proc -sch / >>/var/log/storage-monitor.log
  sleep 120
done
EOF

$ chmod +x /usr/bin/script.sh

サービスを作成する

次に、 Systemd に登録したいサービスを作成します。

「サービスを作成する」といっても、 /etc/systemd/system というディレクトリにファイルを作成するだけです。

ファイル作成時は以下の点に注意しましょう。

  • ファイル名は サービス名 とする
  • ファイルの拡張子は .service とする

ファイルの中身は以下のような内容となります。

$ cat <<EOF >/etc/systemd/system/monitor-disk.service
[Unit]
Description=Disk monitoring shell script service
Documentation=
#After=networking.service

[Service]
Type=simple
User=root
Group=root
TimeoutStartSec=0
Restart=on-failure
RestartSec=30s
#ExecStartPre=
ExecStart=/usr/bin/script.sh
SyslogIdentifier=Diskutilization
#ExecStop=

[Install]
WantedBy=multi-user.target
EOF

# 内容を確認する
$ cat /etc/systemd/system/monitor-disk.service
[Unit]
Description=Disk monitoring shell script service
Documentation=
#After=networking.service

[Service]
Type=simple
User=root
Group=root
TimeoutStartSec=0
Restart=on-failure
RestartSec=30s
#ExecStartPre=
ExecStart=/usr/bin/script.sh
SyslogIdentifier=Diskutilization
#ExecStop=

[Install]
WantedBy=multi-user.target

いわゆる ini ファイル 形式のファイルです。

いちばん大事な点は以下になります。

  • User=root : 実行ユーザ を指定
  • Group=root : 実行グループ を指定
  • ExecStart=/usr/bin/script.sh : 実行ファイル を指定

その他のフィールドについてもかんたんに説明します。

After

今回は利用していませんが、当サービス起動前に起動させておきたいサービス名を騎獣しておきます。
例えば、外部通信が必要なスクリプトの場合には、 After=networking.service と記述します。

ExecStartPre

今回は利用しませんでしたが、
指定されていた場合は ExecStart の処理が実行される前にこちらの処理が実行されます。

SyslogIdentifier

サービスのログは syslog 経由で出力されます。
syslog に出力されるログの各行に設定するプレフィックスとなります。

このプレフィックスを見れば、どのサービスのログかが特定しやすくなります。

systemctl コマンドを使ってサービスの開始、有効化、無効化、停止、再起動を行う

「 サービスの作成 」が終了したら、サービスを管理する systemd に対して、開始や停止を 指示 します。

systemd に対してサービスの管理を指示するためには、 systemctl コマンドを利用します。

サービスを開始

以下のコマンドでサービスを開始します。

$ systemctl start monitor-disk.service

スクリプトが正しく実行されていれば、スクリプトで生成されたログが確認できるはずです。

$ cat /var/log/storage-monitor.log

サービスの状態を確認

以下のコマンドでサービスの状態を確認します。

$ systemctl status monitor-disk.service

サービスが実行されているかを確認したり、出力されたログを確認することも可能です。

サーバ起動時に自動的にサービスを起動させる

このままではサーバ再起動が行われるたびに、手動でサービスを起動してやる必要があります。

これは面倒なので、サーバ起動時に自動的にサービスが起動されるようにしておきましょう。

$ systemctl enable monitor-disk.service

自動機能を無効にする場合は以下のコマンドを実行します。

$ systemctl disable monitor-disk.service

サービスを停止

停止は以下のコマンドです。

$ systemctl stop monitor-disk.service

サービスを再起動

再起動は以下のコマンドです。

$ systemctl reload monitor-disk.service

syslogについて

Systemd はデフォルトで syslog にログを書き出します。

したがって、リアルタイムのログを確認したい場合には以下のコマンドが利用できます。

$ tail -f /var/log/syslog

サービス設定ファイル( /etc/systemd/system/monitor-disk.service )に SyslogIdentifier=Diskutilization という設定を記述しておいたので、
キーワードで検索すれば当スクリプトのログだけに絞り込むことが可能でうs。

$ tail -f /var/log/syslog | grep Diskutilization

ひとこと

はじめにいったとおり、 Kubernetesサーバレス なしくみを用いたサービス運用が進んでいるため、Linux の Systemd を触る機会は最近ほとんどありませんね。

Bash,CentOS,Linux,Ubuntu