systemd

提供: ArchWiki
ナビゲーションに移動 検索に移動

関連記事

プロジェクトウェブページ より:

systemd は Linux 環境の基本構成スイートであり、SysV や LSB init スクリプトと互換性のある、Linux 用のシステム・サービスマネージャです。systemd はサービスの起動を積極的に並行化します。また、ソケットや D-Bus のアクティベーションを使用してサービスを起動し、必要なデーモンの開始を行うことができ、Linux の cgroups によるプロセス管理ができます。システム状態のスナップショット作成と復元、(自動) マウントポイントの管理、煩雑な依存関係に基づいたサービスのコントロールを処理します。systemd は sysvinit の代替として SysV や LSB init スクリプトをサポートしています。init としての機能以外にも、ログデーモンやホストネーム・時刻・ロケールなどシステムの基本設定を制御するユーティリティ、ログイン中のユーザーから実行中のコンテナや仮想マシン、システムアカウントまで管理する機能、ネットワーク設定や時刻同期あるいは名前解決などを管理するシンプルなデーモンも含まれています。
ノート: systemd が Arch に採用された理由については、フォーラムへのこの投稿をご覧ください。

目次

systemctl の基本的な使い方

systemd を管理したり内部情報を見るために使うメインのコマンドが systemctl です。システムの状態を確かめたりシステムやサービスを管理するために使うのは使い方の一部です。詳しくは systemctl(1) を見て下さい。

ヒント:
  • systemctl コマンドに -H <user>@<host> を渡すと、リモートの systemd と対話できます。SSH を利用してリモートの systemd インスタンスに繋ぐのに使われます。
  • Plasma を使っている場合 systemd-kcmAUR をインストールすることで systemctl のグラフィカルフロントエンドを使えます。モジュールをインストールすると System administration の下に設定が追加されます。

ユニットを使う

ユニットには、例えば、サービス (.service) やマウントポイント (.mount)、デバイス (.device)、ソケット (.socket) などがあります。

systemctl を使うとき、一般的には拡張子 (suffix) を含むユニットファイルの完全な名前を指定する必要があります。例えば、sshd.socket のように。しかし、以下のような場合には省略形が存在します:

  • 拡張子が指定されない場合、systemctl は .service とみなします。例えば netctlnetctl.service は同じように扱われます。
  • マウントポイントは自動的に対応する .mount ユニットとして扱われます。例えば、/home を指定することは home.mount の指定と同じです。
  • マウントポイントと同じく、デバイスも自動的に対応する .device ユニットとして扱われます。従って、/dev/sda2 の指定は dev-sda2.device と同じです。

詳細は systemd.unit(5) を見てください。

ノート: ユニットによっては名前に @ 記号が含まれていることがあります (例: name@string.service): これは、そのサービスがテンプレートユニットの インスタンス であることを意味しており、テンプレートユニットのファイル名には string の部分が含まれていません (例: name@.service)。stringinstance identifier と呼ばれ、systemctl コマンドでテンプレートユニットを実行するときに指定する引数と似ています: ユニットファイルの中の %i が置き換えられます。 正確に言うと、name@.suffix テンプレートユニットのインスタンスを作成する前にsystemdname@string.suffix というファイル名のユニットが存在しないか確認します。ただし名前の"衝突"が発生するのは極めて稀で、@ 記号を含むユニットファイルは大抵テンプレートです。そういう決まりです。また、テンプレートユニットが instance identifier を付けられずに呼ばれたときは、%i が置き換えられないため実行失敗になります。

以下の表のコマンドは、systemctl の暗黙のデフォルトである --system から、system unit' を操作するものです。代わりに、ユーザー単位 で操作するには、root 権限なしで systemctl --user を使ってください。全てのユーザーに対してユーザーユニットを有効・無効にするには systemd/ユーザー#基本設定 も見て下さい。

ヒント:
  • 以下のコマンドのほとんどは複数のユニットを指定することが可能です、詳しくは systemctl(1) を参照。
  • --now スイッチは enable, disable, mask と一緒に使うことで、それぞれ起動、停止、マスクをリブート後ではなく即座に行うことができます。
  • パッケージには様々な目的のユニットが入っています。パッケージをインストールしたら、pacman -Qql package | grep -Fe .service -e .socket でサービスを確認することができます。
