安装 Spring Boot 应用程序

除了使用java -jar直接运行 Spring Boot 应用程序外,还可以将其作为systemdinit.d或 Windows 服务运行。

作为 systemd 服务安装

systemd 是 System V init 系统的后继者,现在被许多现代 Linux 发行版使用。可以使用systemd的“服务”脚本启动 Spring Boot 应用程序。

假设您有一个作为 uber jar 打包在/var/myapp中的 Spring Boot 应用程序,要将其作为systemd服务安装,请创建一个名为myapp.service的脚本并将其放置在/etc/systemd/system目录中。以下脚本提供了一个示例

[Unit]
Description=myapp
After=syslog.target network.target

[Service]
User=myapp
Group=myapp

Type=exec
ExecStart=/path/to/java/home/bin/java -jar /var/myapp/myapp.jar
WorkingDirectory=/var/myapp
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target
请记住为您的应用程序更改DescriptionUserGroupExecStartWorkingDirectory字段。
ExecStart字段不声明脚本操作命令,这意味着默认情况下使用run命令。

运行应用程序的用户、PID文件和控制台日志文件由systemd本身管理,因此必须使用“service”脚本中的相应字段进行配置。有关更多详细信息,请参阅服务单元配置手册页

要标记应用程序在系统启动时自动启动,请使用以下命令

$ systemctl enable myapp.service

运行man systemctl以获取更多详细信息。

作为init.d服务(System V)安装

要将您的应用程序用作init.d服务,请配置其构建以生成一个完全可执行的jar

完全可执行的jar通过在文件前面嵌入一个额外的脚本来工作。目前,某些工具不接受此格式,因此您可能并非总是能够使用此技术。例如,jar -xf可能会静默地无法提取已设置为完全可执行的jar或war文件。建议您仅在打算直接执行jar或war文件时,才将其设置为完全可执行,而不是使用java -jar运行它或将其部署到servlet容器中。
zip64格式的jar文件无法设置为完全可执行。尝试这样做会导致一个jar文件,当直接执行或使用java -jar执行时,该文件会被报告为已损坏。包含一个或多个zip64格式嵌套jar文件的标准格式jar文件可以是完全可执行的。

要使用Maven创建“完全可执行”的jar,请使用以下插件配置

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<configuration>
		<executable>true</executable>
	</configuration>
</plugin>

以下示例显示了等效的Gradle配置

tasks.named('bootJar') {
	launchScript()
}

然后可以将其符号链接到init.d以支持标准的startstoprestartstatus命令。

添加到完全可执行jar中的默认启动脚本支持大多数Linux发行版,并在CentOS和Ubuntu上进行了测试。其他平台(如OS X和FreeBSD)需要使用自定义脚本。默认脚本支持以下功能

  • 以拥有jar文件的用户身份启动服务

  • 使用/var/run/<appname>/<appname>.pid跟踪应用程序的PID

  • 将控制台日志写入/var/log/<appname>.log

假设您在/var/myapp中安装了一个Spring Boot应用程序,要将Spring Boot应用程序作为init.d服务安装,请创建符号链接,如下所示

$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

安装后,您可以以通常的方式启动和停止服务。例如,在基于Debian的系统上,您可以使用以下命令启动它

$ service myapp start
如果您的应用程序无法启动,请检查写入/var/log/<appname>.log的日志文件以查找错误。

您还可以使用标准操作系统工具标记应用程序以自动启动。例如,在Debian上,您可以使用以下命令

$ update-rc.d myapp defaults <priority>

保护init.d服务

以下是一组关于如何保护作为init.d服务运行的Spring Boot应用程序的指南。它并非旨在详尽列出应执行的所有操作以强化应用程序及其运行环境。

当以root用户身份执行时(例如,当使用root用户启动init.d服务时),默认的可执行脚本会以RUN_AS_USER环境变量中指定的用户身份运行应用程序。当未设置环境变量时,将使用拥有jar文件的用户。您永远不应该以root用户身份运行Spring Boot应用程序,因此RUN_AS_USER永远不应该为root,并且您的应用程序的jar文件永远不应该由root拥有。相反,创建一个特定的用户来运行您的应用程序并设置RUN_AS_USER环境变量或使用chown使其成为jar文件的拥有者,如以下示例所示

$ chown bootapp:bootapp your-app.jar

在这种情况下,默认的可执行脚本会以bootapp用户身份运行应用程序。

为了降低应用程序的用户帐户被入侵的可能性,您应该考虑阻止其使用登录shell。例如,您可以将帐户的shell设置为/usr/sbin/nologin

您还应该采取措施防止修改应用程序的jar文件。首先,配置其权限,使其不可写,并且只能由其所有者读取或执行,如以下示例所示

$ chmod 500 your-app.jar

其次,您还应该采取措施,以限制应用程序或正在运行它的帐户被入侵时的损害。如果攻击者确实获得了访问权限,他们可以使jar文件可写并更改其内容。防止此问题的一种方法是使用chattr使其不可变,如以下示例所示

$ sudo chattr +i your-app.jar

这将阻止任何用户(包括root用户)修改jar文件。

如果使用root用户来控制应用程序的服务,并且您使用.conf文件来自定义其启动,则.conf文件将由root用户读取和评估。应相应地对其进行保护。使用chmod以便只有所有者可以读取该文件,并使用chown使root成为所有者,如以下示例所示

$ chmod 400 your-app.conf
$ sudo chown root:root your-app.conf

自定义启动脚本

