Systemd启动后立即终止服务


15

我正在为OSSEC HIDS编写systemd单元文件。问题是,当systemd启动服务时,它将立即停止它们。

当我使用该ExecStart指令时,一切正常。

ExecStart=/var/ossec/bin/ossec-control start

但是,当我进行一些细微的改进时,我可以在OSSEC日志中发现它在启动后会收到SIG 15。

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'

如果我进行其他小的更改,服务将在20秒后收到SIG 15。

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'

因此,我猜想systemd在服务启动后会杀死/ bin / sh进程,然后bin / sh会杀死OSSEC。

我怎么解决这个问题?


1
服务的类型是什么?
维兰德,2015年

@Wieland,我尝试过简单和分叉,但是结果仍然相同。
Daniil Svetlov

Answers:


37

准备协议不匹配

正如Wieland所暗示的那样,Type该服务的重要性。该设置表明systemd 准备就绪的协议希望该服务讲话。一个simple服务被认为是立即准备。在forking服务的初始过程派生一个孩子然后退出之后,它就被视为准备就绪。一个dbus服务被认为当一个服务器出现在桌面总线做好准备。依此类推。

如果您没有在服务单元中声明与该服务相匹配的就绪协议,那么事情就会出错。就绪协议不匹配会导致服务无法正确启动,或者(通常)被systemd诊断为(失败)故障。当某个服务被视为无法启动systemd时,请确保杀死该服务的每个孤立的附加进程(从故障的角度来看,这些附加进程可能一直作为故障的一部分运行),以使该服务正确地回到非活动状态州。

您正是在这样做。

首先,简单的东西:sh -c不匹配Type=simpleType=forking

simple协议中,初始处理被取为服务进程。但是实际上,sh -c包装程序将实际的服务程序作为子进程运行。因此,对于初学者来说,这MAINPID会出错并ExecReload停止工作。使用时Type=simple,首先必须使用sh -c 'exec …'不使用 sh -c。后者通常是正确的做法,比某些人想像的要好。

sh -c也不匹配Type=forking。服务的就绪协议forking非常具体。初始过程必须派生一个孩子,然后退出。systemd将超时应用于此协议。如果初始过程没有在分配的时间内分叉,则表示准备失败。如果初始过程没有在指定时间内退出,那也将是失败的。

不必要的恐怖是 ossec-control

这使我们想到了复杂的东西:那个ossec-control脚本。

事实证明,这是一个System 5 rc脚本,在4个到10个进程之间派生,而这些进程本身又在派生并退出。这是System 5 rc脚本中的一种,它试图在一个脚本中管理整个服务器进程集,其中包括for循环,竞争条件,sleep试图避免它们的任意s,会导致系统处于半启动状态的故障模式,以及二十年前促使人们发明诸如AIX System Resource Controller和daemontools之类的所有其他恐怖因素。而且,不要忘记在二进制目录中隐藏的shell脚本,该脚本会即时重写以实现特质enabledisable动词。

因此,当您/bin/sh -c '/var/ossec/bin/ossec-control start'发生的情况是:

  1. systemd分叉它期望的服务过程。
  2. 那是壳,叉ossec-control
  3. 这反过来又在4到10个孙子之间分叉。
  4. 孙子们全部分叉并依次离开。
  5. 大孙子们都分叉并平行离开。
  6. ossec-control 退出。
  7. 第一个外壳退出。
  8. 该服务工序都很大,great-孙子,不过因为工作的匹配这样既不forking ,也不simple准备协议,systemd认为服务作为一个整体已经失败,并关闭了回去。

实际上,在systemd下根本不需要这些恐怖。都没有

系统化模板服务单元

而是编写一个非常简单的模板单元

[单元]
Description = OSSEC HIDS%i服务器
之后= network.target 

[服务]
类型=简单
ExecStartPre = / usr / bin / env / var / ossec / bin /%p-%i -t
ExecStart = / usr / bin / env / var / ossec / bin /%p-%i -f

[安装]
WantedBy =多用户目标

将此另存为/etc/systemd/system/ossec@.service

