仅在*目标套接字正在侦听之后才启动 systemd 服务?

big*_*osh 5 linux systemd

我有一个服务 X,它需要在启动时连接到侦听套接字。该目标套接字本身由 systemd 启动的另一个服务 Y 打开。

有没有办法在单元文件(或其他方式)中指定仅在服务 Y 成功启动并打开侦听套接字后才启动服务 X?

请注意,如果初始连接失败,我无法将服务 X 更改为重试。固定延迟也不能很好地工作,因为服务 Y 在打开侦听套接字之前需要不同的时间。

meu*_*euh 8

systemd 的工作方式略有不同。您将 systemd 配置为创建和侦听套接字,如果像 X 这样的任何人尝试连接,那么 systemd 会启动 Y 来处理连接,并将套接字传递给它。所以 X 可以在 Y 之前在理论上开始,但这无关紧要。以后的连接将由 Y 处理。(您也可以配置它以便为每个连接重新启动 Y,但我认为这不是您的情况)。

对 Y 的最小更改是让它接受预先创建的套接字作为其 stdin/stdout 文件描述符,而不是自己进行创建/绑定。

这是您可以尝试的测试设置,而不是 root。您需要 3 个单元文件。 ~/.local/share/systemd/user/mysock.socket告诉 systemd 创建套接字以及如何传递它:

# create listening socket. on 1st connect run mysock.service
[Socket]
ListenStream=5555
Accept=false
Run Code Online (Sandbox Code Playgroud)

~/.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
Run Code Online (Sandbox Code Playgroud)

最后,您的 X 服务有一个 Unit 说它需要套接字。对于 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
Run Code Online (Sandbox Code Playgroud)

python 在 stdin 上获取套接字,即文件描述符 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()
Run Code Online (Sandbox Code Playgroud)

在 a 之后systemctl --user daemon-reload,您应该能够使用 X 运行

systemctl --user start mysockdepend
Run Code Online (Sandbox Code Playgroud)

并在日志中journalctl看到 Y 已启动,以及带有日期的调试输出。

从发明它的人那里阅读套接字激活第二个


Mar*_*erg 2

systemd 使用套接字文件处理这种情况。

将创建一个名为 systemd 的单元文件some-socket.socket来表示套接字。

然后您的Service X服务文件可以包含After=引用套接字的指令。

有关套接字文件的官方 systemd 文档应该会有所帮助。

  • 鉴于问题中描述的服务 Y 的行为,这没有提及必须对服务 Y 进行的修改。将套接字单元应用于未修改的服务 Y,最终会得到多个侦听套接字,其中只有一个起作用。具有讽刺意味的是,不起作用的套接字将是服务 X 将尝试连接的套接字,并且练习的实际目标将无法实现。 (3认同)