systemd 如何确定服务已停止?

systemd 如何确定服务已停止?

我们的应用程序使用 init.d 脚本来启动和停止应用程序作为服务。在 CentOS 7 下,/sbin/init符号链接到 systemd,因此我可以使用以下任一方法启动我的应用程序:

service myapp start

或者

systemctl start myapp

我遇到的问题是,使用或stop在服务上运行不会停止我的应用程序。的输出:servicesystemctlsystemctl status

[root@nec04 ~]# systemctl status myapp
myapp.service - SYSV: Service script to start/stop my application
   Loaded: loaded (/etc/rc.d/init.d/myapp)
   Active: inactive (dead) since Mon 2015-10-05 15:17:41 CEST; 22h ago
  Process: 31850 ExecStop=/etc/rc.d/init.d/myapp stop (code=exited, status=0/SUCCESS)
  Process: 21054 ExecStart=/etc/rc.d/init.d/myapp start (code=exited, status=0/SUCCESS)

使用service命令:

[root@nec04 ~]# service myapp status
Local database at :3307 is started
Watchdog is running
Application is running

为什么systemctl认为我的应用程序没有运行?难道 systemctl 没有调用 stop 函数,因为它认为我的应用程序已经停止了?

答案1

我不知道输出service,从未真正使用过该工具,但根据systemctl应用程序确实已停止。这就是这Active: inactive (dead)条线的意思。 (Loaded仅意味着 systemd 已将单元文件加载到内存中;无论应用程序是否正在运行,这都应该始终如此。)

如果应用程序实际上仍然有一个进程在运行,则意味着停止功能无法正常工作。然而,这不应该发生;一旦systemctl停止某些内容,它将(在超时后)使用 cgroup 强制终止该应用程序启动的所有进程。因此,除非您的进程以 root 身份运行并且故意脱离其 cgroup(一种极其病态的行为),否则 systemd 应该杀死它。不过,我不确定它如何与 sysVinit 仿真交互。

由于 systemd 使用其 sysVinit 模拟,将 init 脚本用作单元文件,因此整个问题变得复杂。重写为适当的单元文件可能会更好,如所述这里。我倾向于建议使用Type=simple而不是,因为程序拥有switch 或等效项比与 dbus 对话Type=dbus更常见,而且这也更容易添加到您可以控制的代码中。--no-daemon

答案2

为什么systemctl认为我的应用程序没有运行?

因为,正如汤姆·亨特所说,它没有运行。

难道是systemctl因为它认为我的应用程序已经停止而没有调用停止函数?

不,非常清楚做过调用 stop 函数,并将其作为进程#31850 运行。

这里有两种可能性,都不是 systemd 问题:

  • 在某些时候,您直接启动服务程序,而不是作为 systemd 服务。这就是仍在运行的内容。当然systemd不会知道这一点。
  • status您的脚本的功能有init.d问题。这并不是init.d世界历史上第一个这样有缺陷的剧本。

myapp.service - SYSV:启动/停止我的应用程序的服务脚本

那个“SYSV:”有一个赠品表明你的init.d脚本很差。它甚至没有 LSB 标头块。

正如汤姆·亨特所说,编写一些服务单元。或者记住迁移到 systemd 的第一条规则,然后去捏那些已经写好的规则。从表面上看,您实际上拥有三个相互依赖但不同的服务,并且应该编写多个服务单元来表达这些相互依赖关系。如果其中一个是侦听端口 3307 的数据库服务器,则几乎肯定适用第一条规则。

进一步阅读

相关内容