GNU/Linux >> Linux の 問題 >  >> Linux

systemdを使用してスタートアップを管理する

最近Linuxシステムをセットアップしているときに、サービスや他のユニットの依存関係が、それらの依存するサービスやユニットが開始する前に稼働していることを確認する方法を知りたいと思いました。具体的には、systemdが起動シーケンスを管理する方法、特に基本的に並列システムでサービスが開始される順序を決定する際に、より多くの知識が必要でした。

SystemV(このシリーズの最初の記事で説明したように、systemdの前身)は、起動スクリプトにSXXプレフィックス(XXは00から99までの数字)を付けて起動シーケンスを順序付けます。次に、SystemVは並べ替え順序を使用します。名前を付けて、各開始スクリプトを目的の実行レベルに合わせて順番に実行します。

ただし、systemdは、システム管理者が作成または変更できるユニットファイルを使用して、初期化だけでなく通常の操作用のサブルーチンを定義します。このシリーズの3番目の記事では、マウントユニットファイルの作成方法について説明しました。この5番目の記事では、別の種類のユニットファイル(起動時にプログラムを実行するサービスユニットファイル)を作成する方法を示します。ユニットファイルの特定の構成設定を変更し、systemdジャーナルを使用して、起動シーケンスでの変更の場所を表示することもできます。

準備

rhgbを削除したことを確認してください およびquiet GRUB_CMDLINE_LINUX =から / etc / default / grubの行 このシリーズの2番目の記事で示したように、ファイル。これにより、この記事のいくつかの実験に必要なLinuxスタートアップメッセージストリームを観察できます。

プログラム

このチュートリアルでは、起動時にコンソールでメッセージを監視し、後でsystemdジャーナルでメッセージを監視できるようにする簡単なプログラムを作成します。

シェルプログラム/usr/local/bin/hello.shを作成します 次のコンテンツを追加します。起動時に結果が表示され、systemdジャーナルを調べたときに簡単に見つけられるようにする必要があります。 「Helloworld」プログラムのバージョンを使用し、その周りにいくつかのバーがあるので、目立ちます。ファイルが実行可能であり、セキュリティのために700の権限を持つrootによるユーザーとグループの所有権を持っていることを確認してください:

#!/usr/bin/bash
# Simple program to use for testing startup configurations
# with systemd.
# By David Both
# Licensed under GPL V2
#
echo "###############################"
echo "######### Hello World! ########"
echo "###############################"

コマンドラインからこのプログラムを実行して、正しく機能することを確認します。

[root@testvm1 ~]# hello.sh 
###############################
######### Hello World! ########
###############################
[root@testvm1 ~]#

このプログラムは、任意のスクリプト言語またはコンパイル言語で作成できます。 hello.sh プログラムは、Linuxファイルシステム階層構造(FHS)に基づいて他の場所に配置することもできます。 / usr / local / binに配置します コマンドを入力するときにパスを追加しなくても、コマンドラインから簡単に実行できるようにディレクトリを作成します。私が作成するシェルプログラムの多くは、コマンドラインから実行する必要があり、systemdなどの他のツールで実行する必要があることがわかりました。

サービスユニットファイル

サービスユニットファイル/etc/systemd/system/hello.serviceを作成します 以下の内容で。このファイルは実行可能である必要はありませんが、セキュリティのために、rootおよび644または640のアクセス許可によるユーザーとグループの所有権が必要です。

# Simple service unit file to use for testing 
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh

[Install]
WantedBy=multi-user.target

サービスステータスを表示して、サービスユニットファイルが期待どおりに機能することを確認します。構文エラーはここに表示されます:

[root@testvm1 ~]# systemctl status hello.service 
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)
[root@testvm1 ~]#

この「ワンショット」サービスタイプは、問題なく複数回実行できます。ワンショットタイプは、サービスユニットファイルによって起動されたプログラムがメインプロセスであり、systemdが依存プロセスを開始する前に完了する必要があるサービスを対象としています。

