設定 - Systemdサービスユニット
概要
サービスとは、PCの起動時に自動的に実行され、バックグラウンドで仕事をするために待機するソフトウェアのことである。
一般的に、サービスはグラフィカルユーザインターフェースを持たず、ユーザの操作無しに動作する。
最もよく知られているサービスは、Web、メール、データベース等のサーバで、Apache、MySQL等がある。
また、ハードウェアの検出やUSBメモリの自動統合(マウント)等もサービスによって行われる。
サービスには、システム起動時に関連するタスクやハードウェアに関連するタスクを行う"内部サービス"と、
その後にユーザがインストールするサービス(通常は全てのサーバサービスを含む)の2種類がある。
技術用語やコンピュータ用語では、サービスは伝統的にデーモンと呼ばれている。
そのため、サーバコンポーネントであるsshdやmysqldのように、サービスを表すプログラムの最後の文字として"d"が用いられることが多い。
一方、Systemdは、システムおよびセッションマネージャ(initシステム)であり、
コンピュータの起動プロセスからシャットダウンまでの全動作時間にわたって、システム上で動作するすべてのサービスを管理する役割を担っている。
プロセスは常に(可能な限り)並行して起動され、起動プロセスを可能な限り短くする。
ここで、.serviceで終わる設定ファイルを作成して、Systemdが制御・監視するプロセスに関するコードを保持する場合をSystemd Service Unitファイルと呼ぶ。
Systemdには、サービス、タイマ、マウントポイント、ソケット、スワップスペース、デバイス等のユニットが存在する。
そのため、Systemdは管理用の設定の全てをファイルから取得する。
Systemdの用語では、これらを"ユニット"と呼び、システム全体に適用されるユニットと各ユーザ領域にのみ適用されるユニットがある。
ユニットには、サービスを開始するためのサービスユニットや、ある時点でのアクションを(繰り返し)実行するためのタイマユニット等、様々な種類がある。
各タイプのユニットファイルに共通しているのは、iniファイルに似た構造をしていることである。
ユニットファイルは、いくつかのセクション(多くの場合、3セクション)で構成されている。
Systemdではセクションと呼ばれ、その中に一連のキーと値のペア(Systemdではディレクティブと呼ばれる)が格納されている。
コマンドライン
コマンドラインやターミナルでSystemdを管理するツールはsystemctlと呼ばれる。
多くのコマンドはシステムに深く介入するため、root権限が必要である。
そのため、必要な操作を行うには、このコマンドをスーパユーザ権限で実行する必要がある。
ログ
Systemdは、ログ情報を中央のジャーナルに書き込む。
これは、journalctl
コマンドにより読み出すことができ、検索やフィルタのオプションも含まれている。
システム全体の単位
usr/lib/systemd/systemディレクトリには、サービスによってシステム全体にプレインストールされているユニットの全てのファイルがある。
/etc/systemd/systemディレクトリには、ユーザが作成または編集したシステム全体のユニットの全てのファイルがある。
/etc/systemd/systemディレクトリと/usr/lib/systemd/systemdディレクトリで同名のユニットファイルがある場合は、
/etc/systemd/systemディレクトリのファイルが優先される。
ユニットの種類
ユニットには様々な種類があり、ファイルの拡張子に応じてsystemdの扱いが異なる。
種類(拡張子) | 説明 |
---|---|
.device | デバイスファイルを作成する。 |
.mount | ファイルシステムのマウントとアンマウントをする。 |
.path | ファイルやディレクトリの変更に応じたサービスユニットを実行する。 |
.network | ネットワークの設定を行う。 |
.service | サービスを設定する。 |
.socket | プロセス間の接続を確立する。 |
.target | ユニットのグループを定義する。 |
.timer | Cronジョブのような定期的なタスクを実行する。 |
ここでは、.service拡張子のユニットについて記載する。
ユニットファイルの構造
ユニットファイルは、3つのセクションで構成される。
- [Unit]セクション
- 依存関係や順次関係等、依存しない設定を記述する。
- [Install]セクション
systemctl enable / disable
コマンドに関連する設定を記述する。
- [Service]セクション
- 固有の設定項目を記述する。
オプションに複数の項目を記述する時は、スペース区切り、または、同じオプションを複数回に分けて記述する。
# スペース区切り After=NetworkManager.service systemd-resolved.service # 複数回に分ける After=NetworkManager.service After=systemd-resolved.service
- [Unit]セクション
- ユニットの種類によらない一般的なオプションの設定
- Description
- このユニットの説明を記述する。
sudo systemctl status
を実行する時に表示される。
- Documentation
- このユニットについてのドキュメントのURIを記述する。
- After
- このユニットの前に起動するユニットを記述する。
- Before
- このユニットの後に起動するユニットを記述する。
- Requires
- このユニットが依存するユニットを記述する。
- 前のユニットの起動が失敗した場合は起動しない。
- Wants
- このユニットが依存するユニットを記述する。
- 前のユニットの起動が失敗した場合でも起動する。
- Conflicts
- 同時に有効化してはいけないユニットを指定する。
- [Service]セクション
- サービスに関する設定を記述する。
- Type
- プロセスの起動方法を記述する。
- 各方法は以下の6通りある。
- "起動が完了する"とは、次の他ユニットが実行可能であることを意味する。
- simple
- デフォルト。コマンドを実行した時点で起動完了と判定する。
- 指定コマンドがフォアグラウンドで実行を継続する場合に使用する。
- forking
- 子プロセスをバックグラウンドで起動して、親プロセスが終了した時点(最初のコマンドが終了した時点)で起動完了と判定する。
- 最初のコマンドが終了する場合に使用する。
- oneshot
- simpleと似ているが、次のユニットを実行する前に自身のプロセスを終了する。(コマンドが終了したら起動完了と判定して、サービスも終了したものと認識する)
RemainAfterExit=yes
を指定する場合は、コマンド終了後もサービスは起動したままと認識する。- 1度だけコマンドを実行するタイプの場合に使用する。
- dbus
- D-Bus(プロセス間通信用メッセージバス)を使用するプロセスであり、
BusName
で指定した接続名がD-Busに登録される時点で起動完了と判定する。
- D-Bus(プロセス間通信用メッセージバス)を使用するプロセスであり、
- notify
- simpleと似ているが、systemdのライブラリ関数である
sd_notify
関数を使用して、起動完了のメッセージを受信した時に起動が完了する。 - コマンドのプログラムにおいて、
sd_notify
関数を使用して起動完了を通知するように設計されている必要がある。
- simpleと似ているが、systemdのライブラリ関数である
- idle
- simpleと似ているが、他のジョブが終了するまで待機する。(シェルへの出力が混ざらないようにするため)
- ExecStart
- 起動時に実行するコマンドを記述する。
- ExecStop
- 停止時に実行するコマンドを記述する。
- ExecReload
- リロード時に実行するコマンドを記述する。
- Restart
- プロセスが異常終了した時、プロセスを再起動する条件を記述する。
- 未指定の場合、10秒の間に5回以上再起動すると、次の10秒間は再起動を試みない。
StartLimitInterval
秒の間にStartLimitBurst
回以上再起動すると、次のStartLimitInterval
秒の間は再起動を試みない。- 各条件は以下の4つがある。
- always
- 常に自動的に再起動する。
- no
- 再起動しない。
- on-success
- 終了コードが0で再起動する。
- on-failure
- 終了コードが0以外で再起動する。
- on-abort
- キャッチできないシグナルで終了した時に再起動する。
- on-watchdog
- 監視時間切れで再起動する。
- on-abnormal
- SIGHUP、SIGINT、SIGTERM、SIGPIPE以外のシグナルで終了した時に再起動する。
- RestartSec
- 再起動するまでの待ち時間(秒)を記述する。
- ExecStartPreおよびExecStartPost
- サービス起動前(ExecStartPre)およびサービス起動後(ExecStartPost)の追加コマンドを指定する。
- これは、サービスの起動判定には関連させたくないコマンドを指定する。
- ExecStopPost
- サービス停止後に実行するコマンドを指定する。
- これは、サービスが異常終了した場合にも実行される。
- KillMode
- ExecStopで停止せずに残ったプロセスの処理方法を指定する。
- none
- 残プロセスは放置する。
- process
- メインプロセスが残っている場合、SIGTERM / SIGKILLで停止する。
- その他の残プロセスは放置する。
- control-group
- グループ内の全ての残プロセスをSIGTERM / SIGKILLで停止する。
- mixed
- メインプロセスをSIGTERM / SIGKILLで停止して、続けてグループ内の全ての残プロセスをSIGKILLで停止する。
- PIDFile
- fork型サービスのメインプロセスのPIDファイルを指定する。
- BusName
- D-Bus型サービスのbus接続名を指定する。
- User
- プロセスを起動するユーザを指定する。
- Group
- プロセスを起動するグループを指定する。
- PrivateTmp
- このサービス専用の/tmpと/var/tmpを用意する。
- ReadOnlyDirectories
- 指定ディレクトリ以下をReadOnlyモードにする。
- InaccessibleDirectories
- 指定ディレクトリ以下をアクセス不可にする。
- RootDirectory
- 指定ディレクトリにchrootする。
- [Install]セクション
- インストール時の設定を記述する。
- Alias
sudo systemctl enable
コマンドの実行時に、Aliasで指定された名前のユニットのシンボリックリンクを作成する。
- RequiredBy
sudo systemctl enable
コマンドの実行時に、このユニットの".required"ディレクトリにリンクを作成する。
- WantedBy
sudo systemctl enable
コマンドの実行時に、このユニットの".wants"ディレクトリにリンクを作成する。
- Also
sudo systemctl enable / disable
コマンドの実行時に、同時にenable / disableするユニットを記述する。
ユニットの詳細を知りたい場合は、以下のコマンドを実行する。
man systemd.unit
サービスの詳細を知りたい場合は、以下のコマンドを実行する。
man systemd.service
以下に、よく使用されるユニットファイルのフォーマットを示す。
[Unit] Description=<ユニットファイルの説明> After=<指定したユニットリストの起動後に実行する> Before=<指定したユニットリストの前に実行する> Requires=<指定したユニットリストの起動成功後に実行する。(ユニット起動時に依存ユニットも起動するが、依存ユニット失敗時は起動しない)> Wants=<指定したユニットリストが起動失敗しても実行する。(ユニット起動時に依存ユニットも起動するが、依存ユニット失敗時でも起動する)> [Service] Environment=<環境変数リスト> EnvironmentFile=<環境変数ファイル> Type=<simple | forking | oneshot | dbus | notify | idle> ExecStart=<起動コマンド> ExecStop=<停止コマンド> ExecReload=<再起動コマンド> Restart=<always | on-abort | on-watchdog | on-abnormal | on-failure | on-success | no> RemainAfterExit=<yes | no> PIDFile=<メインプロセスのPIDファイルパス> User=<ユニットファイルの実行ユーザ> SuccessExitStatus=<(0以外に)メインプロセス正常終了とみなすexitコードリスト> [Install] Alias=<ユニットの別名> RequiredBy=<sudo systemctl enableコマンドの実行時に、このユニットの".required"ディレクトリにリンクを作成する> WantedBy=<sudo systemctl enableコマンドの実行時に、このユニットの".wants"ディレクトリにリンクを作成する> Also=<同時に起動および停止するユニット>
ユニットの依存関係および順序の確認
Systemdユニットの依存関係および順序は、以下のコマンドで確認できる。
指定したユニットが必要とするユニットを表示する。ユニット名を省略した時は、default.targetが指定される。
依存関係のユニットがTargetタイプの場合、さらに、それが必要なユニットを再帰的に表示する。
--all
オプションを付加することにより、全てのユニットを再帰的に表示する。
sudo systemctl list-dependencies <ユニット名>
指定したユニットよりも先に起動するユニットを表示する。
sudo systemctl list-dependencies <ユニット名> --after
指定したユニットよりも後に起動するユニットを表示する。
sudo systemctl list-dependencies <ユニット名> --before
ユニットの有効化 / 無効化
指定のユニットを有効化および無効化する。
maskを使用する場合、sudo systemctl disable
と異なり、sudo systemctl start
での手動起動もできなくなる。
maskによる無効化は、/etc/systemd/systemディレクトリ下に/dev/nullへのシンボリックリンクを張ることにより行われる。
また、/etc/systemd/systemディレクトリ下に設定ファイルを作成している場合は、maskによる無効化はできない。
sudo systemctl mask <ユニット名> # または sudo systemctl unmask <ユニット名>
サービスの遅延実行
Systemdサービスを遅延起動する方法には、主に2つの方法がある。
ただし、タイマユニットを使用する方法が一般的であり、より柔軟性が高い。
- Systemdのタイマーユニットを使用する方法
- Systemdサービスファイル自体に遅延を設定する方法
タイマユニットを使用する方法
まず、実行するコマンドまたはプログラムを起動するSystemdサービスファイルを作成する。
[Unit]
Description=My delayed service
[Service]
ExecStart=<実行するコマンドまたはプログラムのパス> [コマンドまたはプログラムのオプション]
次に、特定のSystemdサービスファイルをどのタイミングで起動するかを指定するタイマファイルを作成する。
[Unit]
Description=Timer for my service
[Timer]
OnBootSec=30 # 30秒後に起動する場合
#OnBootSec=10min # 10分後に起動する場合
OnUnitActiveSec=24h # サービスが最後にアクティブになってから24時間後に再びサービスを起動する (繰り返し実行する場合)
Unit=<タイマ起動するsystemdサービスファイル名>
[Install]
WantedBy=timers.target # タイマをシステムのタイマターゲットに関連付けて、システム起動時にタイマを有効にする
Systemdサービスファイルとタイマファイルを、/etc/systemd/systemディレクトリ、または、~/.config/systemd/userディレクトリに配置する。
Systemdサービスのデーモンを再読み込みする。
# /etc/systemd/systemディレクトリに保存した場合 sudo systemctl daemon-reload # ~/.config/systemd/userディレクトリに保存した場合 systemctl --user daemon-reload
タイマサービスを有効または開始する。
これにより、指定時間後にSystemdサービスが自動的に起動するようになる。
# /etc/systemd/systemディレクトリに保存した場合 sudo systemctl enable <タイマファイル名 例: my_service.timer> # 起動時に開始する場合 sudo systemctl start <タイマファイル名 例: my_service.timer> # 通常起動する場合 # ~/.config/systemd/userディレクトリに保存した場合 systemctl --user enable <タイマファイル名 例: my_service.timer> # 起動時に開始する場合 systemctl --user start <タイマファイル名 例: my_service.timer> # 通常起動する場合
Systemdサービスファイル自体に遅延を設定する方法
Systemdサービスファイル内にExecStartPre
キーで時間を指定して、サービスの実行前に遅延 (例: sleep
コマンドを使用) を挿入する方法もあるが、この方法は推奨されない。
これは、Systemdのタイマ機能を使用する方法と比較して、柔軟性に欠けることやシステムの起動プロセスを不必要に遅延させる可能性がある。
そのため、タイマユニットを作成および使用して、サービスの起動タイミングを細かく制御することが推奨される。
Systemdサービスファイルの構文の確認
Systemdサービスファイル全体の構文を確認する。
これにより、問題のある部分を特定して、修正することができる。
sudo systemd-analyze verify <Systemdサービスファイルまたはタイマファイル等のパス>
訂正後は、Systemdサービスファイルを再読み込みして、変更を有効にする。
sudo systemctl daemon-reload # または systemctl --user daemon-reload
独自のユニットやSystemdサービスファイルの作成
例えば、PC起動時に何らかのスクリプトやソフトウェアをバックグラウンドで実行したいとする。
そのためには、サービスユニットを作成する必要がある。
サービスユニットを作成するための構文を、以下に示す。
まず、/etc/systemd/systemディレクトリまたは/usr/lib/systemd/systemディレクトリに、ユニットファイルを作成する。
一般的には、ユーザが任意で作成するユニットファイルは、/etc/systemd/systemディレクトリに配置する。
sudo vi /usr/lib/systemd/system/<ユニットファイル名>.service または sudo vi /etc/systemd/system/<ユニットファイル名>.service
# スクリプトを使用する場合 [Unit] Description = # サービスの説明を記述する After = network.target # ※指定しなくてもよい [Service] User= # ユーザ名 例. root ※指定しなくてもよい WorkingDirectory= # 実行するファイルまたはスクリプトがあるディレクトリのフルパス ※指定しなくてもよい ExecStart = # 実行するファイルまたはスクリプトへのフルパス または ファイル名のみ(WorkingDirectoryを指定する場合) Restart=always # ※指定しなくてもよい [Install] WantedBy = # multi-user.target または graphical.target等
# Pythonを使用する場合 [Unit] Description = # サービスの説明を記述する After = network.target # ※指定しなくてもよい [Service] User= # ユーザ名 例. root ※指定しなくてもよい WorkingDirectory= # 実行する.pyファイルがあるディレクトリのフルパス ※指定しなくてもよい ExecStart = # <Pythonの実行ファイル> <実行する.pyファイルへのフルパス または ファイル名のみ(WorkingDirectoryを指定する場合)> # 例. /usr/bin/python3 main.py Restart=always # ※指定しなくてもよい [Install] WantedBy = # multi-user.target または graphical.target等
以下の例では、Glancesという名前のサービスファイルを作成して、Linux向けの監視ツールであるglancesをバックグラウンドで動作させている。
sudo vi /usr/lib/systemd/system/glances.service
[Unit] Description = Glances in Web Server Mode After = network.target [Service] ExecStart = /usr/bin/glances -w -t 5 [Install] WantedBy = multi-user.target
[Install]
セクションでは、[WantedBy]
キーにより、ユニットがいつ起動するかを指定する。
下表に、指定することができるキーの値を示す。
ターゲット | 説明 |
---|---|
multi-user.target | グラフィカルログインの有無にかかわらず、マルチユーザシステム用(ランレベル3に対応) |
graphical.target | グラフィカルログインが必要なマルチユーザシステム用(ランレベル3 + グラフィカルログインに対応) |
rescue.target | 一般的に、シングルユーザモードはシステムのレスキュー時にのみ必要(ランレベル1に対応) |
reboot.target | システムの再起動時にのみユニットが実行する。 |
poweroff.target | システムのシャットダウン開始時にのみ実行するユニットである。 |
default.target | 別の既存ターゲットへのシンボリックリンクである。 例えば、Ubuntuデスクトップの初期設定では、default.targetはgraphical.targetである。 |
サービスファイルを読み込んで、新しいサービスを追加する。
sudo systemctl daemon-reload
手動で作成したシステムのサービスユニットを有効にする
サービスユニットの作成後は、サービスを有効にして起動する必要がある。
<サービスユニットのファイル名>において、
例えば、上記で作成したglancesサービスを有効にするには、sudo systemctl enable glances.service
となる。
以下のコマンドを実行して、新しいサービスユニットを読み込み・追加する。
sudo systemctl daemon-reload
サービスユニットを自動起動に設定する。
sudo systemctl enable <サービスユニットのファイル名>
サービスユニットを起動する。
sudo systemctl start <サービスユニットのファイル名>
サービスユニットの状態を確認する。
sudo systemctl status <サービスユニットのファイル名>
Journald
Journaldの動作を、以下に示す。
- Rsyslogdへ出力する内容を、systemd-journald.service(Journald)に送信する。
- Journaldはメタ情報を追加して、/var/log/journalディレクトリ下に記録する。
journalctl
コマンドを使用して、Journaldのログ(バイナリ形式)を検索および表示する。
Systemdは、Rsyslogdの設定変更が必要となる。
- 従来の動作
- プロセス → /dev/log → Rsyslogd
- Systemd
- プロセス → /dev/log → Systemd → /run/systemd/journal/syslog → Rsyslogd
また、Rsyslogdには、Journaldから直接ログ情報を取得するモジュールであるimjournalが存在しており、
UnixSocketである/run/systemd/journal/syslogファイルの代わりに、imjournalを利用することもできる。
journalctl
コマンドの便利なオプションを、以下に示す。
- -aオプション
- 長いメッセージを省略しない。
- -bオプション
- 直前のサーバ起動以降のログを表示する。
- -eオプション
- ページャーで最後にジャンプする。
- -fオプション
tail -f
コマンドのように、順次表示する。
- -uオプション
- 指定したユニットのログを表示する。
- -xオプション
- メッセージの説明がある場合は追加する。
- --since='YYYY-MM-DD hh:mm:ss'
- 指定日以降のログを表示する。
- --until='YYYY-MM-DD hh:mm:ss'
- 指定日までのログを表示する。
# 例 sudo journalctl -ex -u <systemdサービスユニット名>