Systemd:等待端口打开以启动服务或声明服务已启动

Systemd:等待端口打开以启动服务或声明服务已启动

我有一些服务(A、B、C)需要另一个服务(activemq)处于“活动”状态,并且在启动它们之前让所有必需的端口侦听连接。服务B和C依赖于A,而A又依赖于activemq及其监听的端口(特别是61616端口)。

我遇到的问题是,在 activemq 完成打开所有端口之前,systemd 将 activemq 服务标记为“活动”。所以我的服务 (A) 启动然后终止。

我尝试过的:

set: Restart=on-success (或始终)它有效,但我需要为所有服务( ABC )执行此操作。我不想应用这种规则。

它的工作原理是在服务 A 中添加:

ExecStartPre=/bin/sleep 30 

然后服务 A 正确启动,因此 B 和 C 无需任何进一步配置(除了为所有服务设置的相应“After=”和“Requires=”之外:A、B 和 C)。但我认为这不是一个正确/干净的解决方案。

我还尝试了 [Service] 中的其他选项,但没有任何效果,例如 Type=fork 等

我想要的是:

  • 告诉 systemd 仅在所有端口(其中有四个)或至少最后一个端口(这是导致问题的端口)侦听时才将 activemq 服务标记为“活动”:61616 或
  • 仅在端口 61616 监听后启动服务 A(某种 Require=tcp/61616 或类似的东西)

activemq.service 文件是:

[Unit]
Description=Activemq Servoce
After=local-fs.target                                                                                                                                                                      
After=network.target                                                                                                                                                                       

[Service]                                                                                                                                                                                  
Type=simple                                                                                                                                                                                
SuccessExitStatus=0 143                                                                                                                                                                    
ExecStart=/usr/bin/activemq console                                                                                                                                                        
User=activemq                                                                                                                                                                              
Group=activemq                                                                                                                                                                             
Restart=always
PrivateTmp=true

[Install]
WantedBy=multi-user.target

答案1

基于:

在 activemq 完成打开所有端口之前,systemd 将 activemq 服务标记为“活动”。

和:

[服务 A] 依赖于 activemq 及其端口进行监听(特别是端口 61616)。

...您可以将 systemd 对服务状态的理解从“进程正在运行”修改为“进程正在运行”该端口已打开”。对我来说,这似乎比修改所有后续单元文件来检查打开的端口更简单。一种方法是使用ExecStartPost 选项该繁忙循环等待操作系统指示该端口正在被监听。

一个例子:

ExecStartPost=/usr/bin/timeout 30 sh -c 'while ! ss -H -t -l -n sport = :61616 | grep -q "^LISTEN.*:61616"; do sleep 1; done'

这为 systemd 提供了一个在 ExecStart 之后执行的命令。该命令是timeout,它为主应用程序在 30 秒内未成功启动并侦听端口的情况提供故障停止。该timeout命令包装了一个简单的sh -c ...shell 循环,用于测试正在侦听的端口。 shell 循环本身会运行,直到条件为真为止,每次测试之间间隔ss ... | grep ...一秒钟。sleep

ss命令有以下选项:

  • -H-- 抑制标题(这个选项不是必需的,但我喜欢消除噪音)
  • -t-- 仅显示 TCP 套接字
  • -l-- 仅显示监听套接字
  • -n-- 不要将服务号码解析为名称 -- 将它们保留为号码,以便我们grep稍后使用
  • sport = :61616-- 一个过滤器,将输出限制为源端口为 61616 的条目

然后,该grep命令查找以“LISTEN”开头且后跟字符串“:61616”的行,表明主应用程序已开始侦听该端口。该-q标志告诉 grep 仅报告成功或失败,并且不发出任何输出,因为我们只关心该行是否存在。

在主应用程序启动期间,systemd 显示“正在激活(start-post)”状态,直到 ExecStartPost 命令退出。如果应用程序成功启动并在 30 秒内打开端口,systemd 会将状态更新为“活动(正在运行)”。如果发生故障,systemd 将(在您的示例中)Restart=always重新启动整个过程,但否则会报告“失败(结果:退出代码)”并指向 ExecStartPost 命令及其退出代码“(code=exited, status =124)”,表示命令超时,将终止主进程。

相关内容