如何在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是适当的。
当前回答
构建中需要以下配置。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
其他回答
我知道这是一个老问题,但我想提出另一种方法,即appassembler-maven-plugin。以下是我POM中的相关部分,其中包括许多我们认为有用的额外选项值:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<configuration>
<generateRepository>true</generateRepository>
<repositoryLayout>flat</repositoryLayout>
<useWildcardClassPath>true</useWildcardClassPath>
<includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
<configurationDirectory>config</configurationDirectory>
<target>${project.build.directory}</target>
<daemons>
<daemon>
<id>${installer-target}</id>
<mainClass>${mainClass}</mainClass>
<commandLineArguments>
<commandLineArgument>--spring.profiles.active=dev</commandLineArgument>
<commandLineArgument>--logging.config=${rpmInstallLocation}/config/${installer-target}-logback.xml</commandLineArgument>
</commandLineArguments>
<platforms>
<platform>jsw</platform>
</platforms>
<generatorConfigurations>
<generatorConfiguration>
<generator>jsw</generator>
<includes>
<include>linux-x86-64</include>
</includes>
<configuration>
<property>
<name>wrapper.logfile</name>
<value>logs/${installer-target}-wrapper.log</value>
</property>
<property>
<name>wrapper.logfile.maxsize</name>
<value>5m</value>
</property>
<property>
<name>run.as.user.envvar</name>
<value>${serviceUser}</value>
</property>
<property>
<name>wrapper.on_exit.default</name>
<value>RESTART</value>
</property>
</configuration>
</generatorConfiguration>
</generatorConfigurations>
<jvmSettings>
<initialMemorySize>256M</initialMemorySize>
<maxMemorySize>1024M</maxMemorySize>
<extraArguments>
<extraArgument>-server</extraArgument>
</extraArguments>
</jvmSettings>
</daemon>
</daemons>
</configuration>
<executions>
<execution>
<id>generate-jsw-scripts</id>
<phase>package</phase>
<goals>
<goal>generate-daemons</goal>
</goals>
</execution>
</executions>
</plugin>
我最终为WAR/JAR布局做了systemd服务
我调用java -jar是因为它更灵活。我还试着把ExecStart=spring-mvc。战争,但即使是可执行的,我得到'Exec格式错误'
无论如何,现在systemd出现在所有发行版上,并提供了一个很好的解决方案来重定向日志(syserr是重要的,当你的服务甚至没有启动log4j文件位置将为空:))。
cat /etc/systemd/system/spring-mvc.service
[Unit]
Description=Spring MVC Java Service
[Service]
User=spring-mvc
# The configuration file application.properties should be here:
WorkingDirectory=/usr/local/spring-mvc
# Run ExecStartPre with root-permissions
PermissionsStartOnly=true
ExecStartPre=-/bin/mkdir -p /var/log/spring-mvc
ExecStartPre=/bin/chown -R spring-mvc:syslog /var/log/spring-mvc
ExecStartPre=/bin/chmod -R 775 /var/log/spring-mvc
#https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
ExecStart=/usr/bin/java \
-Dlog4j.configurationFile=log4j2-spring.xml \
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \
-Dspring.profiles.active=dev \
-Denvironment-type=dev \
-XX:+UseConcMarkSweepGC \
-XX:CMSInitiatingOccupancyFraction=80 \
-XX:NewSize=756m \
-XX:MetaspaceSize=256m \
-Dsun.net.inetaddr.ttl=5 \
-Xloggc:/var/log/spring-mvc/gc.log \
-verbose:gc \
-verbosegc \
-XX:+DisableExplicitGC \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+PreserveFramePointer \
-XX:+StartAttachListener \
-Xms1024m \
-Xmx1024m \
-XX:+HeapDumpOnOutOfMemoryError \
-jar spring-mvc.war
SuccessExitStatus=143
StandardOutput=journal
StandardError=journal
KillSignal=SIGINT
TimeoutStopSec=20
Restart=always
RestartSec=5
StartLimitInterval=0
StartLimitBurst=10
LimitNOFILE=500000
LimitNPROC=500000
#https://www.freedesktop.org/software/systemd/man/systemd.exec.html#LimitCPU=
#LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=, LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=, LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=, LimitRTTIME=¶
SyslogIdentifier=spring-mvc
[Install]
WantedBy=multi-user.target
# https://www.freedesktop.org/software/systemd/man/journalctl.html
#check logs --- journalctl -u spring-mvc -f -o cat
Rsyslog -将应用程序的syslog输入重定向到特定的文件夹/文件
cat /etc/rsyslog.d/30-spring-mvc.conf
if $programname == 'spring-mvc' then /var/log/spring-mvc/spring-mvc.log
& stop
logrotate
cat /etc/logrotate.d/spring-mvc.conf
/var/log/spring-mvc/spring-mvc.log
{
daily
rotate 30
maxage 30
copytruncate
missingok
notifempty
compress
dateext
dateformat _%Y-%m-%d_%H-%M
delaycompress
create 644 spring-mvc syslog
su spring-mvc syslog
}
logrotate gc
cat /etc/logrotate.d/spring-mvc-gc.conf
/var/log/spring-mvc/gc.log
{
daily
rotate 30
maxage 30
copytruncate
missingok
notifempty
compress
dateext
dateformat _%Y-%m-%d_%H-%M
delaycompress
create 644 spring-mvc syslog
su spring-mvc syslog
}
I don't know of a "standard" shrink-wrapped way to do that with a Java app, but it's definitely a good idea (you want to benefit from the keep-alive and monitoring capabilities of the operating system if they are there). It's on the roadmap to provide something from the Spring Boot tool support (maven and gradle), but for now you are probably going to have to roll your own. The best solution I know of right now is Foreman, which has a declarative approach and one line commands for packaging init scripts for various standard OS formats (monit, sys V, upstart etc.). There is also evidence of people having set stuff up with gradle (e.g. here).
在这个问题中,@PbxMan的回答可以让你开始:
在Linux上运行Java应用程序作为服务
编辑:
还有另一种不太好的方式在重启时启动进程,使用cron:
@reboot user-to-run-under /usr/bin/java -jar /path/to/application.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