アクション コマンド 注意
システム状態の分析
システムステータスを表示する systemctl status
実行中のユニット リスト systemctl or
systemctl list-units
失敗したユニット 一覧 systemctl --failed
インストールされているユニット 一覧1 systemctl list-unit-files
PID のプロセスステータス を表示 systemctl status pid cgroup slice, メモリ と 上位プロセス
ユニットの状態を確認する
ユニットに関連付けられている マニュアルページを表示する systemctl help unit ユニットでサポートされています
ユニットの ステータス systemctl status unit 実行されているかどうかを含む
ユニットが有効かどうかを チェック する systemctl is-enabled unit
本体の起動、再起動、再読み込み
ユニットを即座に スタート する systemctl start unit as root
ユニットを即座に ストップ する systemctl stop unit as root
ユニットを 再起動 する systemctl restart unit as root
ユニットとその設定を 再読み込み する systemctl reload unit as root
systemd マネージャーの再読み込み 設定2 systemctl daemon-reload as root ユニットスキャン
ユニットの有効化
ブート時に自動的に起動するユニットを 有効 にする systemctl enable unit as root
起動時に自動起動するユニットを 有効 にして、すぐに 起動 する systemctl enable --now unit as root
無効 にすると、ブート時に起動しなくなります systemctl disable unit as root
ユニット3再有効化 する systemctl reenable unit as root つまり、無効化して新たに有効化する
ユニットのマスキング
mask して起動不能にするユニット4 systemctl mask unit as root
unmask ユニット systemctl unmask unit as root
  1. 利用可能なユニットファイルがあるディレクトリは systemd.unit(5) § UNIT FILE LOAD PATH を参照してください。
  2. これは変更されたユニットに設定の再読み込みを要求しません (アクション Reload を参照して下さい)。
  3. 例えば、最後に有効化してからその [インストール] セクションが変更された場合。
  4. 手動でも依存関係としても、マスクは危険です。既存のマスクされたユニットをチェックします。
    # systemctl list-unit-files --state=masked

電源管理

非特権ユーザーでの電源管理には、polkit が必要です。ローカルの systemd-logind ユーザーセッションで、他のセッションがアクティブでない場合、以下のコマンドは root 権限がなくても動作します。そうでない場合(例えば、他のユーザーが tty にログインしているなど)、systemd は自動的に root パスワードを要求します。

コマンド
システムをシャットダウンして再起動する systemctl reboot
システムをシャットダウンして電源を切る systemctl poweroff
システムを一時停止する systemctl suspend
システムをハイバネーションにする systemctl hibernate
システムをハイブリッドスリープ状態にする (または suspend-to-both) にする systemctl hybrid-sleep

ユニットファイル

systemd の ユニットファイル の構文は XDG の Desktop Entry Specification である .desktop から影響を受けています。そして .desktop は Microsoft Windows の .ini ファイルからインスパイアされています。ユニットファイルは複数の場所に配置されます (配置場所のリストを確認するには systemctl show --property=UnitPath を実行してください)。優先度が低い方から説明すると:

  • /usr/lib/systemd/system/: インストールしたパッケージに含まれているユニット
  • /etc/systemd/system/: システムの管理者がインストールしたユニット
ノート:
  • ユーザーモードsystemd を動作させたときにロードされるパスは完全に異なります。
  • systemd ユニットの名前に使うことができるのは ASCII 英数字とアンダーバー、ピリオドだけです。他の文字列は "\x2d" エスケープに置き換える必要があります。詳しくは systemd.unit(5)systemd-escape(1) を見て下さい。

依存関係を解決する

systemd ではユニットファイルを適切に書くことで依存関係を解決します。一番典型的なケースは、ユニット A が走る前に、ユニット A がユニット B を必要としている場合です。この場合、A[Unit] セクションに Requires=BAfter=B を加えます。依存が必然ではない場合、代わりに Wants=BAfter=B を加えます。Wants=Requires=After= を含まないことに注意してください、もし After= を明記しなかったときは、2つのユニットは並行して実行されます。

基本的に、依存関係はターゲットではなくサービスに記述します。例えば、network.target はネットワークインターフェースを設定する全てのサービスによって使われるので、カスタムユニットを起動させる順番は network.target が起動し終わってからにする必要があります。

タイプ

