59. 安装 Spring Boot 应用程序

除了使用java -jar运行 Spring Boot 应用程序外,还可以为 Unix 系统制作完全可执行的应用程序。完全可执行的 jar 可以像其他任何可执行二进制文件一样执行,也可以是在 init.d 或 systemd 中注册。这使得在普通生产环境中安装和 ManagementSpring Boot 应用程序变得非常容易。

Warning

完全可执行的 jar 通过在文件的开头嵌入一个额外的脚本来工作。当前,某些工具不接受此格式,因此您可能无法始终使用该技术。例如,jar -xf可能无声地无法提取出可以完全执行的 jar 或 war。建议仅在打算直接执行 jar 或 war 时才使其完全可执行,而不是使用java -jar运行它或将其部署到 servlet 容器中。

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

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

使用 Gradle,等效配置为:

springBoot {
    executable = true
}

然后,您可以通过键入./my-application.jar(其中my-application是工件的名称)来运行您的应用程序。包含 jar 的目录将用作您应用程序的工作目录。

59.1 支持的 os

默认脚本支持大多数 Linux 发行版,并已在 CentOS 和 Ubuntu 上进行了测试。其他平台,例如 OS X 和 FreeBSD,将要求使用自定义embeddedLaunchScript

59.2 Unix/Linux 服务

使用init.dsystemd可以轻松地将 Spring Boot 应用程序作为 Unix/Linux 服务启动。

59.2.1 作为 init.d 服务安装(系统 V)

如果您已经配置了 Spring Boot 的 Maven 或 Gradle 插件来生成完全可执行的 jar,并且没有使用自定义embeddedLaunchScript,那么您的应用程序可以用作init.d服务。只需将 jar 链接到init.d以支持标准的startstoprestartstatus命令。

该脚本支持以下功能:

  • 以拥有 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

Tip

如果您的应用程序无法启动,请检查写入/var/log/<appname>.log的日志文件是否有错误。

您还可以标记应用程序以使用标准 os 工具自动启动。例如,在 Debian 上:

$ update-rc.d myapp defaults <priority>

保护 init.d 服务

Note

以下是一组有关如何保护作为 init.d 服务运行的 Spring Boot 应用程序的准则。它并不旨在详尽列出增强应用程序及其运行环境所需的所有工作。

当以 root 身份执行时(例如使用 root 来启动 init.d 服务时),默认的可执行脚本将以拥有 jar 文件的用户身份运行应用程序。您永远不要以root的身份运行 Spring Boot 应用程序,因此您的应用程序的 jar 文件绝对不应由 root 拥有。而是创建一个特定用户来运行您的应用程序,并使用chown使其成为 jar 文件的所有者。例如:

$ chown bootapp:bootapp your-app.jar

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

Tip

为了减少应用程序的用户帐户遭到破坏的机会,应考虑阻止它使用登录 Shell 程序。例如,将帐户的 Shell 设置为/usr/sbin/nologin

您还应该采取步骤来防止修改应用程序的 jar 文件。首先,配置其权限,使其不能被写入,只能由其所有者读取或执行:

$ chmod 500 your-app.jar

其次,如果您的应用程序或运行该应用程序的帐户受到威胁,则还应采取措施限制损害。如果攻击者确实获得了访问权限,则他们可以使 jar 文件可写并更改其内容。防止这种情况发生的一种方法是使用chattr使其不可变:

$ sudo chattr +i your-app.jar

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

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

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

59.2.2 作为系统服务安装

Systemd 是 System V init 系统的后继产品,现在被许多现代 Linux 发行版使用。尽管您可以 continue 将init.d脚本与systemd一起使用,但是也可以使用systemd'service'脚本来启动 Spring Boot 应用程序。

假设您已在/var/myapp中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序作为systemd服务安装,请使用以下示例创建名为myapp.service的脚本并将其放置在/etc/systemd/system目录中:

[Unit]
Description=myapp
After=syslog.target

[Service]
User=myapp
ExecStart=/var/myapp/myapp.jar
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

Tip

切记为您的应用程序更改DescriptionUserExecStart字段。

Tip

请注意,ExecStart字段未声明脚本操作命令,这意味着默认情况下使用run命令。

请注意,与作为init.d服务运行时不同,运行应用程序,PID 文件和控制台日志文件的用户由systemd本身 Management,因此必须使用“服务”脚本中的适当字段进行配置。有关更多详细信息,请咨询服务单元配置手册页

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

