Systemd

當 systemd 套接字連接關閉時停止子服務

  • May 20, 2020

我正在嘗試通過套接字遠端啟動元服務。要求:

  1. 建立連接時,套接字應該啟動元服務
  2. 元服務應在啟動Wants=時啟動所有子 ( ) 服務
  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()連接,但在連接停止時關閉?這可能是第一個或最後一個連接,我對此不可知。那將是最簡單的解決方案,也可以解決其餘問題。是否有使用 C 應用程序的範例,accept()以便我可以弄清楚 systemd 如何通過sockfd我們的第一個參數accept(int sockfd, ...)?然後我可以自己寫一些東西。我嘗試執行,但在使用 bind() 時一直失敗。

這是使用的另一種嘗試Accept=yes

# simple.socket
[Unit]
Description=Socket

[Socket]
ListenStream=11111
Accept=yes

# simple@.service  # 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
PartOf=simple@.service # This fails to connect to the instance

[Service]
ExecStart=sleep infinity # Business goes here

在這種情況下,一切都很好。當連接關閉時,會simple@XYZ.service很好地停止,但simple-child.service會繼續執行。那是因為PartOf=simple@.service沒有引用正確的實例。我真的更願意避免使用模板simple-child.service,但讓我們嘗試一下:

# simple.socket
[Unit]
Description=Socket

[Socket]
ListenStream=11111
Accept=yes

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

[Service]
ExecStart=-cat -
StandardInput=socket

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

[Service]
ExecStart=sleep infinity # Business goes here

在這種情況下simple@.service,模板化為simple@6-127.0.0.1:11111-127.0.0.1:49276.service,但%i僅是6。它只生成simple-child@6.servicePartOf=simple@6.service因此停止時無法simple@6-127.0.0.1:11111-127.0.0.1:49276.service停止。

我有一個解決方案,但它在 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.servicesimple.service確實有效,但這不是一個很好的解決方案。

引用自:https://unix.stackexchange.com/questions/587836