7つのサービスタイプがあり、systemd.service(5)のマニュアルページでそれぞれの説明を(サービスユニットファイルの他の部分とともに)見つけることができます。 (詳細については、この記事の最後にあるリソースを参照してください。)

私は好奇心が強いのですが、エラーがどのように見えるかを見たかったのです。そこで、 Type =oneshotから「o」を削除しました 行なので、 Type =neshotのように見えました 、コマンドを再度実行しました:

[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 06 08:50:09 testvm1.both.org systemd[1]: /etc/systemd/system/hello.service:12: Failed to parse service type, ignoring: neshot
[root@testvm1 ~]#

これらの結果は、エラーがどこにあるかを正確に教えてくれ、問題の解決を非常に簡単にしました。

その他のLinuxリソース

  • Linuxコマンドのチートシート
  • 高度なLinuxコマンドのチートシート
  • 無料のオンラインコース:RHELの技術概要
  • Linuxネットワーキングのチートシート
  • SELinuxチートシート
  • Linuxの一般的なコマンドのチートシート
  • Linuxコンテナとは何ですか?
  • 最新のLinux記事

hello.serviceを復元した後でも注意してください ファイルを元の形式にすると、エラーが持続します。再起動するとエラーがクリアされますが、そうする必要はないので、このような永続的なエラーをクリアする方法を探しました。コマンドsystemctldaemon-reloadを必要とするサービスエラーが発生しました エラー状態をリセットしますが、この場合は機能しませんでした。このコマンドで修正できるエラーメッセージには、常にその旨のステートメントが含まれているように見えるので、実行することを知っています。

ただし、 systemctl daemon-reloadを実行することをお勧めします。 ユニットファイルを変更した後、または新しいファイルを作成した後。これにより、変更が行われたことがsystemdに通知され、変更されたサービスまたはユニットの管理に関する特定のタイプの問題を防ぐことができます。先に進み、このコマンドを実行します。

サービスユニットファイルのスペルミスを修正した後、単純な systemctl restart hello.service エラーをクリアしました。 hello.service に他のエラーを導入して、少し実験してください。 ファイルを作成して、どのような結果が得られるかを確認してください。

サービスを開始する

これで、新しいサービスを開始し、ステータスを確認して結果を確認する準備が整いました。前のセクションで再起動した可能性がありますが、ワンショットサービスは一度実行してから終了するため、何度でも開始または再起動できます。

先に進んでサービスを開始し(以下を参照)、ステータスを確認します。エラーをどれだけ試したかによって、結果は私のものとは異なる場合があります:

[root@testvm1 ~]# systemctl start hello.service 
[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

statusコマンドの出力で、systemdメッセージが hello.shを示していることに注意してください。 スクリプトが開始され、サービスが完了しました。スクリプトからの出力も確認できます。この表示は、サービスの最新の呼び出しのジャーナルエントリから生成されます。サービスを数回開始してから、statusコマンドをもう一度実行して、意味を確認してください。

また、ジャーナルの内容を直接確認する必要があります。これを行うには複数の方法があります。 1つの方法は、レコードタイプ識別子(この場合はシェルスクリプトの名前)を指定することです。これにより、以前の再起動のジャーナルエントリと現在のセッションが表示されます。ご覧のとおり、私はこの記事の調査とテストをしばらく行っています:

[root@testvm1 ~]# journalctl -t hello.sh
<snip>
-- Reboot --
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
May 08 15:55:47 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
May 08 16:01:51 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

hello.serviceのsystemdレコードを見つけるには ユニット、systemdで検索できます。 G + Enterを使用できます ジャーナルエントリの最後までページングしてから、スクロールして目的のエントリを見つけます。 -bを使用します。 最新のスタートアップのエントリのみを表示するオプション:

[root@testvm1 ~]# journalctl -b -t systemd
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:50 testvm1.both.org systemd[1]: Starting D-Bus System Message Bus...
May 10 10:37:50 testvm1.both.org systemd[1]: Started D-Bus System Message Bus.

私はあなたが見つけるかもしれないもののアイデアをあなたに与えるために他のいくつかのジャーナルエントリをコピーしました。このコマンドは、systemdに関連するすべてのジャーナル行を吐き出します—これを書いたときは109,183行です。これは、分類する必要のある大量のデータです。ポケットベルの検索機能を使用できます。これは通常、少ないです。 、または組み込みの grepを使用できます 特徴。 -g (または-grep = )オプションはPerl互換の正規表現を使用します:

[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:01:01 EDT. --
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

標準のGNUgrepを使用できます コマンドですが、最初の行にログメタデータが表示されません。

helloに関連するジャーナルエントリだけを表示したくない場合 サービスでは、時間範囲を指定することで少し絞り込むことができます。たとえば、 10:54:00の開始時刻から開始します。 上記のエントリの開始分であるテストVMで。 -since =に注意してください オプションは引用符で囲む必要があり、このオプションは-S"<時間指定>"として表すこともできます。 。

日付と時刻はホストによって異なるため、ジャーナルの時刻と一致するタイムスタンプを使用してください。

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:00"
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=54 op=LOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd"'
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/"'
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <error> [1589122560.0633] dhcp4 (enp0s3): error -113 dispatching events
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <info>  [1589122560.0634] dhcp4 (enp0s3): state changed bound -> fail
<snip>

since 仕様では、それ以前のすべてのエントリがスキップされますが、それ以降は不要なエントリがまだたくさんあります。 untilを使用することもできます 興味のある時間の少し後に来るエントリを削除するオプション。イベントが発生した1分だけが必要です:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:04:59 EDT. --
May 10 10:54:35 testvm1.both.org systemd[1]: Reloading.
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=27 op=UNLOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=26 op=UNLOAD
<snip>
ay 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
lines 1-46/46 (END)

この期間に多くのアクティビティがあった場合は、次のオプションの組み合わせを使用して、結果のデータストリームをさらに絞り込むことができます。

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00" -t "hello.sh"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:10:41 EDT. --
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

あなたの結果は私のものと似ているはずです。この一連の実験から、サービスが適切に実行されたことがわかります。

再起動-最終的に

これまでのところ、サービスをインストールしたホストを再起動していません。結局のところ、このハウツーは起動時にプログラムを実行することに関するものだからです。まず、起動シーケンス中にサービスを起動できるようにする必要があります。

[root@testvm1 ~]# systemctl enable hello.service 
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
[root@testvm1 ~]#

リンクが/etc/systemd/system/multi-user.target.wantsに作成されていることに注意してください。 ディレクトリ。これは、サービスユニットファイルで、サービスが multi-user.targetによって「必要」であると指定されているためです。 。

再起動し、起動シーケンス中にデータストリームを監視して、「Helloworld」メッセージを確認してください。待って…あなたはそれを見なかったのですか?まあ、私もそうではありませんでした。非常に速く進みましたが、 hello.serviceを開始しているというsystemdのメッセージが表示されました。 。

最新のシステム起動以降のジャーナルを確認してください。 lessを使用できます 「こんにちは」または「こんにちは」を見つけるためのポケットベルの検索ツール。多くのデータ行を削除しましたが、周囲のジャーナルエントリの一部を残したので、サービスに関連するエントリがローカルでどのように表示されるかを確認できます。

[root@testvm1 ~]# journalctl -b
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Listening on SSSD Kerberos Cache Manager responder socket.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Sockets.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Basic System.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Modem Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Network Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Avahi mDNS/DNS-SD Stack...
May 10 10:37:49 testvm1.both.org systemd[1]: Condition check resulted in Secure Boot DBX (blacklist) updater being skipped.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
May 10 10:37:49 testvm1.both.org systemd[1]: Started irqbalance daemon.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=irqbalance comm="systemd" exe="/usr/lib/sy>"'
May 10 10:37:49 testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Hardware Monitoring Sensors...
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting NTP client/server...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=livesys-late comm="systemd" exe="/usr/lib/>"'
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>"'
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
May 10 10:37:50 testvm1.both.org audit: BPF prog-id=28 op=LOAD
<snip>

systemdがhello.serviceを開始したことがわかります hello.shを実行したユニット ジャーナルに出力が記録されたシェルスクリプト。起動中にそれをキャッチできた場合は、スクリプトを開始していることを示すsystemdメッセージと、サービスが成功したことを示す別のメッセージも表示されます。上記のデータストリームの最初のsystemdメッセージを見ると、systemdが基本的なシステムターゲットに到達した直後にサービスを開始したことがわかります。

ただし、起動時にもメッセージが表示されるようにしたいと思います。これを実現する方法があります。次の行を[Service]に追加します。 hello.serviceのセクション ファイル:

StandardOutput=journal+console

hello.service ファイルは次のようになります:

# Simple service unit file to use for testing 
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh
StandardOutput=journal+console

[Install]
WantedBy=multi-user.target

この行を追加した後、システムを再起動し、起動プロセス中に表示が上にスクロールするデータストリームを監視します。小さなボックスにメッセージが表示されます。起動シーケンスが完了したら、最新の起動のジャーナルを表示して、新しいサービスのエントリを見つけることができます。

シーケンスの変更

サービスが機能しているので、起動シーケンスのどこから開始するかを確認し、変更してみることができます。 systemdの目的は、主要なターゲットのそれぞれの中で、できるだけ多くのサービスと他のユニットタイプを並行して開始することであることを覚えておくことが重要です: basic.target multi-user.target 、および graphics.target 。最新のブートのジャーナルエントリが表示されているはずです。これは、上記の出力の私のジャーナルに似ているはずです。

systemdは、ターゲットの基本システムに到達した直後にテストサービスを開始したことに注意してください。これは、 WantedByのサービスユニットファイルで指定したものです。 行なので、それは正しいです。何かを変更する前に、 /etc/systemd/system/multi-user.target.wantsの内容をリストしてください ディレクトリを開くと、サービスユニットファイルへのシンボリック(ソフト)リンクが表示されます。 [インストール] サービスユニットファイルのセクションでは、サービスを開始するターゲットを指定し、 systemctl enable hello.serviceを実行します。 コマンドは、適切な「ターゲットが欲しい」ディレクトリにリンクを作成します:

hello.service -> /etc/systemd/system/hello.service

特定のサービスは、 basic.targetの間に開始する必要があります 、およびその他は、システムが graphics.target を開始していない限り、開始する必要はありません。 。この実験のサービスは、 basic.targetでは開始されません - graphics.targetまで開始する必要がないと仮定します 。したがって、 WantedByを変更します 行:

WantedBy=graphical.target

必ずhello.serviceを無効にしてください 再度有効にすると、古いリンクが削除され、 graphicsal.targets.wantsに新しいリンクが追加されます。 ディレクトリ。必要なターゲットを変更する前にサービスを無効にするのを忘れた場合は、 systemctl disableを実行できることに気付きました。 コマンドを実行すると、リンクは両方の「targetwants」ディレクトリから削除されます。次に、サービスを再度有効にして再起動する必要があります。

graphics.targetでサービスを開始する際の1つの懸念 これは、ホストが multi-user.targetで起動する場合です。 、このサービスは自動的に開始されません。サービスがGUIデスクトップインターフェイスを必要とする場合、それはあなたが望むものかもしれませんが、それはあなたが望むものではないかもしれません。

graphics.targetのジャーナルエントリを確認します およびmulti-user.target -o short-monotonicを使用する カーネル起動後の秒数をマイクロ秒の精度で表示するオプション:

[root@testvm1 ~]# journalctl -b -o short-monotonic

multi-user.targetの結果 :

[   17.264730] testvm1.both.org systemd[1]: Starting My hello shell script...
[   17.265561] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<SNIP>
[   19.478468] testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
[   19.507359] testvm1.both.org iptables.init[844]: iptables: Applying firewall rules: [  OK  ]
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
[   19.507835] testvm1.both.org hello.sh[843]: ######### Hello World! ########
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
<SNIP>
[   21.482481] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   21.482550] testvm1.both.org smartd[856]: Opened configuration file /etc/smartmontools/smartd.conf
[   21.482605] testvm1.both.org systemd[1]: Finished My hello shell script.

そしてgraphical.targetのいくつかの結果 :

[   19.436815] testvm1.both.org systemd[1]: Starting My hello shell script...
[   19.437070] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<SNIP>
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.612614] testvm1.both.org hello.sh[841]: ######### Hello World! ########
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.629455] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629569] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629682] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   19.629782] testvm1.both.org systemd[1]: Finished My hello shell script.

