我有一个简单的 Java 服务器 + 几个我想使用 systemd 运行并保持活动的脚本(Ubuntu 16.04)我是 systemd 新手,该服务不断重新启动并显示此日志
Nov 16 10:20:12 systemd[1]: app.service: Unit entered failed state.
Nov 16 10:20:12 systemd[1]: app.service: Failed with result 'resources'.
Nov 16 10:29:25 systemd[1]: app.service: State 'stop-sigterm' timed out. Killing.
Nov 16 10:29:25 systemd[1]: app.service: Unit entered failed state.
Nov 16 10:29:25 systemd[1]: app.service: Failed with result 'timeout'.
Nov 16 10:31:06 systemd[1]: app.service: Service hold-off time over, scheduling restart.
我有 2 个简单的 bash 脚本来运行/控制服务器;
这是我的服务定义 app.service
[Unit]
Description=java server
[Service]
ExecStart=-/home/deploy/server/serverctl.sh start
ExecStop=-/home/deploy/server/serverctl.sh stop
ExecReload=-/home/deploy/server/serverctl.sh restart
SyslogIdentifier=my-app
User=deploy
Restart=always
RestartSec=100
Type=simple
[Install]
WantedBy=multi-user.target
我的start.sh
#!/bin/bash
cd "$(dirname "$0")"
java -mx500m -cp lib/* mylcass -port 8080 -arg val > server.log 2>&1 & echo $!
它运行服务器并返回 PID
我有一个控制脚本来启动/停止/状态重启服务器,它工作正常
#!/bin/bash
PID_FILE='/tmp/myserver.pid'
# ***********************************************
start() {
PID=`/path/to/server-start.sh`
}
case "$1" in
start)
if [ -f $PID_FILE ]; then
PID=`cat $PID_FILE`
if [ -z "`ps axf | grep -w ${PID} | grep -v grep`" ]; then
start
else
exit 0
fi
else
start
fi
if [ -z $PID ]; then
exit 3
else
echo $PID > $PID_FILE
exit 0
fi
;;
status)
echo "status"
if [ -f $PID_FILE ]; then
PID=`cat $PID_FILE`
if [ -z "`ps axf | grep -w ${PID} | grep -v grep`" ]; then
echo "Not running (process dead but pidfile exists)"
exit 1
else
echo "Running [$PID]"
exit 0
fi
else
echo "Not running"
exit 3
fi
;;
stop)
if [ -f $PID_FILE ]; then
PID=`cat $PID_FILE`
if [ -z "`ps axf | grep -w ${PID} | grep -v grep`" ]; then
exit 1
else
PID=`cat $PID_FILE`
kill -HUP $PID
rm -f $PID_FILE
exit 0
fi
else
exit 3
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {status|start|stop|restart}"
exit 1
esac
有什么想法吗?如何让 systemd 确保服务器正常运行?
答案1
首先,请停止使用您的“服务器控制脚本”。这是 systemd 的工作。init 系统已经跟踪服务 PID 并提供启动/停止命令。
另外,除非您确实知道有必要,否则不要-
在 ExecStart 中使用该标志。它告诉 systemd 忽略启动失败,您肯定想知道服务何时失败。
最后,尽量避免myapp &
在启动脚本中使用。(Init 不需要它——根据定义,服务已经在后台运行。)如果您必须使用它,那么Type=forking
会更正确。
(设置正确的 Type= 会告诉 systemd 期望什么,即何时将服务器视为“正在启动”、 “已启动” 或 “已完成”。Type=simple 表示初始进程绝不'backgrounds' 本身;Type=forking 则相反。)
这样,下面的方法应该可以更好地发挥作用:
app.service
[Unit]
Description=java server
[Service]
Type=simple
User=deploy
ExecStart=/home/deploy/server/start.sh
SyslogIdentifier=my-app
Restart=always
RestartSec=100
[Install]
WantedBy=multi-user.target
start.sh
#!/bin/sh
cd "$(dirname "$0")"
exec java -mx500m -cp lib/* mylcass -port 8080 -arg val
答案2
如果您的start.sh
确实这么简单,您也可以根本不使用它。
恕我直言,这实际上是首选方式:
[Unit]
Description=My Java App
[Service]
Type=simple
User=deploy
WorkingDirectory=/home/deploy/server
ExecStart=/usr/bin/java -mx500m -cp lib/* mylcass -port 8080 -arg val
SyslogIdentifier=my-app
Restart=always
RestartSec=100
[Install]
WantedBy=multi-user.target
无需复制 Systemd 免费提供给您的功能。
注意,这不会复制脚本> server.log
的功能。相反,输出由更好的方式start.sh
处理,恕我直言。journald
如果您需要用户配置,请直接在程序中读取配置文件,或使用 systemd 的环境变量。请参阅Environment=
和EnvironmentFile=
服务选项。
您甚至可以将这些环境变量转换为传递给命令的参数和${FOO}
。
使用覆盖文件来app.service.d/*
保持 ENV 变量(或其他配置)分开。