設定 - Systemdサービスユニット

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

サービスとは、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の扱いが異なる。

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に登録される時点で起動完了と判定する。
      • notify
        simpleと似ているが、systemdのライブラリ関数であるsd_notify関数を使用して、起動完了のメッセージを受信した時に起動が完了する。
        コマンドのプログラムにおいて、sd_notify関数を使用して起動完了を通知するように設計されている必要がある。
      • 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の動作を、以下に示す。

  1. Rsyslogdへ出力する内容を、systemd-journald.service(Journald)に送信する。
  2. Journaldはメタ情報を追加して、/var/log/journalディレクトリ下に記録する。
  3. 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サービスユニット名>