systemd ソケット接続が閉じるとサブサービスが停止する

systemd ソケット接続が閉じるとサブサービスが停止する

ソケットを介してリモートでメタサービスを開始しようとしています。必要:

  1. 接続が確立されると、ソケットはメタサービスを開始する必要があります。
  2. メタサービスはWants=起動時にすべてのchild()サービスを開始する必要があります。
  3. 接続が閉じたら、メタサービスを停止する必要があります。
  4. メタサービスが停止したら、すべての子(ConsistsOf=)サービスも停止する必要があります。

複数の接続を期待しないため、複数の接続が確立された場合、要件は定義されません。

試みは次のとおりです。

# simple.socket
[Unit]
Description=Socket

[Socket]
ListenStream=11111
Accept=no

# simple.service
[Unit]
Description=Meta-service
Wants=simple-child.service # Will be a full tree of dependencies

[Service]
ExecStart=-cat -  # cat will fail to start because it doesn't accept connections
StandardInput=socket

# simple-child.service
[Unit]
Description=Child1
PartOf=simple.service # Puts a ConsistsOf= relationship in simple.service

[Service]
ExecStart=sleep infinity # Business goes here

ここで問題はいつですかAccept=noExecStart=着信接続処理を担当します。 cat -電話しないでくださいaccept()だからsimple.service始めません。ExecStart=接続に使用できますが、accept()接続が停止したときに閉じることができる別の基本的なツールはありますか?それは最初の接続でも最後の接続でもかまいません。私はそれについて不可知論的です。これは最も簡単な解決策であり、残りの問題も解決します。 systemdが最初の引数をどのaccept()ように渡すかを理解できるCアプリケーションを使用する例はありますか?それから私は自分のものを書くことができます。走ってみようsockfdaccept(int sockfd, ...)これただし、バインド()を使用すると常に失敗します。

以下は、以下を使用した別の試みですAccept=yes

# simple.socket
[Unit]
Description=Socket

[Socket]
ListenStream=11111
Accept=yes

# [email protected]  # Note the template here
[Unit]
Description=Meta-service
Wants=simple-child.service

[Service]
ExecStart=-cat - # now cat will work!
StandardInput=socket

# simple-child.service
[Unit]
Description=Child1
[email protected] # This fails to connect to the instance

[Service]
ExecStart=sleep infinity # Business goes here

この場合、すべてが順調に進み始めました。接続が閉じられると[email protected]正常に停止しますが、引き続きsimple-child.service実行されます。[email protected]正しいインスタンスが参照されないためです。テンプレートの使用を避けたいのですが、simple-child.service試してみます。

# simple.socket
[Unit]
Description=Socket

[Socket]
ListenStream=11111
Accept=yes

# [email protected]
[Unit]
Description=Meta-service
Wants=simple-child@%i.service  % Starts simple-child as a template

[Service]
ExecStart=-cat -
StandardInput=socket

# [email protected] # Newly templated
[Unit]
Description=Child1
PartOf=simple@%i.service  # Using %i 

[Service]
ExecStart=sleep infinity # Business goes here

この場合、[email protected]テンプレートは[email protected]:11111-127.0.0.1:49276.serviceですが。作成のみなので、停止すると停止できません。%i6[email protected][email protected][email protected]:11111-127.0.0.1:49276.service

答え1

解決策がありますが、Pythonで書かれているので、依存関係のために理想的ではありません。

# simple.socket
[Unit]
Description=Socket

[Socket]
ListenStream=11111
Accept=no

# simple.service
[Unit]
Description=Meta-service
Wants=simple-child.service

[Service]
ExecStart=/usr/local/bin/listen.py

# simple-child.service
[Unit]
Description=Child1
PartOf=simple.service

[Service]
ExecStart=sleep infinity

Pythonスクリプトは次のとおりです。

#!/usr/bin/env python3

from socketserver import TCPServer, StreamRequestHandler
import socket

class Handler(StreamRequestHandler):
    def handle(self):
        while True:
            c = self.rfile.read(1)
            if len(c) == 0:
                exit()

class Server(TCPServer):

    SYSTEMD_FIRST_SOCKET_FD = 3

    def __init__(self, server_address, handler_cls):
        TCPServer.__init__(self, server_address, handler_cls, bind_and_activate=False)
        self.socket = socket.fromfd(self.SYSTEMD_FIRST_SOCKET_FD, self.address_family, self.socket_type)

if __name__ == "__main__":
    HOST, PORT = "12.34.56.78", 12345 # This gets overridden by systemd
    server = Server((HOST, PORT), Handler)
    server.serve_forever()

接続が確立されると、simple.service両方がsimple-child.service開始されます。接続が終了すると、接続は停止しsimple.serviceますが、simple-child.service関係にもかかわらず何とか停止しませんPartOf=。追加することは効果がExecStop=systemctl stop simple-child.serviceありますが、simple.serviceそれほど良い解決策ではありません。

関連情報