不一定需要这个。

不一定需要这个。

我有一堆服务(比如C0C1…… C9),这些服务只能在服务S完成初始化并完全运行并准备好其他服务后启动。我如何使用 systemd 来安排它?

在 systemd 中使用路径激活和目标订购服务假设服务S有一种写出某种标志文件的机制。相反,假设我可以完全控制服务S运行的程序,并且可以在需要时向其中添加 systemd 机制。

答案1

不一定需要这个。

如果C服务需要等待S准备好才能打开与其的套接字连接,那么根本不需要这样做。相反,人们可以利用早期监听套接字打开由服务经理。

几个系统,包括洛朗·贝尔科特的 s6,我的小吃工具集和 systemd 有一些方法监听套接字可以尽早开放,这是设置服务的第一件事。它们都涉及除打开侦听套接字的服务程序之外的其他内容,以及服务程序在调用时接收侦听套接字作为已打开的文件描述符。

具体来说,使用 systemd 创建一个插座单元定义监听套接字。 systemd 打开套接字单元并对其进行设置,以便内核网络子系统正在侦听连接;并在生成处理套接字连接的进程时将其作为打开文件描述符传递给实际服务。 (它可以通过两种方式做到这一点,就像可以一样,但是对服务与服务inetd细节的讨论超出了本答案的范围。)Accept=trueAccept=false

重要的一点是,人们不一定需要比这更多的订购。内核将客户端连接批量放入队列中,直到服务程序初始化并准备好接受它们并与客户端通信。

当这样做时,准备协议就是关键。

systemd 有一组准备协议它理解,通过Type=服务单元中的设置指定服务。这里感兴趣的特定准备协议是notify准备协议。有了它,systemd 就会被告知等待来自服务的消息,当服务准备好时,它会发送一条标记准备就绪的消息。 systemd 会延迟其他服务的激活,直到标记为就绪为止。

利用它涉及两件事:

  • 修改 的代码S,使其调用 Pierre-Yves Ritschardnotify_systemd()函数或 Cameron T Normannotify_socket()函数之类的函数。
  • Type=notify使用和为服务设置服务单元NotifyAccess=main

NotifyAccess=main限制(这是默认设置)是因为 systemd 需要知道忽略来自恶作剧(或只是简单的错误)程序的消息,因为系统上的任何进程都可以向 systemd 的通知套接字发送消息。

人们优先使用 Pierre-Yves Ritchard 或 Cameron T Norman 的代码,因为它不排除在 UbuntuBSD、Debian FreeBSD、实际的 FreeBSD、TrueOS、OpenBSD 等上使用此机制的可能性; systemd 作者提供的代码确实排除了这些。

要避免的一个陷阱是systemd-notify程序。它有几个主要问题,其中最重要的是用它发送的消息最终可能会在未被 systemd 处理的情况下被丢弃。在这种情况下S,最主要的问题是它不作为服务的“主”进程运行,因此必须使用NotifyAccess=all.

另一个要避免的陷阱是认为forking协议更简单。它不是。正在做正确地涉及不分叉和退出父级,直到(一方面)程序的所有工作线程都在运行。这与绝大多数分叉守护进程的实际分叉方式不符。

进一步阅读

答案2

像这样:

服务

[Unit]
Description=My main Service

[Service]
Type=notify
ExecStart=/usr/bin/myBinary

C0服务

[Unit]
Description=Dependent service number 0
PartOf=S.service

C1.服务

[Unit]
Description=Dependent service number 1
PartOf=S.service

C9.服务

[Unit]
Description=Dependent service number 9
PartOf=S.service

其中 /usr/bin/myBinary 使sd_notify 就绪=1初始化完成后调用。

根据您希望依赖项的行为方式,您可以使用 PartOf、Requires 或 BindsTo 或其他的

答案3

systemd.service(5)具体参考手册页关于类型=的部分,每种服务类型都有不同的方式让 Systemd 确定它已准备好向其他服务提供功能:

  • 如果Type=simple,则应在守护程序启动之前安装其通信通道(例如,由 systemd 通过套接字激活设置的套接字)。

  • 如果Type=forking,则父进程预计在启动完成且所有通信通道均已建立后退出。

  • 如果Type=dbus,则预计守护进程会在 D-Bus 总线上获取一个名称,此时 systemd 将继续启动后续单元。

  • 如果Type=notify,则预计守护程序sd_notify(3)在完成启动时通过或等效调用发送通知消息。发送此通知消息后,systemd 将继续启动后续单元。

对于最后一个选项(通过 发送消息sd_notify),您可以使用该systemd-notify实用程序,并记住使用 授予其访问权限NotifyAccess=all

鉴于您可以控制服务S,您可以自由选择最适合您的用例的选项,或者只是最容易实现的选项。

相关内容