graphics.targetがあるにもかかわらず ユニットファイルの「want」hello.service ユニットは起動から約19.5秒または19.6秒で動作します。しかし、 hello.service multi-user.targetで約17.24秒に開始します グラフィカルターゲットでは19.43秒。

これは何を意味するのでしょうか? /etc/systemd/system/default.targetを見てください リンク。そのファイルの内容は、systemdが最初にデフォルトのターゲット graphicsal.targetを開始することを示しています。 、次に multi-user.targetを取り込みます :

[root@testvm1 system]# cat default.target
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
[root@testvm1 system]#

graphics.targetでサービスを開始するかどうか またはmulti-user.target hello.service ユニットは起動開始から約19.5秒または19.6秒で動作します。これとジャーナルの結果(特に単調出力を使用した結果)に基づいて、これらのターゲットの両方が並行して開始していることがわかります。ジャーナル出力からもう1つ見てください:

[   28.397330] testvm1.both.org systemd[1]: Reached target Multi-User System.
[   28.397431] testvm1.both.org systemd[1]: Reached target Graphical Interface.

両方のターゲットはほぼ同時に終了します。 graphics.target であるため、これは一貫しています。 multi-user.targetを取得します multi.user targetまで終了できません 到達した、つまり終了しました。ただし、 hello.service これよりはるかに早く終了します。