Maven或Gradle插件编写的默认嵌入式启动脚本可以通过多种方式进行自定义。对于大多数人来说,使用默认脚本以及一些自定义通常就足够了。如果您发现无法自定义您需要的内容,请使用embeddedLaunchScript选项完全编写您自己的文件。

在写入时自定义启动脚本

在启动脚本写入jar文件时自定义其元素通常很有意义。例如,init.d脚本可以提供“描述”。由于您事先知道描述(并且它不需要更改),因此您不妨在生成jar文件时提供它。

要自定义写入的元素,请使用Spring Boot Maven插件的embeddedLaunchScriptProperties选项或Spring Boot Gradle插件的launchScriptproperties属性

默认脚本支持以下属性替换

名称 描述 Gradle默认值 Maven默认值

mode

脚本模式。

auto

auto

initInfoProvides

“INIT INFO”的Provides部分

${task.baseName}

${project.artifactId}

initInfoRequiredStart

“INIT INFO”的Required-Start部分。

$remote_fs $syslog $network

$remote_fs $syslog $network

initInfoRequiredStop

“INIT INFO”的Required-Stop部分。

$remote_fs $syslog $network

$remote_fs $syslog $network

initInfoDefaultStart

“INIT INFO”的Default-Start部分。

2 3 4 5

2 3 4 5

initInfoDefaultStop

“INIT INFO”的Default-Stop部分。

0 1 6

0 1 6

initInfoShortDescription

“INIT INFO”的Short-Description部分。

${project.description}的单行版本(回退到${task.baseName}

${project.name}

initInfoDescription

“INIT INFO”的Description部分。

${project.description}(回退到${task.baseName}

${project.description}(回退到${project.name}

initInfoChkconfig

“INIT INFO”的chkconfig部分

2345 99 01

2345 99 01

confFolder

CONF_FOLDER的默认值

包含jar文件的文件夹

包含jar文件的文件夹

inlinedConfScript

对应一个应该内联到默认启动脚本中的文件脚本的引用。这可用于在加载任何外部配置文件之前设置环境变量(例如JAVA_OPTS

logFolder

LOG_FOLDER的默认值。仅对init.d服务有效

logFilename

LOG_FILENAME的默认值。仅对init.d服务有效

pidFolder

PID_FOLDER的默认值。仅对init.d服务有效

pidFilename

PID_FOLDER中PID文件的名称的默认值。仅对init.d服务有效

useStartStopDaemon

是否应使用start-stop-daemon命令(如果可用)来控制进程

true

true

stopWaitTime

STOP_WAIT_TIME的默认值(以秒为单位)。仅对init.d服务有效

60

60

在运行时自定义脚本

对于需要在jar文件写入之后进行自定义的脚本项,您可以使用环境变量或配置文件

默认脚本支持以下环境属性

变量 描述

MODE

操作的“模式”。默认值取决于jar文件的构建方式,但通常为auto(表示它尝试通过检查它是否在名为init.d的目录中是否为符号链接来猜测它是否为init脚本)。您可以将其显式设置为service,以便stop|start|status|restart命令起作用,或者如果要让脚本在前台运行,则将其设置为run

RUN_AS_USER

将用于运行应用程序的用户。未设置时,将使用拥有jar文件的用户。

USE_START_STOP_DAEMON

是否应使用start-stop-daemon命令(如果可用)来控制进程。默认为true

PID_FOLDER

pid文件夹的根名称(默认为/var/run)。

LOG_FOLDER

放置日志文件的文件夹的名称(默认为/var/log)。

CONF_FOLDER

读取.conf文件的文件夹的名称(默认为与jar文件相同的文件夹)。

LOG_FILENAME

LOG_FOLDER中日志文件的名称(默认为<appname>.log)。

APP_NAME

应用程序的名称。如果从符号链接运行jar文件,则脚本会猜测应用程序名称。如果它不是符号链接或您要显式设置应用程序名称,则这很有用。

RUN_ARGS

传递给程序(Spring Boot应用程序)的参数。

JAVA_HOME

java可执行文件的位置是默认情况下使用PATH发现的,但是如果$JAVA_HOME/bin/java处存在可执行文件,则可以显式设置它。

JAVA_OPTS

启动JVM时传递给JVM的选项。

JARFILE

jar文件的显式位置,以防脚本用于启动它实际上未嵌入的jar文件。

DEBUG

如果非空,则在shell进程上设置-x标志,允许您查看脚本中的逻辑。

STOP_WAIT_TIME

在停止应用程序之前等待强制关闭的时间(以秒为单位)(默认为60)。

PID_FOLDERLOG_FOLDERLOG_FILENAME变量仅对init.d服务有效。对于systemd,等效的自定义是使用“service”脚本进行的。有关更多详细信息,请参阅服务单元配置手册页
使用Conf文件

除了JARFILEAPP_NAME 之外,上一节中列出的设置可以通过使用.conf 文件进行配置。该文件应位于 jar 文件旁边,并具有相同的名称,但后缀为.conf 而不是.jar。例如,名为/var/myapp/myapp.jar 的 jar 使用名为/var/myapp/myapp.conf 的配置文件,如下例所示

myapp.conf
JAVA_OPTS=-Xmx1024M
LOG_FOLDER=/custom/log/folder
如果您不希望配置文件位于 jar 文件旁边,则可以设置CONF_FOLDER 环境变量来自定义配置文件的位置。

要了解如何适当地保护此文件,请参阅有关保护 init.d 服务的指南

Microsoft Windows 服务

可以使用 winsw 将 Spring Boot 应用程序作为 Windows 服务启动。

一个(单独维护的示例)逐步描述了如何为您的 Spring Boot 应用程序创建 Windows 服务。