カスタムサービスファイルを書くときにどのスタートアップタイプを使うべきか考える必要があります。タイプは [Service] セクションの Type= パラメータで設定します。より詳しい説明は systemd.service(5) を見て下さい。

  • Type=simple (デフォルト): systemd はプロセスを起動した時点でサービスが立ち上がったとみなします。プロセスをフォークすることはできません。ソケットアクティベーション以外で他のサービスが必要な場合に、このタイプを使ってはいけません。
  • Type=forking: 起動したプロセスが一旦フォークし、親プロセス側が終了したときに、 systemd はサービスが立ち上がったとみなします。このタイプでなくてもかまわないとき以外は、古典的なデーモンにはこのタイプを使って下さい。また PIDFile= を指定することで systemd はメインプロセスの情報を追い続けます。
  • Type=oneshot: シングルジョブを行い終了するスクリプト用のタイプです。また RemainAfterExit=yes を設定することで systemd はプロセスが終了した後もサービスがアクティブだとみなします。
  • Type=notify: Type=simple と同じですが、利用可能になったときにデーモンが systemd に信号を送るように条件がつけられます。この通知のリファレンス実装は libsystemd-daemon.so によって提供されています。
  • Type=dbus: 指定の BusName が DBus のシステムバスに乗ったときに使うことができるサービス。
  • Type=idle: idle の挙動は Type=simple と非常に似ています。ただし、サービスバイナリの実行は全てのジョブが処理されるまで待たされます。これを使えば、コンソールに状態を出力するシェルサービスで、出力が混じってしまうのを避けることができます。

ユニットファイルの編集

パッケージに入っているユニットファイルを編集する方法は2つあります: 新しいユニットファイルで完全に置き換えるか、ドロップインファイルを作成して既存のユニットファイルに上書きして適用させるかです。どちらの方法でも、変更を加えた後はユニットをリロードする必要があります。systemctl edit でユニットを編集するか (自動でユニットがリロードされます) または次のコマンドで全てのユニットをリロードしてください:

# systemctl daemon-reload
ヒント:
  • systemd-delta を使うことでどのファイルが上書きされ、どこが変更されたのか調べることができます。
  • ユニットファイルや関連するドロップインファイルの中身を見るには systemctl cat unit を使います。
  • 公式リポジトリから vim-systemdAUR をインストールすることで、Vimsystemd ユニットファイルのシンタックスハイライトが可能です。

ユニットファイルを置換する

ユニットファイル /usr/lib/systemd/system/unit を置き換えたいときは、/etc/systemd/system/unit ファイルを作成してユニットを再有効することでシンボリックリンクをアップデートします:

# systemctl reenable unit

もしくは、次を実行:

# systemctl edit --full unit

このコマンドはテキストエディタで /etc/systemd/system/unit を開いて (ファイルが存在しない場合はインストールされているユニットがコピーされます)、編集を終えた時に自動的にユニットをリロードします。

ノート: Pacman は元のユニットファイルが更新されても置き換えられたユニットファイルをアップデートしません。そのため、この方法ではシステムメンテナンスが多少厄介になります。この理由があるために、次のセクションで説明する方法の方が推奨されます。

ドロップインファイル

ユニットファイル /usr/lib/systemd/system/unit のドロップインファイルを作成するには、/etc/systemd/system/unit.d/ という名のディレクトリ (例: /etc/systemd/system/httpd.service.d/) を作成してその中に *.conf を配置します。このファイルを使ってオプションを上書きしたり追加してください。systemd*.conf ファイルをパースして元のユニットファイルの一番上に設定を適用します。

ドロップインファイルを作成する一番簡単な方法は次のコマンドを実行することです:

# systemctl edit unit

テキストエディタで /etc/systemd/system/unit.d/override.conf ファイルが開かれ (必要であればファイルが作成されます)、編集を終えた時に自動でユニットがリロードされます。

初期状態にリバート

systemctl edit を使って変更したユニットを元に戻したい場合、以下のコマンドを実行:

# systemctl revert unit

サンプル

例えば、ユニットに依存するデーモンを追加したい場合、以下のファイルを作成することができます:

/etc/systemd/system/<unit>.d/customdependency.conf
[Unit]
Requires=<new dependency>
After=<new dependency>

oneshot タイプでないユニットの ExecStart ディレクティブを置き換えるには、以下のファイルを作成します:

/etc/systemd/system/unit.d/customexec.conf
[Service]
ExecStart=
ExecStart=new command
ノート: ExecStart は置き換える前に空白にする必要があるので注意してください ([1])。タイマーの OnCalendar など複数回指定できるアイテムも同じです。

サービスが自動的に再起動されるようにするには:

/etc/systemd/system/unit.d/restart.conf
[Service]
Restart=always
RestartSec=30

ターゲット

Systemd ではランレベルに似たものとしてターゲットを使っています。ただしその挙動には少し違いがあります。それぞれのターゲットはナンバリングされる代わりに名前がつけられ、ある特定の目的のために作られ、複数のターゲットを同時に有効にできるようになっています。ターゲットによっては、他のターゲットのサービスを全て引継ぎ、そこにサービスを追加するよう実装されています。一般的な SystemVinit ランレベルに擬態する systemd ターゲットもあり、親しみのある telinit RUNLEVEL コマンドを使って使用するターゲットを切り替えることが可能です。

現在のターゲットを獲得

systemd では runlevel の代わりに次のコマンドが使われます:

$ systemctl list-units --type=target

カスタムターゲットを作る

標準の Fedora インストールではランレベルごとに特定の目的が設定されています; 0, 1, 3, 5, 6 のランレベルには特定の sytemd ターゲットと一対一の対応関係が存在します。残念ながら、ユーザー定義のランレベル (2 や 4 など) で同じことをする良い方法はありません。もしあなたがそうしたいならば、既に存在しているランレベルをベースに新しい systemd ターゲット/etc/systemd/system/<your target> として作り (/usr/lib/systemd/system/graphical.target がサンプルになるかもしれません)、/etc/systemd/system/<your target>.wants ディレクトリを作って、有効にしたいサービスに /usr/lib/systemd/system/ からシンボリックリンクを貼ることが示唆されています。

SysV ランレベルと systemd ターゲットの対応表

SysV ランレベル systemd ターゲット 説明
0 runlevel0.target, poweroff.target システムを停止。
1, s, single runlevel1.target, rescue.target シングルユーザーモード。
2, 4 runlevel2.target, runlevel4.target, multi-user.target ユーザー定義・サイト指定ランレベル。デフォルトでは、3 と同一。
3 runlevel3.target, multi-user.target マルチユーザー、非グラフィカル。一般的にマルチコンソールやネットワークを介してログインするのに使われます。
5 runlevel5.target, graphical.target マルチユーザー、グラフィカル。通常、ランレベル 3 の全てのサービスにグラフィカルログインを付加。
6 runlevel6.target, reboot.target 再起動
emergency emergency.target 緊急シェル

現在のターゲットを変更する

systemd ではターゲットは"ターゲットユニット"を通して扱うことができます。ターゲットを変えるには次のようにします:

# systemctl isolate graphical.target

これは現在のターゲットを変えるだけで、次の起動時には影響がありません。SysVinit での、telinit 3telinit 5 のようなコマンドと同じです。

起動するデフォルトターゲットを変更

標準のターゲットは default.target で、これは graphical.target へのシンボリックリンクです。これは、古いランレベル5にほぼ対応します。

systemctl を使用して現在のターゲットを確認するには、次の手順に従います。

$ systemctl get-default

ブート先のデフォルトターゲットを変更するには、default.target シンボリックリンクを変更します。systemctl の場合

# systemctl set-default multi-user.target
Removed /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target.

または、次の カーネルパラメータ のいずれかをブートローダに追加します。

  • systemd.unit=multi-user.target (これは、古いランレベル3にほぼ対応しています)
  • systemd.unit=rescue.target (これは、古いランレベル1にほぼ対応しています)

デフォルトのターゲット順序

systemd は、次の順序に従って default.target を選択します。

  1. 上記のカーネルパラメータ
  2. /etc/systemd/system/default.target への Symlink
  3. /usr/lib/systemd/system/default.target への Symlink

systemd の構成要素

systemd のコンポーネントをいくつか(網羅的ではない)紹介します。

systemd.mount - マウンティング

systemd/etc/fstab で指定されたパーティションとファイルシステムのマウントを担当します。systemd-fstab-generator(8)/etc/fstab の全てのエントリを systemd 単位に変換します; これは起動時とシステムマネージャの設定が再ロードされた時に実行されます。

systemd は通常の fstab 機能を拡張し、追加のマウントオプションを提供します。これらのオプションはマウントユニットの依存関係に影響を与えます。例えば、ネットワークが立ち上がった時だけマウントするようにしたり、他のパーティションがマウントされた時だけマウントするようにすることができます。特定の systemd マウントオプションの完全なリストは、通常 x-systemd. で始まり、 systemd.mount(5) § FSTAB で詳細に説明されています。