これが意味するのは、これら2つのターゲットがほぼ並行して起動するということです。ジャーナルエントリを調べると、それらの主要なターゲットのそれぞれからのさまざまなターゲットとサービスがほぼ並行して開始されていることがわかります。 multi-user.target graphics.targetの前に完了する必要はありません 開始します。したがって、これらのプライマリターゲットを使用して起動をシーケンスするだけではうまく機能しませんが、ユニットが graphics.targetに必要な場合にのみ起動されるようにするのに役立ちます。 。

続行する前に、 hello.serviceを元に戻します WantedBy =multi-user.targetへのユニットファイル (まだの場合)

ネットワークの実行後にサービスが開始されるようにします

一般的な起動シーケンスの問題は、ネットワークが稼働した後にユニットが起動することを確認することです。 Freedesktop.orgの記事ネットワークが稼働した後にサービスを実行する ネットワークが「稼働中」と見なされる時期については、実際のコンセンサスはないと述べています。ただし、この記事には3つのオプションがあり、完全に機能するネットワークのニーズを満たすのは network-online.targetです。 。 network.targetに注意してください は起動ではなくシャットダウン中に使用されるため、起動をシーケンスしようとしているときには何の役にも立ちません。

他の変更を行う前に、必ずジャーナルを調べて、 hello.serviceを確認してください。 ユニットはネットワークのかなり前に起動します。 network-online.targetを探すことができます ジャーナルで確認してください。