$ systemctl enable myapp.service

有关更多详细信息,请参考man systemctl

59.2.3 自定义启动脚本

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

编写脚本时自定义脚本

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

要自定义书面元素,请使用 Spring Boot Maven 或 Gradle 插件的embeddedLaunchScriptProperties选项。

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

NameDescription
mode脚本模式。默认为auto
initInfoProvides“ INIT INFO”的Provides部分。对于 Gradle,默认为spring-boot-application;对于 Maven,默认为${project.artifactId}
initInfoRequiredStart“ INIT INFO”的Required-Start部分。默认为$remote_fs $syslog $network
initInfoRequiredStop“ INIT INFO”的Required-Stop部分。默认为$remote_fs $syslog $network
initInfoDefaultStart“ INIT INFO”的Default-Start部分。默认为2 3 4 5
initInfoDefaultStop“ INIT INFO”的Default-Stop部分。默认为0 1 6
initInfoShortDescription“ INIT INFO”的Short-Description部分。对于 Gradle,默认为Spring Boot Application;对于 Maven,默认为${project.name}
initInfoDescription“ INIT INFO”的Description部分。对于 Gradle,默认值为Spring Boot Application;对于 Maven,默认为${project.description}(回落为${project.name})。
initInfoChkconfig“ INIT INFO”的chkconfig部分。默认为2345 99 01
confFolderCONF_FOLDER的默认值。默认为包含 jar 的文件夹。
logFolderLOG_FOLDER的默认值。仅对init.d服务有效。
logFilenameLOG_FILENAME的默认值。仅对init.d服务有效。
pidFolderPID_FOLDER的默认值。仅对init.d服务有效。
pidFilenamePID_FOLDER中 pid 文件名称的默认值。仅对init.d服务有效。
useStartStopDaemon如果start-stop-daemon命令可用,则应使用它来控制过程。默认为true
stopWaitTimeSTOP_WAIT_TIME的默认值。仅对init.d服务有效。默认为 60 秒。

运行时自定义脚本

对于脚本中需要自定义的项目,在Jar子写完之后,可以使用环境变量或config file

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

VariableDescription
MODE操作的“模式”。默认值取决于 jar 的构建方式,但通常为auto (表示通过检查目录init.d中的符号链接来尝试猜测它是否为初始化脚本)。您可以将其显式设置为service,以便stop|start|status|restart命令起作用;如果您只想在前台运行脚本,则可以将其设置为run
USE_START_STOP_DAEMON如果start-stop-daemon命令可用,则应使用它来控制过程。默认为true
PID_FOLDERpid 文件夹的根名称(默认为/var/run)。
LOG_FOLDER放置日志文件的文件夹的名称(默认为/var/log)。
CONF_FOLDER从中读取.conf 文件的文件夹的名称(默认情况下与 jar 文件相同的文件夹)。
LOG_FILENAMELOG_FOLDER(默认为<appname>.log)中的日志文件名称。
APP_NAME应用程序的名称。如果 jar 是从符号链接运行的,则脚本会猜测应用程序的名称,但是如果不是符号链接,或者您想显式设置应用程序的名称,则可能会有用。
RUN_ARGS传递给程序的参数(Spring Boot 应用程序)。
JAVA_HOME默认情况下,通过使用PATH发现java可执行文件的位置,但是如果$JAVA_HOME/bin/java处有可执行文件,则可以显式设置它。
JAVA_OPTS启动 JVM 时传递给 JVM 的选项。
JARFILEjar 文件的显式位置,以防脚本被用于启动实际上未嵌入的 jar。
DEBUG如果不为空,则会在 shell 进程中设置-x标志,从而易于查看脚本中的逻辑。
STOP_WAIT_TIME停止应用程序之前要强制关闭的 await 时间(以秒为单位)(默认为60)。

Note

PID_FOLDERLOG_FOLDERLOG_FILENAME变量仅对init.d服务有效。对于systemd,等效的自定义项是使用“服务”脚本进行的。查看服务单元配置手册页以获取更多详细信息。

除了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

Tip

如果您不喜欢配置文件位于 jar 旁边,则可以使用CONF_FOLDER环境变量来自定义配置文件的位置。

要了解有关适当保护此文件的信息,请参阅确保 init.d 服务的准则

59.3 Microsoft Windows 服务

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

Spring Boot 核心的示例maintained separately分步介绍了如何为 Spring Boot 应用程序创建 Windows 服务。