Rhel 7:如果给出后台选项,systemd 将无法启动进程

Rhel 7:如果给出后台选项,systemd 将无法启动进程

我有一个 systemd 单元文件(serv_unit.service):

[Unit]
Description=My service

[Service]
Type=simple
Restart=always
RestartSec=60
StartLimitInterval=400
StartLimitBurst=3
ExecStart=/etc/init.d/myscript start

[Install]
WantedBy=multi-user.target

/etc/init.d/myscript

source /etc/myfile.sh # JAVA_home & other vars are resolved through this file
mode=$1
case "$mode" in
  'start')
    # Start daemon
    daemon --user=abc $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args &

我遇到的问题是当我运行以下命令时:

systemctl start serv_unit.service

我看不到 java 进程。但是当我删除尾随的&IE:

daemon --user=abc $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args

可以看到 Java 进程(并且该 Java 进程没有崩溃,因此排除了它在后台崩溃的可能性)

原因何在?

答案1

除了主要问题之外,从 systemd 调用 init.d 脚本有点多余,而且通常一开始就不是一个好主意。以下就是您所需的全部内容:

User=abc
EnvironmentFile=/etc/myfile.conf
ExecStart=/usr/bin/env $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args

EnvironmentFile 只能是简单的 KEY=value 赋值,但如果配置必须采用 shell 脚本语法,则也可以使用:

User=abc
ExecStart=/bin/sh -c ". /etc/myfile.sh && exec $$JAVA_HOME/bin/java -cp $$appClassPath $$MAIN_CLASS $$args"

SyslogIdentifier=(如果服务生成标准输出消息,您也应该在两种情况下进行设置。)

服务类型

Systemd 服务应遵循特定规则。一个.service单元只能有一个“主”守护进程,该Type=选项会告诉 systemd 该进程如何工作。

Type=simple表示初始进程(即从 ExecStart= 启动的进程)本身是服务的主进程。一旦主进程退出,服务就被认为已经停止,以便清理所有剩余物。

这意味着如果你使用 Type=simple,你就是告诉 systemd 该守护进程将不会进入“后台”。事实上,你还告诉 systemdinit.d 脚本– 不是daemon– 是服务的主要流程……

因此,最好的情况是,init.d 脚本不仅不会尝试将实际的守护进程置于后台,而且还可以通过exec如下方式启动它:

case "$mode" in
    'start-foreground')
        # Start daemon in foreground
        exec daemon --user=abc $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args

另一方面,Type=forking表示初始过程将要在启动过程中 fork 和 exit,并且应该从 PIDFile= 或启发式地发现主进程。

使用哪一个

使用具有内置“守护进程”模式Type=forking具有显著的优势:systemd 服务一直处于“正在启动”状态,直到守护进程最终尝试进入后台,此时它最终进入“已启动/活动”状态。这有助于配置依赖项,例如服务 A 可以声明“After=B.service”。

但是,如果后台运行是通过外部手段完成的,比如 shell&特性——没有任何可以报告守护进程是否已经准备好的东西——那么它就完全无用您可能应该只使用Type=simple不带任何背景选项。

相关内容