Systemdのネットワーク関連ユニット (After=network.targetあたり)
Systemdのユニットファイルの中にAfter=network.target
という記述をよく見かけますが、ちょっとややこしい仕様です。
本記事は、Systemdのそのあたりのネットワーク関連ユニットの概要をまとめたものです。対象は主にRHEL7、CentOS7以降です。
Systemdに関する基本的な内容は、以下の記事にまとめてあります。
本記事の目的
After=network.target
の意味を把握する。- ネットワークが起動してからサービス起動する設定を把握する (network-online.target)。
- ネットワーク関連ユニットの概要を把握する。
基本
After=network.target ≠ ネットワーク疎通可
サービスのユニットファイルにAfter=network.target
が記載されていても、それは「ネットワーク疎通できるようになった後にそのサービスを起動する」ということを保証するものではありません。
httpdやpostfixが起動失敗するケース
例えば、httpd サービスのユニットファイル (httpd.service) には、After=network.target
が記載されています。
httpd.conf にて特定のIPアドレスのみを Listen するよう指定している環境において、OS起動時に、そのIPアドレスが使用可能になる前に httpd サービスの起動が開始されてしまうと、Cannot assign requested address: AH00072: make_sock: could not bind to address x.x.x.x:443
といったエラーで起動失敗します。
postfixのinet_interfacesの指定でも同様の事象が起きることがあります (fatal: parameter inet_interfaces: no local interface found for x.x.x.x
)。
network.target でなく network-online.target
ネットワークの起動が完了した後にそのサービスを起動したい場合は、network-online.target
というユニットとの順序関係を指定します。
順に説明していきます。
ネットワークを待ってサービス起動する設定(network-online.target)
ネットワーク疎通(※)ができるようになってからサービスを起動する設定について説明します。
(※)本記事では、ネットワークインタフェースの設定(IPアドレス割り当てなど)が完了した状態を指します。そのIPアドレスに対するソケット割り当て(バインド)ができる状態です。
元のユニットファイルを直接編集しても良いですが、保守性を考慮し、以下のようにドロップインスニペット (drop-in file、別の設定ファイル) を利用します。ユニットファイルのカスタマイズの全般的なことについては、以下の記事にまとめてあります。
例としてhttpdの場合の手順を記載しますが、他のサービスでも同様です。
# systemctl edit httpd
にて、以下を記載します。
[Unit] After=network-online.target Wants=network-online.target
エディタはデフォルトでvimでなくnanoが起動します(参考1、参考2)。
nanoでは、上記を記載後、Ctrl+”S”(上書き保存)→Ctrl+”X”(閉じる)で保存と終了ができます。もしくは、Ctrl+”X”(閉じる)→保存するか聞かれたら”Y”(はい)→ファイル名の確認でEnterでも同様です。
# systemctl edit httpd
にて設定変更した際は、# systemctl daemon-reload
を実行しなくても自動的にsystemdが再読み込みしてくれるようです。
(ユニットファイルを手動変更した場合には、systemdに再読み込みさせるため# systemctl daemon-reload
が必要)
この設定により、httpdはネットワーク疎通できるようになってからサービス起動するようになります。
詳細は、後述します。
詳細
ドロップインスニペット (drop-in file) の管理TIPS
ドロップインスニペットを設定すると、以下のようにファイルが作成されます。インストール時に配置された元のユニットファイルを変更せず、別ファイルに設定を追加する形です。
$ cat /etc/systemd/system/httpd.service.d/override.conf
[Unit] After=network-online.target Wants=network-online.target
ドロップインスニペットの存在確認
あるユニットにドロップインスニペットが存在していることは、以下のようにsystemctl status
の結果にDrop-In:
行が表示されることでも確認できます。
$ systemctl status httpd
● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) Drop-In: /etc/systemd/system/httpd.service.d └override.conf
ドロップインスニペットの修正
ドロップインスニペットを修正したいときは、前述の手順と同様に、systemctl edit
で可能です。
ドロップインスニペットの削除
ドロップインスニペットを削除したいときは、編集画面で中身を空にして保存してもキャンセルされてしまい削除できないので注意が必要です。
# systemctl edit httpd
(ドロップインスニペットのファイルを空にして保存しようとした場合) Editing "/etc/systemd/system/httpd.service.d/override.conf" canceled: temporary file is empty.
ドロップインスニペットを削除したいときは、以下のようにsystemctl revert
を利用できます。ただし、必要なファイルも削除されないか注意が必要です。
# systemctl revert httpd
Removed /etc/systemd/system/httpd.service.d/override.conf. Removed /etc/systemd/system/httpd.service.d.
systemctl revert
により、指定したユニットのドロップインスニペットが削除されますが、他に手動で修正したユニットファイルも削除(※)されるようなので注意が必要です。systemctl revert
ではどうしても支障がある場合は、手動でドロップインスニペットのファイルを削除する方が無難でしょう。
(※)詳細な動作は確認していませんが、/usr/lib/配下のオリジナルのユニットファイル(vendor-supplied)を/etc/system/system配下等にコピーしてから修正した同名のユニットファイルがあればそれが削除され、オリジナルのユニットファイルのみが存在する状態に戻るようです。なお、オリジナルのユニットファイルが無く、自作したユニットファイルが1つあるだけであれば、それは削除されずに残るはずです。
ドロップインスニペットによる設定の反映確認
ドロップインスニペットで追加した設定が反映されていることは、systemctl show
でも確認できます。
$ systemctl show httpd
… After=remote-fs.target nss-lookup.target system.slice systemd-tmpfiles-setup.service httpd-init.service tmp.mount systemd-journald.socket basic.target sysinit.target -.mount network-online.target network.target (お使いの環境によって、改行されず見切れるので続きを見る場合は → キーで最後まで見られます) …
ネットワーク関連ユニットの把握
After=network.target
の意味や、関連する特殊ユニットについて説明します。
概要
システム起動時、以下のnetwork-pre.targetから順にユニットが起動されます。
- network-pre.target
↑After
- NetworkManager.service
↓Before(,Wants)
- network.target (After=network-pre.target含む)
↑ Requires
- NetworkManager-wait-online.service (After=NetworkManager.service含む)
↓ Before(,WantedBy)
- network-online.target (After=network.target含む)
※NetworkManager-dispatcher.serviceについては省略
グレーの矢印 (↑、↓) や補記は、矢印の元のユニットにおいてBefore,After等の順序関係が矢印の先のユニットに対して指定されていることを示しています。依存関係 (Wants,Requires等) も記載しています。
「network~」はsystemdにおけるネットワーク関連の特殊ユニット(詳細はman systemd.special
)、「NetworkManager~」はOS標準のネットワーク管理サービスであるNetworkManager関連のユニットです。
systemctl list-dependencies
でユニットの依存関係を確認してみると、システム起動時には、NetworkManager.serviceが起動するよう指定されていることが分かります(NetworkManager.serviceは、WantedBy=multi-user.target
が指定されています)。
$ systemctl list-dependencies
default.target … ● ├NetworkManager.service …
また参考までに、各ユニットは以下のように有効化(enabled)、もしくは特殊ユニットの場合はstaticになっていることが分かります。
# systemctl list-unit-files | grep NetworkManager
NetworkManager-dispatcher.service enabled NetworkManager-wait-online.service enabled NetworkManager.service enabled
# systemctl list-unit-files | grep network
network-online.target static network-pre.target static network.target static
次に、各ユニットの説明をします。
1. network-pre.target
特殊ユニットの1つで、サービスの起動順序の制御等に使用されます。
ネットワークインタフェースの設定前に実行されるユニットです。
なお、network-pre.targetは、network.targetと同様にパッシブユニットです。パッシブユニットについては後述のnetwork.targetの箇所で説明します。
2. NetworkManager.service
特殊ユニットではなく、通常のユニットです。
NetworkManagerのメインのユニットです。ネットワークインタフェースの設定処理等を実行します。
3. network.target (重要)
特殊ユニットの1つで、サービスの起動順序の制御等に使用されます。
After=network.target
が指定されたユニット(サービス)の起動は、ネットワーク疎通可能になるまで遅延される訳ではありません。
systemdがnetwork.targetを起動すると、ネットワークの設定を行うサービスが開始した状態にはなりますが、それはネットワークデバイスの設定(IPアドレス設定等)までが完了した状態ではありません。
そのため、After=network.target
が指定されたユニットは、OS起動時にはnetwork.targetの起動後に自身のサービスを起動し始めるのですが、まだその時点ではIPアドレスが使用可能になっていないこともあるので、その場合にはソケット割り当て(バインド)が失敗してしまいます。
では、何のためにAfter=network.target
が指定されているサービスがあるのかと言うと、それは起動時でなく停止時の順序制御のためのようです。
After=network.target
が指定されたユニットが停止するまで、network.targetの停止処理が開始されることはありません。
つまり、自身が停止するまでネットワークが起動していないといけないサービスには、After=network.target
を指定しておくべきということになります。
このように、停止時の順序の話になると、「After」という単語の意味とは逆の働きをするので、ややこしいです。
network.targetはパッシブユニットです。パッシブユニットについては後述します。
4. NetworkManager-wait-online.service
特殊ユニットではなく、通常のユニットです。
これもNetworkManager関連のユニットです。
NetworkManager-wait-online.serviceは、後述のnetwork-online.targetより先に起動します。After=network-online.target
を設定したときに実質的なネットワーク起動完了を判定するのが、このNetworkManager-wait-online.serviceなのだと思います。
NetworkManager-wait-online.serviceのユニットファイルには、Before=network-online.target
が記載されています。
つまり、NetworkManager-wait-online.serviceが起動完了(=ネットワーク起動完了)してから、network-online.targetの起動が開始されるということです。
5. network-online.target (重要)
特殊ユニットの1つで、サービスの起動順序の制御等に使用されます。
network.targetの場合とは異なり、After=network-online.target
が指定されたユニットの起動は、ネットワーク疎通可能になるまで遅延されます。
前述のNetworkManager-wait-online.serviceがネットワーク起動(IPアドレス設定等)が完了したことを判定後、network-online.targetが起動完了となります。その後にAfter=network-online.target
が指定されたユニットが起動開始されますので、確かにネットワーク疎通可になってから起動できます。
network-online.target自体のタイムアウトは90秒のようです。
なお、開発元によると、ネットワークを利用するサーバソフトウェアのサービスにおいてAfter=network-online.target
を多用しないことが強く推奨されているようです (後述)。これは、例えばサーバソフトウェアはネットワーク起動前であってもローカルコネクションを受け付ける方が一般的には望ましく、そもそもAfter=network-online.target
の主目的がネットワーク無しでは動作できないクライアントソフトウェアのためにあると説明されています。
また、開発者向けに、ネットワーク設定が動的に変わっても動作するようプログラムを修正することを求めています。
ただ、実際には例えばhttpdの自動起動失敗を回避するためAfter=network-online.target
を指定したいケースもあるので、システム管理者からすると、なかなかこの思想の通りに運用するのは難しいところです。
以下、開発元のページより引用。
It is strongly recommended not to make use of this target too liberally: for example network server software should generally not pull this in (since server software generally is happy to accept local connections even before any routable network interface is up). Its primary purpose is network client software that cannot operate without network.
…
If you are a developer, instead of wondering what to do about network.target, please just fix your program to be friendly to dynamically changing network configuration.
…
出典:systemd.io
ちなみに、network-online.targetは、network.targetとは異なりパッシブユニットではありません。
(参考)NetworkManager-dispatcher.service
特殊ユニットではなく、通常のユニットです。
これもNetworkManager関連のユニットで、dispatcherはネットワークイベントが発生した場合に、スクリプトを実行するもののようです。
詳細は省略します。
(補足) Systemdの用語
※公式ドキュメントにハッキリとした定義が見当たらないので、私が理解している範囲でまとめています。
passive unit
パッシブユニットとアクティブユニットに関する簡単な説明です (開発元のドキュメント)。
パッシブユニットは、直接起動 (systemctl start
) することはできません。他のサービス (provider) によって依存関係が指定される場合があります。通常、他のサービス (consumer) によって依存関係は指定されません。これには、パッシブユニットがトランザクションの一部でなく、順序のために存在するという理由があるようです。
例えば、パッシブユニットであるnetwork.targetは、consumer によって After=network.target
のように順序関係を指定される場合がありますが、Wants=network.target
やRequires=network.target
のように依存関係は通常指定されません。
一方、非パッシブユニット (通常のユニット?アクティブユニット?) については、そのようなことは無いようです。
例えば、非パッシブユニット (active target?) である network-online.targetは、consumer によって Wants=network.target
やRequires=network.target
のように依存関係を指定される場合があります。順序関係を指定される場合もあります。
実際、前述の設定例では、httpd (consumer) において、After=network.target
と Wants=network.target
の両方を指定しています(開発元の設定例と同等)。
なお、パッシブユニットのユニットファイルには、RefuseManualStart=yes
が記載されているようです (明確な説明はありませんが)。
provider、consumer
前述のproviderとconsumerについても、公式ドキュメントに詳細な記述が見当たらないのですが、基本的には、あるユニットが他のユニットを利用する場合、利用する側のユニットがconsumer、利用される側のユニットがproviderという意味のようです (つまり文脈依存)。
例えば、systemd-resolved というユニットが、他のパッケージによって管理されている /etc/resolv.conf 内の設定を参照するケースでは、systemd-resolved は provider でなく consumer となるようです (開発元のドキュメント)。
参考URL等
-
RedHat社マニュアル(英語) ※英語の方が意味を読み取りやすいかも
-
man関連
man systemd.special
man systemd.unit (drop-in fileの説明を含む)
man systemctl