ターゲットソケットがリッスンした後のみ systemd サービスを開始しますか?

ターゲットソケットがリッスンした後のみ systemd サービスを開始しますか?

起動時にリスニング ソケットに接続する必要があるサービス X があります。そのターゲット ソケット自体は、systemd によって起動された別のサービス Y によって開かれます。

サービス Y が正常に開始され、リスニング ソケットを開いた後にのみサービス X を開始するようにユニット ファイル (またはその他の方法) で指定する方法はありますか?

初期接続が失敗した場合、サービス X を変更して再試行することはできないことに注意してください。また、サービス Y がリスニング ソケットを開くまでに要する時間はさまざまであるため、固定遅延もうまく機能しません。

答え1

systemd の動作は若干異なります。systemd を設定してソケットを作成し、リッスンするようにします。X などが接続しようとすると、systemd は接続を処理するために Y を起動し、ソケットを渡します。したがって、X は名目上は Y より先に起動できますが、問題にはなりません。その後の接続は Y によって処理されます (接続ごとに Y が再起動されるように設定することもできますが、これは当てはまらないと思います)。

Y への最小限の変更は、作成/バインド自体を実行するのではなく、事前に作成されたソケットを stdin/stdout ファイル記述子として受け入れるようにすることです。

以下は、root としてではなく、試すことができるテスト セットアップです。3 つのユニット ファイルが必要です。systemd に ~/.local/share/systemd/user/mysock.socketソケットを作成し、それを渡す方法を指示します。

# create listening socket. on 1st connect run mysock.service
[Socket]
ListenStream=5555
Accept=false

~/.local/share/systemd/user/mysock.service(同じ名前を持つmysock) は、誰かがソケットに接続した場合に開始されるサービスです。ここで Y を開始しますが、これは Python に置き換えました。

[Unit]
Description=started from mysock.socket
[Service]
ExecStart=/home/meuh/bin/python/mysock.py
StandardInput=socket

最後に、X サービスにはソケットが必要であることを示すユニットがあります。XI では、ソケットに日付を書き込む socat を使用しています。 ~/.local/share/systemd/user/mysockdepend.service

[Unit]
Description=dependent on socket listening
Requires=mysock.socket
[Service]
ExecStart=/usr/bin/socat -U tcp:localhost:5555 exec:/usr/bin/date

Python は標準入力のソケット、つまりファイル記述子 0 を受け取り、それを適切な Python ソケット オブジェクトにラップし、accept()それに対して読み取り/書き込みを実行します。 ~/bin/python/mysock.py

#!/usr/bin/python
# started from /home/meuh/.local/share/systemd/user/mysock.service
# with socket on stdin/stdout
import sys, time, socket, subprocess

def debug(msg):
#    time.sleep(3)
    subprocess.call(["/usr/bin/logger", msg])

debug("start\n")
s = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM)
while True:
    conn, addr = s.accept()
    conn.send("hello\n")
    while True:
        try:
            data = conn.recv(100)
            debug("got "+data+"\n")
            if len(data)<=0: break
        except:
            break
    conn.close()

の後systemctl --user daemon-reload、Xを次のように実行できるはずです。

systemctl --user start mysockdepend

ログでjournalctlY が開始されたこと、および日付を含むデバッグ出力を確認します。

詳しくはこちらソケットのアクティベーションそして2番目それを発明した人から。

答え2

systemdはこのようなケースを次のように処理します。ソケットファイル

some-socket.socketソケットを表すために、という名前の systemd ユニット ファイルが作成されます。

次に、Service Xサービス ファイルにAfter=ソケットを参照するディレクティブを含めることができます。

ソケット ファイルに関する公式 systemd ドキュメントが役立つはずです。

関連情報