各种实际服务是此模板的实例,名为:

  • ossec@dbd.service
  • ossec@agentlessd.service
  • ossec@csyslogd.service
  • ossec@execd.service
  • ossec@agentd.service
  • ossec@logcollector.service
  • ossec@syscheckd.service
  • ossec@maild.service
  • ossec@analysisd.service
  • ossec@remoted.service
  • ossec@monitord.service

然后,启用和禁用功能直接来自服务管理系统修复RedHat错误752774),不需要隐藏的shell脚本。

 systemctl启用ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ analysisd ossec @ logcollector ossec @ remoted ossec @ syscheckd ossec @ monitord

此外,systemd可以直接了解和跟踪每个实际服务。它可以使用过滤他们的日志journalctl -u。它可以知道单个服务何时失败。它知道应该启用和运行哪些服务。

顺便说一句:Type=simple-f选项在这里与在许多其他情况下一样。实际上,很少有服务通过dint表示已准备就绪exit,而在这里也不是这种情况。但这就是forking类型的含义。由于某些错误的公认观念,即恶魔应该做的事情,主要在野外进行的服务只是分叉和退出。实际上不是。自1990年代以来就没有。现在该赶上了。

进一步阅读


2
很详细的答案!我还建议创建一个“分组”目标,例如ossec.target,该目标包含Requires=所有需要的实例,然后PartOf=ossec.target在ossec @ .service中进行设置。这将允许通过启动和停止ossec.target来启动和停止ossec。
intelfx 2015年

@JdeBP,哇!非常感谢您提供这种详细的答案。希望我能做这个单元并在这里写下有关结果的信息。虽然我当时会更轻松。但是你是对的,ossec-controll是一个init地狱。
丹尼尔·斯维特洛夫

1
使用/ usr / bin / env作为包装的原因是什么?
Marius Gedminas

1

如果启动服务/应用程序正在维护任何pid,请保留Type = forking并提供pid文件位置。

[单位]
描述=“在启动时运行应用程序”
之后= network.target syslog.target auditd.service

[服务]
类型=分叉
PIDFile = / var / run / apache2 / apache2.pid
ExecStart = / etc / init.d / apache2启动
ExecStop = / etc / init.d / apache2停止
StandardOutput = syslog
StandardError = syslog
重新启动=失败
SyslogIdentifier = webappslog

[安装]
WantedBy =多用户。targetAlias
= webapps


0

有点相关,我有一个systemd服务,看来systemd会在30秒后“杀死”它。

systemctl status service-namemain process exited, code=exited, status=1/FAILURE在30秒过去后显示。

它将“隔离”运行良好(例如在具有相同环境的终端中手动运行)。

原来是

Type=forking
...
Environment=ABC="TRUE"
ExecStart=/path/to/my_script_to_spawn_process.sh

my_script_to_spawn_process.sh里面做

/bin/something > /dev/null 2>&1 &

可以,但是正在丢弃输出日志信息(通常它进入文件,或者如果没有,则去journalctl)。

更改它以登录到其他地方 /bin/something > /tmp/my_file

然后跟踪/tmp/my_file揭示的实际原因。(正切地)您不能Environment=ABC="true"像在bash中那样使用语法,它必须没有引号或所有引号内的键值,例如Environment="ABC=true"导致我的进程在30秒后退出“处于设置阶段”。


-4

请注意,systemd的守护程序模型是简单的,与许多现有的守护程序不兼容,这些守护程序执行多个派生,执行和设置。最常见的是守护程序,这些守护程序以root身份启动以进行设置,然后切换到特权较低的UID进行常规操作。例如,由于特权问题,初始化Pid文件是在systemd下失败的一件事。有一些解决方法(不是修复程序),但是没有充分记录。

JdeBP的解释令人欢迎,但不完整,他声称这全是ossec-control的错,这是不正确的。即使是非常琐碎的东西也是有问题的,例如在杀死进程时,从systemd本身获取截断的日志行来调试问题或有意义的错误消息。


1
无论如何,PID文件有什么用?如果针对给定服务存在一个进程,则可能存在或不存在具有该PID的实际进程,并且当确实存在具有正确PID的进程时,该进程实际上可能不是预期的服务。
JoostM
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.