概要
Systemdのユニットファイルの中にAfter=network.target
といった記述をよく見かけますが、ややこしい仕様なので、誤解の無いようネットワーク関連ユニットの概要を抑えておくことが大事です。
本記事は、Systemdのネットワーク関連ユニットの概要をまとめたものです。対象は主にRHEL7、CentOS7以降です。
なお、Systemdの基本的なサービス管理については、こちらの記事にまとめてあります。
本記事の目的
After=network.target
の意味を把握する。- ネットワークを待ってサービス起動する設定(network-online.target)を把握する。
- ネットワーク関連ユニットの概要を把握する。
目次
基本
After=network.target ≠ ネットワーク疎通可
サービスのユニットファイルにAfter=network.target
が記載されていても、それは「ネットワーク疎通できるようになった後にそのサービスを起動する」ということを保証するものではありません。
例えば、httpdはユニットファイルに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の指定でも同様の事象が起きることがあると思います。
ネットワーク疎通できるようになった後にそのサービスを起動したい場合は、
network-online.target
というユニットとの順序関係を指定します。
順に説明していきます。
ネットワークを待ってサービス起動する設定(network-online.target)
ネットワーク疎通(※)ができるようになってからサービスを起動する設定について説明します。
(※)本記事では、ネットワークインタフェースの設定(IPアドレス割り当てなど)が完了した状態を指します。そのIPアドレスに対するソケット割り当て(バインド)ができる状態です。
元のユニットファイルを直接編集せず、以下のようにdrop-in(別の設定ファイルを追加)を利用します。例としてhttpdの場合の手順を記載しますが、他のサービスでも同様です。drop-inの詳細はman systemd.unit
で確認できます。
# systemctl edit httpd
にて、以下を記載します。
[Unit] After=network-online.target Wants=network-online.target
その後、
# systemctl daemon-reload
を実行してsystemdに読み込ませると、設定完了です。
httpdはネットワーク疎通できるようになってからサービス起動するようになります。
詳細は、後述します。
詳細
drop-inの管理TIPS
drop-inを設定すると、以下のようにdrop-inファイルが作成されます。インストール時に配置された元のユニットファイルを変更せず、別ファイルに設定を追加する形です。
$ cat /etc/systemd/system/httpd.service.d/override.conf
[Unit] After=network-online.target Wants=network-online.target
drop-inが存在していることは、以下のように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
drop-inを修正したいときは、systemctl edit
で可能です。
なお、drop-inを削除したいときは、編集画面で中身を空にして保存してもキャンセルされてしまい削除できないので注意が必要です。
# systemctl edit httpd
(drop-inファイルを空にして保存しようとした場合) Editing "/etc/systemd/system/httpd.service.d/override.conf" canceled: temporary file is empty.
drop-inを削除したいときは、以下のようにsystemctl revert
を利用可能です。ただし、必要なファイルも削除されないか注意が必要です。
# systemctl revert httpd
Removed /etc/systemd/system/httpd.service.d/override.conf. Removed /etc/systemd/system/httpd.service.d.
systemctl revert
により、指定したユニットのdrop-inファイルが削除されますが、他に手動で修正したユニットファイルも削除(※)されるようですので注意が必要です。systemctl revert
ではどうしても支障がある場合は、手動でdrop-inファイルを削除する方が無難でしょう。
(※)詳細な動作は確認していませんが、/usr/lib/配下のオリジナルのユニットファイル(vendor-supplied)を/etc/system/system配下等にコピーしてから修正した同名のユニットファイルがあればそれが削除され、オリジナルのユニットファイルのみが存在する状態に戻るようです。なお、オリジナルのユニットファイルが無く、自作したユニットファイルが1つあるだけであれば、それは削除されずに残るはずです。
drop-inで追加した設定が反映されていることは、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-online.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はパッシブユニットなので、通常のサービス(consumer)において、After=network.target
のように順序関係を指定しても良いですが、Wants=network.target
やRequires=network.target
のように依存関係を指定してはいけません。
パッシブユニットに関する詳細な記述が見つけられませんでしたが、パッシブユニットのユニットファイルには、RefuseManualStart=yes
が記載されているようです。
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秒のようです。
なお、補足事項として、systemd開発プロジェクトをホストしているらしいfreedesktop.orgの説明ページによると、ネットワークを利用するサーバソフトウェアのサービスにおいてAfter=network-online.target
を多用しないことが強く推奨されているようです。これは、例えばサーバソフトウェアはネットワーク起動前であってもローカルコネクションを受け付ける方が一般的には望ましく、そもそもAfter=network-online.target
の主目的がネットワーク無しでは動作できないクライアントソフトウェアのためにあると説明されています。
また、開発者向けに、ネットワーク設定が動的に変わっても動作するようプログラムを修正することを勧めています。
ただ、実際には例えばhttpdの自動起動失敗を回避するためAfter=network-online.target
を指定したいケースもあるので、システム管理者からすると、なかなかこの思想の通りに運用するのは難しいところです。
以下、freedesktop.orgの説明ページより引用。
It is strongly recommended not to pull in 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.
https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
ちなみに、network-online.targetは、network.targetとは異なりパッシブユニットではありません。通常のサービス(consumer)において、After=network.target
のように順序関係を指定する以外に、Wants=network.target
やRequires=network.target
のように依存関係を指定できます。
前述の設定例では、After=network.target
とWants=network.target
の両方を指定しています(freedesktop.orgの説明ページの設定例と同等)。
(参考)NetworkManager-dispatcher.service
特殊ユニットではなく、通常のユニットです。
これもNetworkManager関連のユニットで、dispatcherはネットワークイベントが発生した場合に、スクリプトを実行するもののようです。
詳細は省略します。