如何在Linux系统中很好地配置打包为可执行jar即服务的Spring Boot应用程序?这是推荐的方法,还是应该将此应用程序转换为战争并将其安装到 Tomcat 中?
目前,我可以从 screen
会话运行 Spring Boot 应用程序,这很好,但需要在服务器重新启动后手动启动。
如果我使用可执行 jar 的方法合适,我正在寻找的是一般建议/指导或示例 init.d
脚本。
以下适用于 springboot 1.3 及更高版本:
作为 init.d 服务
可执行 jar 具有通常的启动、停止、重新启动和状态命令。它还将在通常的 /var/run 目录中设置一个 PID 文件,并默认登录通常的 /var/log 目录。
你只需要像这样将你的 jar 符号链接到 /etc/init.d
sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp
或者
sudo ln -s ~/myproject/build/libs/myapp-1.0.jar /etc/init.d/myapp_servicename
之后你可以照常做
/etc/init.d/myapp start
如果需要,然后在您希望应用程序在启动时启动/停止的任何运行级别中设置一个链接。
作为系统服务
要运行安装在 var/myapp 中的 Spring Boot 应用程序,您可以在 /etc/systemd/system/myapp.service 中添加以下脚本:
[Unit]
Description=myapp
After=syslog.target
[Service]
ExecStart=/var/myapp/myapp.jar
[Install]
WantedBy=multi-user.target
注意:如果您使用此方法,请不要忘记使 jar 文件本身可执行(使用 chmod +x),否则它将失败并出现错误“权限被拒绝”。
参考
以下是在 Linux 中将 Java 应用程序安装为系统服务的最简单方法。
假设您正在使用 systemd
(现在任何现代发行版都使用):
首先,在 /etc/systemd/system
中创建一个名为 javaservice.service
的服务文件,其中包含以下内容:
[Unit]
Description=Java Service
[Service]
User=nobody
# The configuration file application.properties should be here:
WorkingDirectory=/data
ExecStart=/usr/bin/java -Xmx256m -jar application.jar --server.port=8081
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
其次,通知 systemd
新的服务文件:
systemctl daemon-reload
并启用它,使其在启动时运行:
systemctl enable javaservice.service
最终,您可以使用以下命令启动/停止新服务:
systemctl start javaservice
systemctl stop javaservice
systemctl restart javaservice
systemctl status javaservice
如果您使用 systemd
,这是将 Java 应用程序设置为系统服务的最非侵入性和最干净的方法。
我特别喜欢这个解决方案的一点是,您不需要安装和配置任何其他软件。随附的 systemd
为您完成所有工作,您的服务的行为与任何其他系统服务一样。我现在在生产中使用了一段时间,在各种发行版上,它就像你期望的那样工作。
另一个优点是,通过使用 /usr/bin/java
,您可以轻松添加 jvm
参数,例如 -Xmx256m
。
另请阅读官方 Spring Boot 文档中的 systemd
部分:http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
[Unit]
部分,例如 After=mysql.service
、Before=apache2.service
。
您还可以使用 supervisord,它是一个非常方便的守护程序,可用于轻松控制服务。这些服务由简单的配置文件定义,这些文件定义了在哪个目录中与哪个用户一起执行什么,等等,有无数的选项。 supervisord 具有非常简单的语法,因此它是编写 SysV 初始化脚本的一个很好的替代方案。
这是您尝试运行/控制的程序的简单supervisord配置文件。 (把这个放到/etc/supervisor/conf.d/yourapp.conf)
/etc/supervisor/conf.d/yourapp.conf
[program:yourapp]
command=/usr/bin/java -jar /path/to/application.jar
user=usertorun
autostart=true
autorestart=true
startsecs=10
startretries=3
stdout_logfile=/var/log/yourapp-stdout.log
stderr_logfile=/var/log/yourapp-stderr.log
要控制应用程序,您需要执行 supervisorctl,它将向您显示一个提示,您可以在其中启动、停止、状态您的应用程序。
命令行界面
# sudo supervisorctl
yourapp RUNNING pid 123123, uptime 1 day, 15:00:00
supervisor> stop yourapp
supervisor> start yourapp
如果 supervisord
守护程序已在运行,并且您已为服务添加配置而无需重新启动守护程序,则只需在 supervisorctl
shell 中执行 reread
和 update
命令即可。
这确实为您提供了使用 SysV Init 脚本所具有的所有灵活性,但易于使用和控制。看看 documentation。
systemd
的作用相同,后者内置于大多数当前的 Linux 发行版中。
我自己刚刚开始做这件事,所以以下是我目前为止的 CentOS init.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
停止时,它将尝试使用 Spring Boot Actuator 执行受控关闭。但是,如果 Actuator 未配置或未能在合理的时间范围内关闭(我给它 5 秒,这确实有点短),该进程将被终止。
此外,脚本假设运行应用程序的 java 进程将是唯一在进程详细信息文本中带有“my-spring-boot-api.jar”的进程。在我的环境中这是一个安全的假设,这意味着我不需要跟踪 PID。
java -jar
执行的需要。脚本的其余部分仍然需要。
如果您想将 Spring Boot 1.2.5 与 Spring Boot Maven Plugin 1.3.0.M2 一起使用,这里有一个解决方案:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.0.M2</version>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>spring-libs-milestones</id>
<url>http://repo.spring.io/libs-milestone</url>
</pluginRepository>
</pluginRepositories>
然后像往常一样编译:mvn clean package
,创建符号链接 ln -s /.../myapp.jar /etc/init.d/myapp
,使其可执行 chmod +x /etc/init.d/myapp
并启动它 service myapp start
(使用 Ubuntu 服务器)
1.3.0.M2
,但是当我尝试 1.3.0.RC1
时出现错误。
springBoot { executable = true }
块完成。
我知道这是一个较老的问题,但我想介绍另一种方式,即 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>
作为 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 并键入管理工具,然后从中选择服务。然后右键选择选项-运行/停止
这是一个将可执行 jar 部署为 systemd 服务的脚本。
它为服务和 .service 文件创建一个用户,并将 jar 文件放在 /var 下,并进行一些基本的权限锁定。
#!/bin/bash
# Argument: The jar file to deploy
APPSRCPATH=$1
# Argument: application name, no spaces please, used as folder name under /var
APPNAME=$2
# Argument: the user to use when running the application, may exist, created if not exists
APPUSER=$3
# Help text
USAGE="
Usage: sudo $0 <jar-file> <app-name> <runtime-user>
If an app with the name <app-name> already exist, it is stopped and deleted.
If the <runtime-user> does not already exist, it is created.
"
# Check that we are root
if [ ! "root" = "$(whoami)" ]; then
echo "Must be root. Please use e.g. sudo"
echo "$USAGE"
exit
fi
# Check arguments
if [ "$#" -ne 3 -o ${#APPSRCPATH} = 0 -o ${#APPNAME} = 0 -o ${#APPUSER} = 0 ]; then
echo "Incorrect number of parameters."
echo "$USAGE"
exit
fi
if [ ! -f $APPSRCPATH ]; then
echo "Can't find jar file $APPSRCPATH"
echo "$USAGE"
exit
fi
# Infered values
APPFILENAME=$(basename $APPSRCPATH)
APPFOLDER=/var/javaapps/$APPNAME
APPDESTPATH=$APPFOLDER/$APPFILENAME
# Stop the service if it already exist and is running
systemctl stop $APPNAME >/dev/null 2>&1
# Create the app folder, deleting any previous content
rm -fr $APPFOLDER
mkdir -p $APPFOLDER
# Create the user if it does not exist
if id "$APPUSER" >/dev/null 2>&1; then
echo "Using existing user $APPUSER"
else
adduser --disabled-password --gecos "" $APPUSER
echo "Created user $APPUSER"
fi
# Place app in app folder, setting owner and rights
cp $APPSRCPATH $APPDESTPATH
chown $APPUSER $APPDESTPATH
chmod 500 $APPDESTPATH
echo "Added or updated the $APPDESTPATH file"
# Create the .service file used by systemd
echo "
[Unit]
Description=$APPNAME
After=syslog.target
[Service]
User=$APPUSER
ExecStart=/usr/bin/java -jar $APPDESTPATH
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
" > /etc/systemd/system/$APPNAME.service
echo "Created the /etc/systemd/system/$APPNAME.service file"
# Reload the daemon
systemctl daemon-reload
# Start the deployed app
systemctl start $APPNAME
systemctl status $APPNAME
https://i.stack.imgur.com/N8JXA.png
我的 Centos 6 / RHEL 的 SysVInit 脚本(还不理想)。此脚本需要 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
我正在尝试制作以“init.d”样式的shell脚本形式呈现的springboot应用程序,并在最后添加一个压缩的java应用程序
通过将这些脚本从 /etc/init.d/spring-app 符号链接到 /opt/spring-app.jar 并将 jar 修改为可执行,可以使“/etc/init.d/spring-app start " "/etc/init.d/spring-app stop" 和其他可能性,如状态工作
据推测,由于 springboot 中的 init.d 样式脚本看起来它们具有必要的魔术字符串(如 # Default-Start: 2 3 4 5
),chkconfig 将能够将其添加为“服务”
但我想让它与 systemd 一起工作
为了完成这项工作,我在上面的其他答案中尝试了许多recipies,但它们都没有在 Centos 7.2 和 Springboot 1.3 上为我工作。大多数情况下,它们会启动服务但无法跟踪 pid
最后,当 /etc/init.d 链接也到位时,我发现以下内容对我有用。应将类似于以下文件的文件安装为 /usr/lib/systemd/system/spring-app.service
[Unit]
Description=My loverly application
After=syslog.target
[Service]
Type=forking
PIDFile=/var/run/spring-app/spring-app.pid
ExecStart=/etc/init.d/spring-app start
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
我最终为 WAR/JAR 布局提供了 systemd 服务
我调用 java -jar 是因为它更灵活。也试过把 ExecStart=spring-mvc.war 但即使是可执行的,我也得到了“执行格式错误”
无论如何,这些天来,systemd 存在于所有发行版中,并提供了一个很好的重定向日志的解决方案(当您的服务甚至没有启动 log4j 文件位置时,syserr 很重要文件位置将为空:))。
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 - 将系统日志输入从应用程序重定向到特定文件夹/文件
cat /etc/rsyslog.d/30-spring-mvc.conf
if $programname == 'spring-mvc' then /var/log/spring-mvc/spring-mvc.log
& stop
对数旋转
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
}
对数旋转 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
}
在这个问题中,@PbxMan 的回答应该可以帮助您入门:
Run a Java Application as a Service on Linux
编辑:
还有另一种不太好的方法来在重新启动时启动进程,使用 cron:
@reboot user-to-run-under /usr/bin/java -jar /path/to/application.jar
这可行,但没有为您的应用程序提供好的启动/停止界面。无论如何,您仍然可以简单地 kill
它...
你在使用 Maven 吗?然后你应该试试 AppAssembler 插件:
Application Assembler Plugin 是一个 Maven 插件,用于生成用于启动 java 应用程序的脚本。 ...所有工件(依赖项+项目中的工件)都添加到生成的 bin 脚本中的类路径中。支持的平台:Unix 变体 Windows NT(不支持 Windows 9x) Java Service Wrapper (JSW)
请参阅:http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/index.html
Spring Boot 项目的 build.gradle 文件中需要进行如下配置。
构建.gradle
jar {
baseName = 'your-app'
version = version
}
springBoot {
buildInfo()
executable = true
mainClass = "com.shunya.App"
}
可执行=真
这是在 unix 系统(Centos 和 Ubuntu)上制作完全可执行的 jar 所必需的
创建一个 .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 内存并激活 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读取或执行。
您可以选择使用更改属性 (chattr) 命令将您的 jar 文件设置为不可变的。
sudo chattr +i your-app.jar
也应为相应的 .conf 文件设置适当的权限。 .conf 只需要读取权限(八进制 400)而不是读取 + 执行(八进制 500)权限
chmod 400 your-app.conf
创建系统服务
/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
跟进 Chad 的出色回答,如果您收到 "Error: Could not find or load main class" 错误 - 并且您花了几个小时尝试排除故障,无论您执行的 shell 脚本是否启动您的 java 应用程序或从 systemd 本身启动它——并且您知道您的类路径是 100% 正确的,例如手动运行 shell 脚本以及运行您在 systemd execstart 中的内容。 确保您是以正确的用户身份运行的!在我的情况下,我尝试了不同的用户,经过相当长的故障排除 - 我终于有预感,将 root 作为用户 - 瞧,应用程序正确启动。在确定这是一个错误的用户问题后,我 chown -R user:user
文件夹和子文件夹以及应用程序作为指定的用户和组正确运行,因此不再需要以 root 身份运行它(安全性差)。
在 systemd 单元文件中,您可以设置环境变量目录或通过 EnvironmentFile
。我建议以这种方式做事,因为它似乎是最少的摩擦。
样本单元文件
$ cat /etc/systemd/system/hello-world.service
[Unit]
Description=Hello World Service
After=systend-user-sessions.service
[Service]
EnvironmentFile=/etc/sysconfig/hello-world
Type=simple
ExecStart=/usr/bin/java ... hello-world.jar
然后在 /etc/sysconfig/hello-world
下设置一个文件,其中包含 Spring Boot 变量的大写名称。例如,名为 server.port
的变量将遵循 SERVER_PORT
的形式作为环境变量:
$ cat /etc/sysconfig/hello-world
SERVER_PORT=8081
这里利用的机制是 Spring Boot 应用程序将获取属性列表,然后翻译它们,将所有内容设为大写,并用下划线替换点。一旦 Spring Boot 应用程序完成此过程,它就会查找匹配的环境变量,并相应地使用任何找到的变量。
此 SO Q&A 中更详细地强调了这一点,标题为:How to set a Spring Boot property with an underscore in its name via Environment Variables?
参考
第四部分。 Spring Boot 特性之二十四、外部化配置
可以在 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
创建一个名为 your-app.service (rest-app.service) 的脚本。我们应该将此脚本放在 /etc/systemd/system 目录中。这是脚本的示例内容
[Unit]
Description=Spring Boot REST Application
After=syslog.target
[Service]
User=javadevjournal
ExecStart=/var/rest-app/restdemo.jar
SuccessExitStatus=200
[Install]
WantedBy=multi-user.target
下一个:
service rest-app start
参考
对于 SpringBoot 2.4.4,除了 @ismael 的说明外
我在我的 maven pom.xml 中有以下内容,使其成为可执行的 jar
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<executable>true</executable>
添加到我的pom.xml
,但打包的 JAR 文件没有执行(..../myapp.jar ... cannot execute binary file
。)-Dspring.profiles.active=prod
)传递给此服务吗?问题 - stackoverflow.com/questions/31242291/…/etc/init.d stop
没有停止应用程序,而是尝试重新启动它。