如何在Linux系统中将Spring Boot应用程序打包为可执行jar as a Service ?这是推荐的方法吗,还是应该将这个应用程序转换为war并将其安装到Tomcat中?
目前,我可以从屏幕会话运行Spring引导应用程序,这很好,但需要在服务器重新启动后手动启动。
我正在寻找的是一般的建议/方向或样本init。D脚本,如果我的方法与可执行jar是适当的。
如何在Linux系统中将Spring Boot应用程序打包为可执行jar as a Service ?这是推荐的方法吗,还是应该将这个应用程序转换为war并将其安装到Tomcat中?
目前,我可以从屏幕会话运行Spring引导应用程序,这很好,但需要在服务器重新启动后手动启动。
我正在寻找的是一般的建议/方向或样本init。D脚本,如果我的方法与可执行jar是适当的。
当前回答
我的SysVInit脚本Centos 6 / RHEL(还不理想)。这个脚本需要ApplicationPidListener。
/etc/init.d/app的源代码
#!/bin/sh
#
# app Spring Boot Application
#
# chkconfig: 345 20 80
# description: App Service
#
### BEGIN INIT INFO
# Provides: App
# Required-Start: $local_fs $network
# Required-Stop: $local_fs $network
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: Application
# Description:
### END INIT INFO
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
exec="/usr/bin/java"
prog="app"
app_home=/home/$prog/
user=$prog
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
lockfile=/var/lock/subsys/$prog
pid=$app_home/$prog.pid
start() {
[ -x $exec ] || exit 5
[ -f $config ] || exit 6
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 1
echo -n $"Starting $prog: "
cd $app_home
daemon --check $prog --pidfile $pid --user $user $exec $app_args &
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc -p $pid $prog
retval=$?
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
stop
start
}
reload() {
restart
}
force_reload() {
restart
}
rh_status() {
status -p $pid $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit 2
esac
exit $?
配置文件/etc/sysconfig/app示例:
exec=/opt/jdk1.8.0_05/jre/bin/java
user=myuser
app_home=/home/mysuer/
app_args="-jar app.jar"
pid=$app_home/app.pid
其他回答
这可以在Ubuntu中使用Systemd服务完成
[Unit]
Description=A Spring Boot application
After=syslog.target
[Service]
User=baeldung
ExecStart=/path/to/your-app.jar SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
你可以点击这个链接获得更详细的描述和不同的方法。 http://www.baeldung.com/spring-boot-app-as-a-service
我自己刚刚抽出时间来做这件事,所以下面是到目前为止我在CentOS初始化方面的进展。D业务控制器脚本。到目前为止,它工作得很好,但我不是leet Bash黑客,所以我相信还有改进的空间,所以欢迎提出改进的想法。
首先,我为每个服务准备了一个简短的配置脚本/data/svcmgmt/conf/my-spring-boot-api.sh,用于设置环境变量。
#!/bin/bash
export JAVA_HOME=/opt/jdk1.8.0_05/jre
export APP_HOME=/data/apps/my-spring-boot-api
export APP_NAME=my-spring-boot-api
export APP_PORT=40001
我使用CentOS,所以为了确保我的服务在服务器重启后启动,我在/etc/init.d/my-spring-boot-api中有一个服务控制脚本:
#!/bin/bash
# description: my-spring-boot-api start stop restart
# processname: my-spring-boot-api
# chkconfig: 234 20 80
. /data/svcmgmt/conf/my-spring-boot-api.sh
/data/svcmgmt/bin/spring-boot-service.sh $1
exit 0
如您所见,它调用初始配置脚本来设置环境变量,然后调用我用来重新启动所有Spring Boot服务的共享脚本。共享脚本是所有内容的核心所在:
#!/bin/bash
echo "Service [$APP_NAME] - [$1]"
echo " JAVA_HOME=$JAVA_HOME"
echo " APP_HOME=$APP_HOME"
echo " APP_NAME=$APP_NAME"
echo " APP_PORT=$APP_PORT"
function start {
if pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
then
echo "Service [$APP_NAME] is already running. Ignoring startup request."
exit 1
fi
echo "Starting application..."
nohup $JAVA_HOME/bin/java -jar $APP_HOME/$APP_NAME.jar \
--spring.config.location=file:$APP_HOME/config/ \
< /dev/null > $APP_HOME/logs/app.log 2>&1 &
}
function stop {
if ! pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
then
echo "Service [$APP_NAME] is not running. Ignoring shutdown request."
exit 1
fi
# First, we will try to trigger a controlled shutdown using
# spring-boot-actuator
curl -X POST http://localhost:$APP_PORT/shutdown < /dev/null > /dev/null 2>&1
# Wait until the server process has shut down
attempts=0
while pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
do
attempts=$[$attempts + 1]
if [ $attempts -gt 5 ]
then
# We have waited too long. Kill it.
pkill -f $APP_NAME.jar > /dev/null 2>&1
fi
sleep 1s
done
}
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
esac
exit 0
当停止时,它将尝试使用弹簧引导驱动器来执行受控关机。但是,如果没有配置执行器或未能在合理的时间范围内关闭(我给它5秒,这真的有点短),进程将被杀死。
此外,脚本还假设运行应用程序的java进程是进程详细信息文本中唯一带有“my-spring-boot-api.jar”的进程。在我的环境中,这是一个安全的假设,这意味着我不需要跟踪pid。
作为Windows服务
如果你想在windows机器上运行,请下载winsw.exe
http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw/2.1.2/
之后,将其重命名为jar文件名(例如:your-app.jar)
winsw.exe -> your-app.exe
现在创建一个xml文件your-app.xml,并将以下内容复制到该文件中
<?xml version="1.0" encoding="UTF-8"?>
<service>
<id>your-app</id>
<name>your-app</name>
<description>your-app as a Windows Service</description>
<executable>java</executable>
<arguments>-jar "your-app.jar"</arguments>
<logmode>rotate</logmode>
</service>
确保exe和xml以及jar文件在同一个文件夹中。
在此之后,在管理员权限下打开命令提示符并将其安装到windows服务。
your-app.exe install
eg -> D:\Springboot\your-app.exe install
如果失败了
Error: Registry key 'Software\JavaSoft\Java Runtime Environment'\CurrentVersion' has value '1.8', but '1.7' is required.
然后试试下面的方法:
Delete java.exe, javaw.exe and javaws.exe from C:\Windows\System32
就是这样:).
在windows下卸载服务
your-app.exe uninstall
查看/运行/停止服务: win+r并输入Administrative tools,然后从中选择服务。然后右击选择选项-运行/停止
构建中需要以下配置。Spring Boot项目中的gradle文件。
build.gradle
jar {
baseName = 'your-app'
version = version
}
springBoot {
buildInfo()
executable = true
mainClass = "com.shunya.App"
}
可执行文件= true
这是使jar在unix系统(Centos和Ubuntu)上完全可执行所必需的。
创建一个.conf文件
如果您想配置自定义JVM属性或Spring Boot应用程序运行参数,那么您可以创建一个与Spring Boot应用程序名称相同的.conf文件,并将其与jar文件并行放置。
考虑到your-app.jar是Spring Boot应用程序的名称,那么您可以创建以下文件。
JAVA_OPTS="-Xms64m -Xmx64m"
RUN_ARGS=--spring.profiles.active=prod
LOG_FOLDER=/custom/log/folder
此配置将为Spring Boot应用程序设置64 MB ram并激活prod配置文件。
在linux中创建一个新用户
为了增强安全性,我们必须创建一个特定的用户来运行Spring Boot应用程序作为服务。
创建新用户
sudo useradd -s /sbin/nologin springboot
在Ubuntu / Debian环境下,修改如下命令:
sudo useradd -s /usr/sbin/nologin springboot
设置密码
sudo passwd springboot
使springboot成为可执行文件的所有者
chown springboot:springboot your-app.jar
防止修改jar文件
chmod 500 your-app.jar
这将配置jar的权限,这样它就不能被写入,只能由它的所有者springboot读取或执行。
您可以使用change attribute (chattr)命令将jar文件设置为不可变的。
sudo chattr +i your-app.jar
也应该为相应的.conf文件设置适当的权限,.conf文件只需要读取权限(Octal 400),而不是读取+执行权限(Octal 500)
chmod 400 your-app.conf
创建Systemd服务
/etc/systemd/system/your-app.service
[Unit]
Description=Your app description
After=syslog.target
[Service]
User=springboot
ExecStart=/var/myapp/your-app.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
如果进程被操作系统杀死,将自动重启进程
添加以下两个属性(Restart和RestartSec)以在失败时自动重新启动进程。
/etc/systemd/system/your-app.service
[Service]
User=springboot
ExecStart=/var/myapp/your-app.jar
SuccessExitStatus=143
Restart=always
RestartSec=30
该更改将使Spring Boot应用程序在失败时重新启动,延迟30秒。如果使用systemctl命令停止服务,则不会重新启动。
在系统启动时安排服务
要标记应用程序在系统引导时自动启动,使用以下命令:
在系统启动时启用Spring Boot应用程序
sudo systemctl enable your-app.service
启动或停止服务
systemctl可以在Ubuntu 16.04 LTS和18.04 LTS中用于启动和停止进程。
开始这个过程
sudo systemctl start your-app
停止进程
sudo systemctl stop your-app
参考文献
https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
Following up on Chad's excellent answer, if you get an error of "Error: Could not find or load main class" - and you spend a couple hours trying to troubleshoot it, whether your executing a shell script that starts your java app or starting it from systemd itself - and you know your classpath is 100% correct, e.g. manually running the shell script works as well as running what you have in systemd execstart. Be sure you're running things as the correct user! In my case, I had tried different users, after quite a while of troubleshooting - i finally had a hunch, put root as the user - voila, the app started correctly. After determining it was a wrong user issue, I chown -R user:user the folder and subfolders and the app ran correctly as the specified user and group so no longer needed to run it as root (bad security).