これらのマウントオプションの例として、自動マウントがあります。これは、ブート時に自動的にマウントするのではなく、リソースが必要な時にだけマウントすることを意味します。これは fstab#Automount with systemd で提供されています。

GPT パーティションの自動マウント

UEFI で起動したシステムでは、特定の条件が満たされると systemd-gpt-auto-generator(8)Discoverable Partitions Specification に従って GPT パーティションを自動マウントし、fstab から省略することができるようになります。

前提条件は以下の通りです。

  • ブートローダは LoaderDevicePartUUID EFI 変数を設定し、使用する EFI システムパーティションが特定できるようにする必要があります。これは systemd-boot, systemd-stub(7)rEFInd (not enabled by default) でサポートされています。これは bootctl を実行して Boot loader sets ESP information の状態をチェックすることによって確認できます。
  • ルートパーティションは、使用する EFI システムパーティションと同じ物理ディスク上になければなりません。オートマウントされる他のパーティションは、ルートパーティションと同じ物理ディスク上になければなりません。これは基本的に、オートマウントされる全てのパーティションは ESP と同じ物理ディスクを共有していなければならないことを意味します。
ヒント: パーティションのオートマウントを無効にするには、パーティションの type GUID を変更するか、パーティション属性ビットを 63 "do not automount" に設定します、参照 gdisk#Prevent GPT partition automounting
/var

/var の自動マウントが動作するためには、PARTUUID がパーティションタイプの UUID (4d21b016-b534-45c2-a9fb-5c16e091fd2d) の SHA256 HMAC ハッシュにマシン ID でキーを付けたものと一致している必要があります。必要な PARTUUID は、以下の方法で取得できます。

$ systemd-id128 -u --app-specific=4d21b016-b534-45c2-a9fb-5c16e091fd2d machine-id
ノート: systemd-id128(1)はマシンIDを/etc/machine-id から読み取るので、システムをインストールする前に必要な PARTUUID を知ることは不可能です。

systemd-sysvcompat

systemd-sysvcompat の主な役割は以下の通りです。(base で必要) は伝統的な linux init バイナリを提供することです。systemd -controlled systems では、init はその systemd 実行ファイルへのシンボリックリンクに過ぎません。

さらに、SysVinit のユーザーが慣れ親しんでいるであろう4つの便利なショートカットも提供されています。便利なショートカットは halt(8), poweroff(8), reboot(8), shutdown(8) です。これら4つのコマンドはそれぞれ systemctl へのシンボリックリンクであり、systemd の動作に支配されます。そのため、#電源管理 での議論が適用されます。

systemd ベースのシステムは init= を使うことでこれらの System V 互換の方法を諦めることができます。boot parameter (例えば、/bin/init is in systemd-sysvcompat ?) と systemd ネイティブ systemctl コマンド引数を見てください。

systemd-tmpfiles - 一時ファイル

systemd-tmpfiles は揮発性ファイルや一時ファイル、ディレクトリの作成、削除、クリーンアップを行います。systemd-tmpfiles は /etc/tmpfiles.d//usr/lib/tmpfiles.d/ にある設定ファイルを読んで、実行するアクションを決めます。前者のディレクトリにある設定ファイルは後者のディレクトリにある設定ファイルより優先されます。

設定ファイルは通常サービスファイルと一緒に提供され、/usr/lib/tmpfiles.d/program.conf というスタイルで命名されます。例えば、Samba デーモンはディレクトリ /run/samba が存在し、正しいパーミッションを持っていることを期待します。そのため、samba パッケージはこの設定で出荷されます。

/usr/lib/tmpfiles.d/samba.conf
D /run/samba 0755 root root

設定ファイルは、起動時に特定のファイルに値を書き込むために使用することもできます。例えば、/etc/rc.local で USB デバイスからの wakeup を無効にするために echo USBE > /proc/acpi/wakeup を使った場合、代わりに以下の tmpfile を使用することができます。

/etc/tmpfiles.d/disable-usb-wake.conf
#    Path                  Mode UID  GID  Age Argument
w    /proc/acpi/wakeup     -    -    -    -   USBE

詳しくは systemd-tmpfiles(8) および tmpfiles.d(5) のマニュアルページを参照してください。

