Linuxでsystemdサービスユニットを作成する方法
systemd は多くの論争の対象となってきましたが、一部のディストリビューションはそれを取り除くためだけにフォークされました (デフォルトで systemd を sysvinit に置き換える Debian のフォークである Devuan を参照)。 Linux の世界における事実上の標準の init システム。
このチュートリアルでは、systemd サービスがどのように構成されているかを確認し、サービスを作成する方法を学びます。 1 つ
このチュートリアルでは次のことを学びます:
サービスユニットとは..
サービスユニットのセクションとは何ですか。
-
各セクションで使用できる最も一般的なオプションは何ですか。
定義できるサービスにはどのような種類がありますか。
systemd init システム
Rhel、CentOS、Fedora、Ubuntu、Debian、Archlinux などの主要なディストリビューションはすべて、init システムとして systemd を採用しています。 Systemd は実際のところ、単なる init システムではありません。これが、一部の人々がその設計に強く反対する理由の 1 つであり、「1 つのことを実行すれば、それをうまく行う」という確立された UNIX のモットーに反します。他の init システムが単純なシェル スクリプトを使用してサービスを管理するのに対し、systemd は独自の .service
ファイル (.service サフィックスが付いたユニット) を使用します。このチュートリアルでは、それらがどのように構造化されているか、および作成方法を説明します。 1つをインストールします。
サービスユニットの構造
サービスユニットとは何ですか? .service
サフィックスが付いたファイルには、systemd によって管理されるプロセスに関する情報が含まれています。これは 3 つの主要なセクションで構成されています。
[ユニット]: このセクションには、サービスの説明など、ユニットの種類に特に関係しない情報が含まれます。
[サービス]: ユニットの特定のタイプに関する情報が含まれます。この場合はサービスです。
[インストール]: このセクションにはユニットのインストールに関する情報が含まれています
それぞれを詳しく分析してみましょう。
[単位]セクション
.service
ファイルの [Unit]
セクションには、ユニット自体の説明と、その動作とその依存関係に関する情報が含まれています (サービスが正しく動作するためには、次のものに依存できます)もう一つ)。ここでは、このセクションで使用できる最も関連性の高いオプションのいくつかについて説明します。
「説明」オプション
まず、Description
オプションがあります。このオプションを使用すると、ユニットの説明を提供できます。この説明は、たとえば、systemd のステータスの概要を返す systemctl
コマンドを呼び出すときに表示されます。ここでは、例として、Fedora システム上で httpd
サービスの記述がどのように定義されているかを示します。
[Unit]
Description=The Apache HTTP Server
「後」オプション
After
オプションを使用すると、スペース区切りのリストの形式で提供するユニットの後にユニットを開始する必要があると指定できます。たとえば、Apache Web サービスが定義されているサービス ファイルを再度観察すると、次のことがわかります。
After=network.target remote-fs.target nss-lookup.target httpd-init.service
上記の行は、network
、remove-fs
、nss-lookup< の後にのみサービス ユニット
ターゲットと httpd.service
を開始するように systemd に指示します。httpd-init サービス
。
「Requires」によるハード依存関係の指定
上で簡単に述べたように、ユニット (この場合はサービス) は、正しく動作するために他のユニット (必ずしも「サービス」ユニットではない) に依存することができます。そのような依存関係は、Requires
オプションを使用して宣言できます。
サービスが依存するユニットのいずれかが開始に失敗すると、サービスのアクティブ化が停止します。これが、これらが ハード依存関係
と呼ばれる理由です。 avahi-daemon のサービス ファイルから抽出されたこの行では、avahi-daemon.socket ユニットからの依存関係としてどのように宣言されているかがわかります。
Requires=avahi-daemon.socket
「ウォンツ」による「ソフト」依存関係の宣言
Requires
オプションを使用して、サービスのいわゆる「ハード」依存関係を宣言する方法を説明しました。 Wants
オプションを使用して、「ソフト」依存関係をリストすることもできます。
違いはなんですか?上で述べたように、「ハード」依存関係が失敗すると、サービス自体も失敗します。ただし、「ソフト」依存関係が失敗しても、依存するユニットの動作には影響しません。提供された例では、 docker.service
ユニットが docker-storage-setup.service
ユニットに対してどのようにソフトな依存関係を持っているかがわかります。
[Unit]
Wants=docker-storage-setup.service
[サービス]セクション
service
ユニットの [Service]
セクションでは、サービスの開始時に実行するコマンドやサービス自体の種類を指定できます。そのうちのいくつかを見てみましょう。
サービスの開始、停止、リロード
サービスは開始、停止、再起動、またはリロードできます。これらの各アクションを実行するときに実行されるコマンドは、[Service]
セクションの関連オプションを使用して指定できます。
サービスの開始時に実行されるコマンドは、ExecStart
オプションを使用して宣言されます。オプションに渡される引数は、スクリプトへのパスにすることもできます。オプションで、 ExecStartPre
オプションと ExecStartPost
オプションをそれぞれ使用して、サービスの開始前と開始後に実行されるコマンドを宣言できます。 NetworkManager サービスを開始するために使用されるコマンドは次のとおりです。
[Service]
ExecStart=/usr/sbin/NetworkManager --no-daemon
同様の方法で、ExecStop
オプションと ExecReload
オプションを使用して、サービスがリロードまたは停止されたときに実行されるコマンドを指定できます。 ExecStartPost
の場合と同様に、プロセスの停止後に起動する 1 つまたは複数のコマンドを ExecStopPost
オプションで指定できます。
サービスの種類
Systemd は、予期される動作に応じて、いくつかの異なるタイプのサービスを定義し、区別します。サービスのタイプは、Type
オプションを使用して次のいずれかの値を指定して定義できます。
単純
フォーク
ワンショット
dバス
通知する
Type
オプションと Busname
オプションが定義されていないが、コマンドが ExecStart
オプションを介して提供されている場合、サービスのデフォルトのタイプは シンプル
。このタイプのサービスが設定されている場合、ExecStart
で宣言されたコマンドがメイン プロセス/サービスとみなされます。
forking
タイプの動作は異なります。ExecStart
で提供されるコマンドは、メイン プロセス/サービスとなる子プロセスをフォークして起動することが期待されます。起動プロセスが終了すると、親プロセスは終了すると予想されます。
Type
オプションと ExecStart
オプションが定義されていない場合は、oneshot
タイプがデフォルトとして使用されます。これは simple
とほとんど同じように動作します。違いは、他のユニットが起動される前にプロセスがジョブを完了することが期待されることです。ただし、RemainAfterExit
オプションが「yes」に設定されている場合 (デフォルトは「no」)、コマンドが終了した後でもユニットは「アクティブ」とみなされます。
次のタイプのサービスは dbus
です。このタイプのサービスが使用される場合、デーモンは BusName
オプションで指定されているように Dbus
から名前を取得することが期待されます。この場合、これは必須になります。残りの部分については、simple
タイプと同様に機能します。ただし、後続のユニットは、DBus 名が取得された後にのみ起動されます。
もう 1 つのプロセスは simple
と同様に機能し、それは notify
です。違いは、デーモンが sd_notify
関数を介して通知を送信することが期待されることです。この通知が送信されると、その後のユニットが起動されます。
プロセスのタイムアウトを設定する
特定のオプションを使用すると、サービスのタイムアウトを定義できます。 RestartSec
から始めましょう: このオプションを使用すると、サービスを再起動する前に systemd が待機する時間 (デフォルトでは秒単位) を設定できます。 「5 分 20 秒」のように、このオプションの値としてタイムスパンを使用することもできます。デフォルトは 100ms
です。
TimeoutStartSec
オプションと TimeoutStopSec
オプションを使用して、それぞれサービスの起動と停止のタイムアウトを秒単位で指定できます。最初のケースでは、指定されたタイムアウトを過ぎてもデーモンの起動プロセスが完了しない場合、失敗したとみなされます。
2 番目のケースでは、サービスを停止する必要があるが、指定されたタイムアウト後に終了しない場合、最初に SIGTERM
が実行され、次に同じ時間が経過した後に SIGKILL
が実行されます。信号が送信されます。どちらのオプションもタイムスパンを値として受け入れ、ショートカット TimeoutSec
を使用して一度に設定できます。 infinity
が値として指定された場合、タイムアウトは無効になります。
最後に、RuntimeMaxSec
を使用して、サービスの実行時間の制限を設定できます。サービスがこのタイムアウトを超えると、サービスは終了され、失敗したとみなされます。
[インストール]セクション
[install]
セクションでは、サービスのインストールに関連するオプションを使用できます。たとえば、Alias
オプションを使用すると、systemctl コマンド (enable
を除く) を使用するときにサービスに使用するエイリアスのスペース区切りのリストを指定できます。
[Unit]
セクションの Requires
オプションと Wants
オプションを使用して依存関係を確立する場合と同様に、[install]
セクションでは、RequiredBy
と WantedBy
を使用できます。どちらの場合も、構成しているユニットに依存するユニットのリストを宣言します。前者のオプションではユニットにハード依存し、後者のオプションでは弱い依存とみなされます。例えば:
[Install]
WantedBy=multi-user.target
上の行で、multi-user
ターゲットがユニットに対してソフトな依存関係があることを宣言しました。 systemd 用語では、.target
接尾辞で終わるユニットは、他の init システムでは Sysvinit
として runtimes
と呼ばれるものに関連付けることができます。したがって、私たちの場合、マルチユーザー目標に達した場合、その目標には私たちのサービスが含まれるはずです。
サービスユニットの作成とインストール
systemd サービスユニットがインストールされるファイルシステムには基本的に、/usr/lib/systemd/system
と /etc/systemd/system
の 2 つの場所があります。前者のパスは、インストールされたパッケージによって提供されるサービスに使用されますが、後者のパスは、システム管理者がデフォルトのサービスをオーバーライドできる独自のサービスに使用できます。
カスタム サービスの例を作成してみましょう。特定のイーサネット インターフェイス (この場合は ens5f5) の wake-on-lan 機能を開始時に無効にし、停止時に再度有効にするサービスを作成するとします。 ethtool
コマンドを使用して、主要なタスクを実行できます。サービス ファイルは次のようになります。
[Unit]
Description=Force ens5f5 ethernet interface to 100Mbps
Requires=Network.target
After=Network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ethtool -s ens5f5 wol d
ExecStop=/usr/sbin/ethtool -s ens5f5 wol g
[Install]
WantedBy=multi-user.target
簡単なユニットの説明を設定し、サービスが network.target
ユニットに依存し、ユニットに到達した後に起動する必要があることを宣言しました。 [Service]
セクションでは、サービスのタイプを oneshot
として設定し、 を使用してコマンドの実行後にサービスがアクティブであるとみなすように systemd に指示しました。 >RemainAfterExit
オプション。また、サービスの開始時と停止時に実行されるコマンドも定義しました。最後に、[Install]
セクションで、サービスを multi-user
ターゲットに含める必要があることを基本的に宣言しました。
サービスをインストールするには、ファイルを /etc/systemd/system
ディレクトリに wol.service
としてコピーし、開始します。
$ sudo cp wol.service /etc/systemd/system && sudo systemctl start wol.service
次のコマンドを使用して、サービスがアクティブであることを確認できます。
$ systemctl is-active wol.service
active
コマンドの出力は、予想どおり、active
です。ここで、「wake on lan」が d
に設定され、無効になっていることを確認するには、次のコマンドを実行します。
$ sudo ethtool ens5f5|grep Wake-on
Supports Wake-on: pg
Wake-on: d
ここで、サービスを停止すると逆の結果が生成され、wol が再度有効になります。
$ sudo systemctl stop wol.service && sudo ethtool ens5f5|grep Wake-on
Supports Wake-on: pg
Wake-on: g
結論
このチュートリアルでは、systemd サービス ファイルがどのように構成されるか、そのセクションとは何か、そして各セクションで使用できるいくつかのオプションについて説明しました。サービスの説明を設定し、その依存関係を定義し、サービスの開始、停止、またはリロード時に実行する必要があるコマンドを宣言する方法を学びました。
systemd は好むと好まざるにかかわらず、Linux の世界では標準の init システムになっているため、その動作方法に慣れることが重要です。 systemd サービスの公式ドキュメントは、freedesktop Web サイトにあります。 systemd を使用したサービスの管理に関する記事もお読みください。