サービスには実際にはネットワークサービスは必要ありませんが、必要なネットワークサービスのアバターとして使用できます。

WantedBy =graphics.targetを設定しているため ネットワークが稼働した後にサービスが開始されることを保証するものではありません。サービスが開始されることを保証する別の方法が必要です。 Fortunately, there is an easy way to do this. Add the following two lines to the [Unit] section of the hello.service unit file:

After=network-online.target                                                                             
Wants=network-online.target

Both of these entries are required to make this work. Reboot the host and look for the location of entries for your service in the journals:

[   26.083121] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0293] device (enp0s3): Activation: successful, device activated.
[   26.083349] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0301] manager: NetworkManager state is now CONNECTED_GLOBAL
[   26.085818] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0331] manager: startup complete
[   26.089911] testvm1.both.org systemd[1]: Finished Network Manager Wait Online.
[   26.090254] testvm1.both.org systemd[1]: Reached target Network is Online.
[   26.090399] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-wait-online comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? termina>"'
[   26.091991] testvm1.both.org systemd[1]: Starting My hello shell script...
[   26.095864] testvm1.both.org sssd[be[implicit_files]][1007]: Starting up
[   26.290539] testvm1.both.org systemd[1]: Condition check resulted in Login and scanning of iSCSI devices being skipped.
[   26.291075] testvm1.both.org systemd[1]: Reached target Remote File Systems (Pre).
[   26.291154] testvm1.both.org systemd[1]: Reached target Remote File Systems.
[   26.292671] testvm1.both.org systemd[1]: Starting Notify NFS peers of a restart...
[   26.294897] testvm1.both.org systemd[1]: iscsi.service: Unit cannot be reloaded because it is inactive.
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.304682] testvm1.both.org hello.sh[1010]: ######### Hello World! ########
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.306569] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306669] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306772] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   26.306862] testvm1.both.org systemd[1]: Finished My hello shell script.
[   26.584966] testvm1.both.org sm-notify[1011]: Version 2.4.3 starting