ノート: この方法は /sys のオプションを設定するのには使えないかもしれません。この場合、modinfo module で設定したいオプションのパラメータがモジュールにあるかどうかを調べ、 config file in /etc/modprobe.d でそのオプションを設定することができます。そうでない場合は、デバイスが現れたらすぐに適切な属性を設定するように udevルール を書く必要があります。

ヒントとテクニック

GUI 設定ツール

  • systemadmsystemd ユニット用のグラフィカルブラウザ。ユニットのリストを表示することができ、タイプでフィルタリングすることもできます。
https://cgit.freedesktop.org/systemd/systemd-ui/ || systemd-ui
  • SystemdGeniesystemd KDE 技術に基づく管理ユーティリティ。
https://invent.kde.org/system/systemdgenie || systemdgenie

ネットワークが稼働した後にサービスを実行する

ネットワークが立ち上がった後までサービスを遅らせるには、以下の依存関係を .service ファイルに含めます。

/etc/systemd/system/foo.service
[Unit]
...
Wants=network-online.target
After=network-online.target
...

ネットワークを管理する特定のアプリケーションのネットワーク待ち受けサービスも有効にして、network-online.target がネットワークの状態を適切に反映するようにする必要があります。

  • NetworkManager を利用している場合、NetworkManager-wait-online.service も一緒に有効になっています。systemctl is-enabled NetworkManager-wait-online.service で確認してください。有効になっていない場合は、再有効化を実行してください。NetworkManager.service です。
  • netctl の場合、netctl-wait-online.service有効化 して下さい。
  • systemd-networkd を利用している場合,systemd-networkd-wait-online.service と共に有効にします.systemctl is-enabled systemd-networkd-wait-online.service でこの状態にあるかどうか確認してください。有効になっていない場合は、再有効化 をしてください。systemd-networkd.service です。

より詳しい説明は freedesktop.org の systemd wiki にある Running services after the network is up をご覧ください。

サービスが DNS クエリを実行する必要がある場合、追加で nss-lookup.target の後に命令する必要があります。

/etc/systemd/system/foo.service
[Unit]
...
Wants=network-online.target
After=network-online.target nss-lookup.target
...

systemd.special(7) § Special Passive System Units を参照してください。

Wants=nss-lookup.target が効果を発揮するためには、 Before=nss-lookup.target でその前に自分自身を命令するサービスが必要です。通常、これはローカルの DNSリゾルバ によって行われます。

もしあれば、どのアクティブなサービスが nss-lookup.target で引っ張っているのかを確認してください。

$ systemctl list-dependencies --reverse nss-lookup.target

インストールされたユニットをデフォルトで有効にする

Arch Linux の /usr/lib/systemd/system-preset/99-default.preset には disable * と記述されています。systemctl プリセットがデフォルトで全てのユニットを無効化するようになり、新しいパッケージがインストールされたときも、ユーザーが手動でユニットを有効化する必要があります。

自動的に有効化させたい場合、/etc/systemd/system-preset/99-default.preset から /dev/null にシンボリックリンクを作成して設定ファイルを上書きしてください。systemctl プリセットの設定ディレクトリで指定しないかぎり、インストールされた全てのユニットが有効化されるようになります。詳しくは systemd.preset(5) の man ページを参照。

ノート: デフォルトで全てのユニットを有効化すると、パッケージに(互いに両立しない)複数のユニットが含まれている場合に問題が生じます。systemctl プリセットはディストリビューションやシステム管理者によって使われることを意図されて作られています。衝突するユニットが有効化されてしまう場合、systemd.preset の man ページに書かれているように、プリセットの設定ファイルを使ってどちらか片方を明示的に無効化させる必要があります。

アプリケーション環境のサンドボックス化

ユニットファイルをサンドボックスとして作成して堅牢な仮想環境にアプリケーションやプロセスを分離させることが可能です。systemd は名前空間ケイパビリティのホワイトリスト・ブラックリスト、Cgroups を活用して 実行環境を設定 しプロセスをコンテナ化します。

既存の systemd ユニットファイルを使ってアプリケーションをサンドボックス化するには strace, stderr, journalctl などでエラーや出力を確認しながら試行錯誤が必要です。まずは上流のドキュメントを検索して先例がないか確認すると良いでしょう。

CapabilityBoundingSet では許可されるケイパビリティのホワイトリストを定義できますが、特定のケイパビリティをブラックリストに追加する用途で使うこともできます。例: CapabilityBoundingSet=~ CAP_SYS_ADMIN

サービスの失敗を通知する

