質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
systemd

systemdは、Linuxの起動処理及びシステム管理を行う技術です。他にも多くのサービス管理機能を備えており、ユーザープロセスを並列に起動しシステムの起動処理に要する時間を短縮できるなどの特徴があります。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

Q&A

解決済

1回答

2457閲覧

Systemd: 依存関係Requiresの挙動が認識と異なる(依存物起動失敗時の起動抑制が働かない)

FugahogeDS

総合スコア23

systemd

systemdは、Linuxの起動処理及びシステム管理を行う技術です。他にも多くのサービス管理機能を備えており、ユーザープロセスを並列に起動しシステムの起動処理に要する時間を短縮できるなどの特徴があります。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

0グッド

0クリップ

投稿2020/05/31 21:16

前提・実現したいこと

Requiresの依存関係と成否があやふやになってます。はっきりさせたいので質問させてください。
各種資料を見ると、依存関係としてのRequires/Wantsについて

  • Requiresは依存ユニットが失敗すると起動できない
  • Wantsは依存ユニットが失敗しても起動する

という記述を見るのですが、Requires先で指定したユニットを敢えてエラー終了するようにしても起動しているように見えてしまいます。

下記のようにunitAとunitBが存在し、unitAがB側に依存という状況で、「unitBの起動に失敗したときにA側を起動させない」ための設定を教えていただければと思います…

現実例としては、 MariaDBが起動できない状況ならWordpress専用Apache(+PHP)の起動をキャンセルする でしょうか(中途半端に起動されるよりは失敗していた方が良い
派)。

発生している問題・エラーメッセージ

sl% sudo systemctl stop unitA unitB sl% sudo systemctl start unitA sl% sudo tail /var/log/syslog Jun 1 05:56:00 sl systemd[1]: Started Unit B. Jun 1 05:56:00 sl systemd[1]: Started Unit A. Jun 1 05:56:00 sl systemd[1]: unitB.service: Main process exited, code=exited, status=1/FAILURE Jun 1 05:56:00 sl systemd[1]: unitB.service: Failed with result 'exit-code'.

と、一度両方のユニットを止めた後A側を起動すると、Bはエラー停止してくれてますが、Aは起動を継続しています。
各ユニットの状態を取得すると、