This confirms that the hello.service unit started after the network-online.target 。 This is exactly what you want. You may also have seen the "Hello World" message as it passed by during startup. Notice also that the timestamp is about six seconds later in the startup than it was before.

The best way to define the start sequence

This article explored Linux startup with systemd and unit files and journals in greater detail and discovered what happens when errors are introduced into the service file. As a sysadmin, I find that this type of experimentation helps me understand the behaviors of a program or service when it breaks, and breaking things intentionally is a good way to learn in a safe environment.

As the experiments in this article proved, just adding a service unit to either the multi-user.target or the graphical.target does not define its place in the start sequence. It merely determines whether a unit starts as part of a graphical environment or not. The reality is that the startup targets multi-user.target and graphical.target —and all of their Wants and Requires—start up pretty much in parallel. The best way to ensure that a unit starts in a specific order is to determine the unit it is dependent on and configure the new unit to "Want" and "After" the unit upon which it is dependent.

Resources

There is a great deal of information about systemd available on the internet, but much is terse, obtuse, or even misleading. In addition to the resources mentioned in this article, the following webpages offer more detailed and reliable information about systemd startup.

  • The Fedora Project has a good, practical guide to systemd. It has pretty much everything you need to know in order to configure, manage, and maintain a Fedora computer using systemd.
  • The Fedora Project also has a good cheat sheet that cross-references the old SystemV commands to comparable systemd ones.
  • For detailed technical information about systemd and the reasons for creating it, check out Freedesktop.org's description of systemd.
  • Linux.com's "More systemd fun" offers more advanced systemd information and tips.

There is also a series of deeply technical articles for Linux sysadmins by Lennart Poettering, the designer and primary developer of systemd. These articles were written between April 2010 and September 2011, but they are just as relevant now as they were then. Much of everything else good that has been written about systemd and its ecosystem is based on these papers.

  • Rethinking PID 1
  • systemd for Administrators, Part I
  • systemd for Administrators, Part II
  • systemd for Administrators, Part III
  • systemd for Administrators, Part IV
  • systemd for Administrators, Part V
  • systemd for Administrators, Part VI
  • systemd for Administrators, Part VII
  • systemd for Administrators, Part VIII
  • systemd for Administrators, Part IX
  • systemd for Administrators, Part X
  • systemd for Administrators, Part XI

Linux
  1. nc を使用して大きなファイルを転送する

  2. ダウン時に Systemd を使用してサービスを再起動する方法は?

  3. Systemd:After と Requires の両方を使用する

  1. systemctlコマンドを使用してsystemdユニットを管理する

  2. Ansibleガイド:Ansibleを使用してファイルを管理する

  3. サービスファイルは存在しますが、systemd によって検出されません

  1. LinuxでSystemctlを使用してSystemdサービスを管理する方法

  2. Systemctlコマンドを使用してSystemdサービスを管理する方法

  3. LinuxでのLogrotateの使用ログファイルの管理(例を含む)