サービス障害を通知するためには、OnFailure= ディレクティブを、例えば ドロップイン設定ファイル を使用して、該当するサービスファイルに追加する必要があります。このディレクティブを各サービスユニットに追加するには、トップレベルのドロップイン設定ファイルを使用します。トップレベルのドロップインについて詳しくは systemd.unit(5) を参照してください。

サービス用のトップレベルのドロップインを作成します。

/etc/systemd/system/service.d/toplevel-override.conf
[Unit]
OnFailure=failure-notification@%n

これにより、すべてのサービスファイルに OnFailure=failure-notification@%n が追加されます。some_service_unit が失敗すると、failure-notification@some_service_unitが開始されて通知(または実行するよう設定された任意のタスク)を処理するようになります。

テンプレートユニット failure-notification@ を作成します。

/etc/systemd/system/failure-notification@.service
[Unit]
Description=Send a notification about a failed systemd unit
After=network.target

[Service]
Type=simple
ExecStart=/path/to/failure-notification.sh %i

failure-notification.sh スクリプトを作成し、何をするか、どのように通知するか(メール、gotify、xmpp など)を定義します。%i は失敗したサービスユニットの名前で、スクリプトの引数として渡されます。

起動に失敗した場合に、何度も failure-notification@.service のインスタンスを起動する再帰を防ぐために、トップレベルのドロップインと同じ名前の空のドロップイン設定ファイルを作成します(空のサービスレベルのドロップイン設定ファイルはトップレベルのドロップインより優先され、後者をオーバーライドします。)

# mkdir -p /etc/systemd/system/failure-notification@.service.d
# touch /etc/systemd/system/failure-notification@.service.d/toplevel-override.conf

トラブルシューティング

systemd のエラーを調査する

例えば、systemd-modules-load サービスのエラーを調べるとします:

1. 起動に失敗している systemd サービスを探しましょう:

$ systemctl --state=failed
systemd-modules-load.service  loaded failed failed  Load Kernel Modules

もしくは systemd のライブログメッセージを確認します:

$ journalctl -fp err

2. Ok, systemd-modules-load サービスに問題が発生していることがわかりました。詳しく見てみましょう:

$ systemctl status systemd-modules-load
systemd-modules-load.service - Load Kernel Modules
   Loaded: loaded (/usr/lib/systemd/system/systemd-modules-load.service; static)
   Active: failed (Result: exit-code) since So 2013-08-25 11:48:13 CEST; 32s ago
     Docs: man:systemd-modules-load.service(8).
           man:modules-load.d(5)
  Process: 15630 ExecStart=/usr/lib/systemd/systemd-modules-load (code=exited, status=1/FAILURE)

Process ID が載っていない場合は、systemctl restart systemd-modules-load で失敗したサービスを再実行してください。

3. エラーを細かく調べるためのプロセス ID (PID) を入手しました。Process ID を使って (ここでは: 15630) 以下のコマンドを実行してください:

$ journalctl _PID=15630
-- Logs begin at Sa 2013-05-25 10:31:12 CEST, end at So 2013-08-25 11:51:17 CEST. --
Aug 25 11:48:13 mypc systemd-modules-load[15630]: Failed to find module 'blacklist usblp'
Aug 25 11:48:13 mypc systemd-modules-load[15630]: Failed to find module 'install usblp /bin/false'

4. カーネルモジュールに間違った設定がなされているようです。よって /etc/modules-load.d/ 下の設定を見てみましょう:

$ ls -Al /etc/modules-load.d/
...
-rw-r--r--   1 root root    79  1. Dez 2012  blacklist.conf
-rw-r--r--   1 root root     1  2. Mär 14:30 encrypt.conf
-rw-r--r--   1 root root     3  5. Dez 2012  printing.conf
-rw-r--r--   1 root root     6 14. Jul 11:01 realtek.conf
-rw-r--r--   1 root root    65  2. Jun 23:01 virtualbox.conf
...

5. エラーメッセージ Failed to find module 'blacklist usblp' はおそらく blacklist.conf 内に間違った設定があることを示しています。手順 3 で見つけたオプションの前に # を挿入して無効化してみましょう:

/etc/modules-load.d/blacklist.conf
# blacklist usblp
# install usblp /bin/false

6. では、systemd-modules-load を起動してみることにします:

$ systemctl start systemd-modules-load

成功した場合、何も表示されないはずです。何かエラーが表示される場合は、手順 3 に戻って下さい。そして新しい PID を使って残った問題を解決してください。