sl% sudo systemctl status unitA unitB --no-pager ● unitA.service - Unit A Loaded: loaded (/usr/local/lib/systemd/system/unitA.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2020-06-01 05:56:00 JST; 1min 35s ago Main PID: 2657 (unitA) Tasks: 1 (limit: 1157) Memory: 632.0K CGroup: /system.slice/unitA.service └─2657 /bin/bash /usr/local/sbin/unitA 6月 01 05:56:00 sl systemd[1]: Started Unit A. ● unitB.service - Unit B Loaded: loaded (/usr/local/lib/systemd/system/unitB.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Mon 2020-06-01 05:56:00 JST; 1min 35s ago Process: 2656 ExecStart=/usr/local/sbin/unitB (code=exited, status=1/FAILURE) Main PID: 2656 (code=exited, status=1/FAILURE) 6月 01 05:56:00 sl systemd[1]: Started Unit B. 6月 01 05:56:00 sl systemd[1]: unitB.service: Main process exited, code=exited, status=1/FAILURE 6月 01 05:56:00 sl systemd[1]: unitB.service: Failed with result 'exit-code'.

と、やはりRequiresの意図と食い違っているように見えます。どこかで私が認識ミスを犯しているのでしょうか?

該当のソースコード

unitA.serviceとunitB.serviceの例です。

[Unit] Description = Unit A Requires = unitB.service After = unitB.service [Service] Type = simple ExecStart = /usr/local/sbin/unitA
[Unit] Description = Unit B [Service] Type = simple ExecStart = /usr/local/sbin/unitB

それぞれで起動するもの(unitA,unitB)は単純に無限ループするスクリプトにしていますが、B側は強制的にエラー終了扱いになるように手を入れてます。

#!/bin/bash # 注意: このスクリプトはひたすらにCPUを無駄遣いします # 強制エラー終了(Bのみ) exit 1 while true; do echo "" > /dev/null done

Aについてはexit行が無いだけです。

補足情報(FW/ツールのバージョンなど)

Ubuntu 20.04LTS上のsystemd環境です。

sl% dpkg -l systemd 要望=(U)不明/(I)インストール/(R)削除/(P)完全削除/(H)保持 | 状態=(N)無/(I)インストール済/(C)設定/(U)展開/(F)設定失敗/(H)半インストール/(W)トリガ待ち/(T)トリガ保留 |/ エラー?=(空欄)無/(R)要再インストール (状態,エラーの大文字=異常) ||/ 名前 バージョン アーキテクチ 説明 +++-==============-==============-============-================================= ii systemd 245.4-4ubuntu3 amd64 system and service manager

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

unoSSkR

2020/06/01 02:04

Suitable for you to write "Before = unitB.service" in unitA.service description?
FugahogeDS

2020/06/01 02:14

Thanks! ``` [Unit] Description = Unit A Requires = unitB.service Before = unitB.service # replaced [Service] Type = simple ExecStart = /usr/local/sbin/unitA ``` but, unitA is running. ``` sl% sudo systemctl stop unit{A,B} sl% sudo systemctl start unitA sl% sudo systemctl status unit{A,B} --no-pager ● unitA.service - Unit A Loaded: loaded (/usr/local/lib/systemd/system/unitA.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2020-06-01 11:07:11 JST; 8s ago Main PID: 12257 (unitA) Tasks: 1 (limit: 1157) Memory: 640.0K CGroup: /system.slice/unitA.service └─12257 /bin/bash /usr/local/sbin/unitA 6月 01 11:07:11 sl systemd[1]: Started Unit A. ● unitB.service - Unit B Loaded: loaded (/usr/local/lib/systemd/system/unitB.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Mon 2020-06-01 11:07:11 JST; 8s ago Process: 12258 ExecStart=/usr/local/sbin/unitB (code=exited, status=1/FAILURE) Main PID: 12258 (code=exited, status=1/FAILURE) 6月 01 11:07:11 sl systemd[1]: Started Unit B. 6月 01 11:07:11 sl systemd[1]: unitB.service: Main process exited, code=exited, status=1/FAILURE 6月 01 11:07:11 sl systemd[1]: unitB.service: Failed with result 'exit-code'. ``` I checked log(/var/log/syslog), running order is A -> B. I want running order; B -> A, and if B is failed, then don't start A.
unoSSkR

2020/06/01 02:30

We should see "Required" section in "man systemd.unit". May be both services are run simultaneously at boot, that's why your situation should be occured. Im not sure but when both services start normally without exit 1 in unitB shell, "systemctl stop unitB.service" would make unitA.servcie stop like you expect, right?
FugahogeDS

2020/06/01 02:55

"RequiredBy" in [Install]? I set "RequiredBy = unitA.service" in unitB.service, and install files. $ sudo systemctl enable unitB.service $ sudo systemctl start unitA But unitA is running. (unitA.service) [Unit] Description = Unit A Requires = unitB.service After = unitB.service [Service] Type = simple ExecStart = /usr/local/sbin/unitA [Install] WantedBy = multi-user.target --- (unitB.service) [Unit] Description = Unit B [Service] Type = simple ExecStart = /usr/local/sbin/unitB [Install] RequiredBy = unitA.service --- sl% ls -l /etc/systemd/system/unitA.service.requires total 0 lrwxrwxrwx 1 root root 43 6月 1 11:43 unitB.service -> /usr/local/lib/systemd/system/unitB.service stop unitB -> stop unitA is OK.
guest

回答1

0

ベストアンサー

おそらく、実現したいことは、Requires= よりも BindsTo= だと思います。

気になったので、Wants=, Requires=, BindsTo= のそれぞれで、挙動を調べてみました。
環境は CentOS 8 / systemd-239-18.el8_1.1.x86_64 です。

Wants=unitBRequires=unitBBindsTo=unitB
unitB 起動成功unitA 起動unitA 起動unitA 起動
unitB 再起動(明示的※)unitA 起動したままunitA 再起動unitA 再起動
unitB 起動後、停止(明示的※)unitA 起動したままunitA 停止unitA 停止
unitB 起動後、停止(その他)unitA 起動したままunitA 起動したままunitA 停止
unitB 起動失敗unitA 起動unitA 起動unitA 起動しない

※「明示的」(explicitly) は systemctl restart/stop による再起動/停止

BindsTo= の場合、unitB (依存ユニット)の 状態 (active/inactive) を見ているのに対し、Requires= の場合は違うようです。
これは、マニュアル systemd.unit(5) の Requires= の「Note that 〜」箇所に説明があります。
明示的ではない停止(プロセス自身の停止など)の場合の挙動についても、unitA に伝搬しない旨、記載があります。
(なぜなのか、何がうれしいのかはよくわかりません。.service ではない、別の種類の Unit だと使い道があるのかもしれません。)

Wants= と比べると、明示的な再起動/停止(systemctl restart/stop unitB)のときの挙動は異なりますが、起動(systemctl start unitB)については、成否に関わらず、unitA は起動しました。

Requiresは依存ユニットが失敗すると起動できない

マニュアルの下記文章では、確かにそのように読めるのですが、よくわかりませんね。

If one of the other units fails to activate, and an ordering dependency After= on the failing unit is set, this unit will not be started.

fails to activate が「依存ユニットの ExecStart= の実行失敗」ではなく、別の何か?
逆に読むと「依存ユニットの activate に成功」しているので、unitA が起動したということか?

投稿2020/06/01 15:52

TaichiYanagiya

総合スコア12173

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

FugahogeDS

2020/06/01 20:08

これですこれです! ありがとうございます。 Requires以上の依存関係があったということですね。 "Activate"がどの部分までなのかが理解できていなかったというのが原因なのかと思います…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問