全て問題ないならば、サービスが正しく起動したか次のコマンドで確認することができます:

$ systemctl status systemd-modules-load
systemd-modules-load.service - Load Kernel Modules
   Loaded: loaded (/usr/lib/systemd/system/systemd-modules-load.service; static)
   Active: active (exited) since So 2013-08-25 12:22:31 CEST; 34s ago
     Docs: man:systemd-modules-load.service(8)
           man:modules-load.d(5)
 Process: 19005 ExecStart=/usr/lib/systemd/systemd-modules-load (code=exited, status=0/SUCCESS)
Aug 25 12:22:31 mypc systemd[1]: Started Load Kernel Modules.

この種の問題は上のように解決できます。より詳しい調査をする場合は次のブート問題の診断を見て下さい。

ブート問題の診断

カーネルコマンドラインに次のパラメータをつけて起動してください: systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M

詳しくはブートデバッグ[2] を見て下さい。

特定のサービスの問題を診断

ある systemd サービスが上手く動作せず、どうなっているのか詳しい情報が欲しい場合、環境変数 SYSTEMD_LOG_LEVELdebug に設定してください。以下は systemd-networkd デーモンをデバッグモードで動かす例です:

# systemctl stop systemd-networkd
# SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd

もしくは同じようにサービスファイルを修正してください:

/lib/systemd/system/systemd-networkd.service
[Service]
...
Environment=SYSTEMD_LOG_LEVEL=debug
....

シャットダウン/再起動にものすごく時間がかかる

シャットダウンに非常に長い時間がかかる(もしくはフリーズする)場合、サービスが存在していないことが問題かもしれません。Systemd はサービスを kill する前に終了するのを待ちます。なにが原因か知るには この記事 を見て下さい。

短いプロセスがログを出力しない

journalctl -u foounit.service が短いプロセスについてなにも表示しない場合、かわりに PID を見て下さい。例えば、systemd-modules-load.service が失敗したとき、systemctl status systemd-modules-load によってそれが PID 123 として動いているとわかったら、その PID の journal の出力を見ることができます、journalctl -b _PID=123。journal の _SYSTEMD_UNIT_COMM などのメタデータは非同期に収集され /proc ディレクトリにプロセスが存在している時だけ表示されます。これを修正するには、SCM_CREDENTIALS のように、ソケット接続を使ってデータを流すようカーネルを変更する必要があります。

クラッシュしたアプリケーションのダンプのジャーナルを無効にする

/etc/systemd/coredump.conf ファイルを編集して次の行を追加してください:

Storage=none

そして設定をリロードしてください:

# systemctl daemon-reload

少しづつ起動時間が長くなっている

systemd-analyze を使用して、以前と比べて起動時間が明らかに伸びていると複数のユーザーが報告しています。systemd-analyze blame を使って NetworkManager が起動するのに異常に長い時間かかるようになったという報告もあります。

問題の原因として /var/log/journal が巨大になりすぎている可能性があります。そのような場合、フォルダ内のファイルを全て削除して journal のファイルサイズをここに書かれているように制限するよう設定すれば解決します(できればファイルを削除する前に、どこかに一時的にバックアップしてください)。

起動時に systemd-tmpfiles-setup.service の実行に失敗する

systemd 219 から、/usr/lib/tmpfiles.d/systemd.conf/var/log/journal 下のディレクトリに対して ACL 属性を指定しており、それによって、ジャーナルが存在するファイルシステムで ACL のサポートを有効にしなくてはならなくなっています。

/var/log/journal が存在するファイルシステムで ACL を有効化する方法はアクセス制御リスト#ACL の有効化を見て下さい。

systemctl enable で /etc/systemd/system にシンボリックリンクが作成されない

/etc/systemd/system/foo.service がシンボリックリンクの場合、systemctl enable foo.service を実行しても以下のエラーで失敗します:

Failed to issue method call: No such file or directory

これは systemd の 仕様 です。絶対パスで有効にすることで回避できます:

# systemctl enable /absolute/path/foo.service

リモートマシンで緊急モードを無効化

リモートマシン (例えば Azure や Google Cloud でホストしている仮想マシン) の緊急モードは無効化すると良いでしょう。緊急モードが起動すると、ネットワークからマシンに接続できなくなってしまうからです。無効化するには以下のコマンドを実行:

# systemctl mask emergency.service
# systemctl mask emergency.target

参照