在部署应用程序时,Spring Boot 的灵活打包选项提供了很多选择。您可以将 Spring Boot 应用程序部署到各种云平台,容器映像(例如 Docker)或虚拟机/真实机上。
本节介绍一些更常见的部署方案。
部署到云端
Spring Boot 的可执行 jar 已为大多数流行的云 PaaS(平台即服务)提供程序准备就绪。这些提供程序往往要求您“自带容器”。他们 Management 应用程序流程(不是专门用于 Java 应用程序),因此他们需要一个中间层,以使您的应用程序适应运行过程的“云”概念。
两家受欢迎的云提供商,Heroku 和 Cloud Foundry,采用了“构建包”方法。 buildpack 将您部署的代码包装在“启动”应用程序所需的任何内容中。它可能是 JDK,也可能是对java
的调用,嵌入式 Web 服务器或成熟的应用程序服务器。一个 buildpack 是可插入的,但是理想情况下,您应该能够通过尽可能少的自定义来获得它。这减少了您无法控制的功能的占用空间。它使开发和生产环境之间的差异最小化。
理想情况下,您的应用程序像 Spring Boot 可执行 jar 一样,具有打包运行所需的一切。
在本节中,我们将介绍如何在“Starter”部分中启动我们开发的简单应用程序并在云中运行。
云计算
如果未指定其他构建包,Cloud Foundry 将提供默认的构建包。 Cloud Foundry Java buildpack对 Spring 应用程序(包括 Spring Boot)提供了出色的支持。您可以部署独立的可执行 jar 应用程序以及传统的.war
打包应用程序。
一旦构建了应用程序(例如,使用mvn clean package
)并拥有安装了 cf 命令行工具,就可以使用cf push
命令部署您的应用程序,并替换已编译的.jar
的路径。在推送应用程序之前,请确保拥有使用 cf 命令行 Client 端登录。以下行显示了使用cf push
命令部署应用程序:
1 | $ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar |
Note
在前面的示例中,我们用
acloudyspringtime
代替您给cf
作为应用程序名称的任何值。
有关更多选项,请参见cf 推文档。如果同一目录中存在 Cloud Foundry manifest.yml文件,则认为该文件。
此时,cf
开始上载您的应用程序,产生类似于以下示例的输出:
1 | Uploading acloudyspringtime... OK |
恭喜你!该应用程序现已上线!
应用程序上线后,可以使用cf apps
命令验证已部署应用程序的状态,如以下示例所示:
1 | $ cf apps |
一旦 Cloud Foundry 确认已部署了您的应用程序,您就应该能够在给定的 URI 上找到该应用程序。在前面的示例中,您可以在http://acloudyspringtime.cfapps.io/
找到它。
绑定到服务
默认情况下,有关正在运行的应用程序以及服务连接信息的元数据作为环境变量(例如$VCAP_SERVICES
)公开给应用程序。该架构决定是由于 Cloud Foundry 的多语言(可以将任何语言和平台支持为 buildpack)所决定的。过程范围的环境变量与语言无关。
环境变量并非总是使用最简单的 API,因此 Spring Boot 会自动提取它们并将数据展平为可以通过 Spring 的Environment
抽象访问的属性,如以下示例所示:
1 |
|
所有 Cloud Foundry 属性均以vcap
为前缀。您可以使用vcap
属性来访问应用程序信息(例如应用程序的公共 URL)和服务信息(例如数据库凭据)。有关完整的详细信息,请参见‘CloudFoundryVcapEnvironmentPostProcessor’ Javadoc。
Tip
Spring Cloud 连接器项目更适合诸如配置数据源之类的任务。 Spring Boot 包括自动配置支持和
spring-boot-starter-cloud-connectors
启动器。
Kubernetes
Spring Boot通过检查环境中的“_SERVICE_HOST”和“_SERVICE_PORT”变量来自动检测Kubernetes部署环境。您可以使用spring.main覆盖此检测。spring.main.cloud-platform
云平台配置属性。
Spring Boot帮助您管理应用程序的状态,并使用执行器使用HTTP Kubernetes探针导出它。
Kubernetes容器生命周期
当Kubernetes删除一个应用程序实例,同时关闭过程包括几个子系统:关闭钩子,取消注册服务,消除负载平衡器的实例,因为这关闭处理发生在平行(由于分布式系统的本质),有一个窗口在此期间交通可以被路由到一个豆荚,也已经开始关闭处理。
您可以在preStop处理程序中配置睡眠执行,以避免请求被路由到已经开始关闭的pod。这个休眠应该足够长,以便停止将新请求路由到pod,其持续时间因部署而异。可以通过pod的配置文件中的PodSpec配置preStop处理器,如下所示:
1 | spec: |
一旦预停止钩子完成,SIGTERM将被发送到容器,优雅的关闭将开始,允许任何剩余的正在运行的请求完成。
Heroku
Heroku 是另一个流行的 PaaS 平台。要自定义 Heroku 构建,请提供Procfile
,它提供部署应用程序所需的内容。 Heroku 为 Java 应用程序分配一个port
,然后确保路由到外部 URI 起作用。
您必须配置您的应用程序以侦听正确的端口。以下示例显示了我们的 Starter REST 应用程序的Procfile
:
1 | web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar |
Spring Boot 使-D
参数作为可从 Spring Environment
实例访问的属性。 server.port
配置属性被馈送到嵌入式 Tomcat,Jetty 或 Undertow 实例,然后在启动时使用该端口。 $PORT
环境变量是由 Heroku PaaS 分配给我们的。
这应该是您需要的一切。 Heroku 部署最常见的部署工作流程是将代码git push
投入生产,如以下示例所示:
1 | $ git push heroku master |
您的应用程序现在应该已经在 Heroku 上启动并运行了。
OpenShift
OpenShift是 Kubernetes 容器编排平台的 Red Hat 公共(和企业)扩展。与 Kubernetes 相似,OpenShift 具有许多用于安装基于 Spring Boot 的应用程序的选项。
OpenShift 有许多资源描述了如何部署 Spring Boot 应用程序,包括:
AmazonWebServices(AWS)
Amazon Web Services 提供了多种安装基于 Spring Boot 的应用程序的方法,这些方法既可以作为传统的 Web 应用程序(war),也可以作为具有嵌入式 Web 服务器的可执行 jar 文件安装。选项包括:
- AWS Elastic Beanstalk
- AWS Code Deploy
- AWS OPS 作品
- AWS 云形成
- AWS 容器注册表
每个都有不同的功能和定价模型。在本文档中,我们仅描述最简单的选项:AWS Elastic Beanstalk。
AWS Elastic Beanstalk
如官方Elastic Beanstalk Java 指南中所述,部署 Java 应用程序有两个主要选项。您可以使用“ Tomcat 平台”或“ Java SE 平台”。
使用Tomcat平台
该选项适用于产生 war 文件的 Spring Boot 项目。无需特殊配置。您只需要遵循官方指南即可。
使用JavaSE平台
该选项适用于产生 jar 文件并运行嵌入式 Web 容器的 Spring Boot 项目。 Elastic Beanstalk 环境在端口 80 上运行 nginx 实例以代理在端口 5000 上运行的实际应用程序。要对其进行配置,请将以下行添加到application.properties
文件:
1 | 5000 = |
Tip
默认情况下,Elastic Beanstalk 上载源并在 AWS 中进行编译。但是,最好改为上传二进制文件。为此,请在您的
.elasticbeanstalk/config.yml
文件中添加类似于以下内容的行:
1
2 deploy:
artifact: target/demo-0.0.1-SNAPSHOT.jarTip
默认情况下,Elastic Beanstalk 环境是负载平衡的。负载均衡器的成本很高。为避免该开销,请按照亚马逊文档所述将环境类型设置为“单个实例”。您还可以使用 CLI 和以下命令来创建单实例环境:
1 eb create -s
Summary
这是通向 AWS 的最简单方法之一,但还有更多内容要讲,例如如何将 Elastic Beanstalk 集成到任何 CI/CD 工具中,如何使用 Elastic Beanstalk Maven 插件而不是 CLI 等等。 blog post详细介绍了这些主题。
Boxfuse和AmazonWebServices
Boxfuse通过将您的 Spring Boot 可执行 jar 或 war 变成一个最小的 VM 映像来工作,该映像可以在 VirtualBox 或 AWS 上不变地部署。 Boxfuse 与 Spring Boot 进行了深度集成,并使用 Spring Boot 配置文件中的信息自动配置端口和运行状况检查 URL。 Boxfuse 在生成的图像以及它提供的所有资源(实例,安全组,弹性负载均衡器等)中均利用此信息。
创建Boxfuse account,将其连接到您的 AWS 账户,安装最新版本的 Boxfuse Client 并确保该应用程序已由 Maven 或 Gradle 构建(通过使用mvn clean package
)后,就可以部署 Spring 使用与以下类似的命令将应用程序引导到 AWS:
1 | $ boxfuse run myapp-1.0.jar -env=prod |
有关更多选项,请参见boxfuse 运行文档。如果当前目录中存在boxfuse.conf文件,则将其考虑。
Tip
默认情况下,Boxfuse 在启动时会激活名为
boxfuse
的 Spring 配置文件。如果您的可执行 jar 或 war 包含application-boxfuse.properties文件,则 Boxfuse 的配置将基于其包含的属性。
此时,boxfuse
为您的应用程序创建一个映像,上传该映像,并在 AWS 上配置和启动必要的资源,其输出类似于以下示例:
1 | Fusing Image for myapp-1.0.jar ... |
您的应用程序现在应该已启动并在 AWS 上运行。
请参阅在 EC2 上部署 Spring Boot 应用和Boxfuse Spring Boot 集成的文档上的博客文章,以开始使用 Maven 构建来运行该应用程序。
GoogleCloud
Google Cloud 有多个选项可用于启动 Spring Boot 应用程序。最容易上手的可能是 App Engine,但您也可以找到在 Container Engine 的容器中或 Compute Engine 的虚拟机上运行 Spring Boot 的方法。
要在 App Engine 中运行,您可以先在用户界面中创建一个项目,该项目将为您设置一个唯一的标识符,并还设置 HTTP 路由。将 Java 应用程序添加到项目中,并将其保留为空,然后使用Google Cloud SDK从命令行或 CI 构建将 Spring Boot 应用程序推入该插槽。
App Engine Standard 要求您使用 WAR 包装。按照these steps的要求将 App Engine Standard 应用程序部署到 Google Cloud。
另外,App Engine Flex 要求您创建一个app.yaml
文件来描述您的应用程序所需的资源。通常,您将此文件放在src/main/appengine
中,它应类似于以下文件:
1 | service: default |
您可以通过将项目 ID 添加到构建配置中来部署应用程序(例如,使用 Maven 插件),如以下示例所示:
1 | <plugin> |
然后使用mvn appengine:deploy
进行部署(如果您需要先进行身份验证,则构建将失败)。
安装SpringBoot应用程序
除了使用java -jar
运行 Spring Boot 应用程序外,还可以为 Unix 系统制作完全可执行的应用程序。完全可执行的 jar 可以像其他任何可执行二进制文件一样执行,也可以是在 init.d 或 systemd 中注册。这使得在普通生产环境中安装和 Management Spring Boot 应用程序变得非常容易。
Warning
完全可执行的 jar 通过在文件的开头嵌入一个额外的脚本来工作。当前,某些工具不接受此格式,因此您可能无法始终使用此技术。例如,
jar -xf
可能会默默地提取无法完全执行的 jar 或 war。建议仅在打算直接执行 jar 或 war 时才使它们完全可执行,而不是使用java -jar
运行它或将其部署到 servlet 容器中。
要使用 Maven 创建一个“完全可执行”的 jar,请使用以下插件配置:
1 | <plugin> |
以下示例显示了等效的 Gradle 配置:
1 | bootJar { |
然后,您可以通过键入./my-application.jar
(其中my-application
是工件的名称)来运行您的应用程序。包含 jar 的目录用作应用程序的工作目录。
支持的os
默认脚本支持大多数 Linux 发行版,并已在 CentOS 和 Ubuntu 上进行了测试。其他平台,例如 OS X 和 FreeBSD,则需要使用自定义的embeddedLaunchScript
。
Unix/Linux服务
使用init.d
或systemd
可以轻松地将 Spring Boot 应用程序作为 Unix/Linux 服务启动。
作为init.d服务安装(系统 V)
如果您将 Spring Boot 的 Maven 或 Gradle 插件配置为生成完全可执行的 jar,而不使用自定义embeddedLaunchScript
,则您的应用程序可以用作init.d
服务。为此,请将 jar 链接到init.d
以支持标准start
,stop
,restart
和status
命令。
该脚本支持以下功能:
- 以拥有 jar 文件的用户身份启动服务
- 使用
/var/run/<appname>/<appname>.pid
跟踪应用程序的 PID - 将控制台日志写入
/var/log/<appname>.log
假设您已在/var/myapp
中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序安装为init.d
服务,请创建一个符号链接,如下所示:
1 | $ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp |
安装后,您可以按照通常的方式启动和停止服务。例如,在基于 Debian 的系统上,可以使用以下命令启动它:
1 | $ service myapp start |
Tip
如果您的应用程序无法启动,请检查写入
/var/log/<appname>.log
的日志文件是否有错误。
您还可以使用标准 os 工具将应用程序标记为自动启动。例如,在 Debian 上,您可以使用以下命令:
1 | $ 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 文件的所有者,如以下示例所示:
1 | $ chown bootapp:bootapp your-app.jar |
在这种情况下,默认的可执行脚本以bootapp
用户身份运行该应用程序。
Tip
为了减少应用程序的用户帐户遭到破坏的机会,应考虑阻止它使用登录 Shell 程序。例如,您可以将帐户的 Shell 设置为
/usr/sbin/nologin
。
您还应该采取步骤来防止修改应用程序的 jar 文件。首先,配置其权限,使其不能被写入,只能由其所有者读取或执行,如以下示例所示:
1 | $ chmod 500 your-app.jar |
其次,如果您的应用程序或运行该应用程序的帐户受到威胁,您还应采取措施限制损害。如果攻击者确实获得了访问权限,则他们可以使 jar 文件可写并更改其内容。防止这种情况发生的一种方法是使用chattr
使其不变,如以下示例所示:
1 | $ sudo chattr +i your-app.jar |
这将阻止任何用户(包括 root 用户)修改 jar。
如果使用 root 来控制应用程序的服务,并且您使用.conf 文件自定义其启动,则 root 用户将读取并评估.conf
文件。应该相应地对其进行保护。使用chmod
,以便只有所有者可以读取文件,并使用chown
将 root 成为所有者,如以下示例所示:
1 | chmod 400 your-app.conf |
作为系统服务安装
systemd
是 System V init 系统的后继产品,现已被许多现代 Linux 发行版使用。尽管您可以 continue 将_脚本与systemd
一起使用,但是也可以通过使用systemd
‘service’脚本来启动 Spring Boot 应用程序。
假设您已在/var/myapp
中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序安装为systemd
服务,请创建名为myapp.service
的脚本并将其放置在/etc/systemd/system
目录中。以下脚本提供了一个示例:
1 | [Unit] |
Tip
切记为您的应用程序更改
Description
,User
和ExecStart
字段。Note
ExecStart
字段未声明脚本操作命令,这意味着默认情况下使用run
命令。
请注意,与作为init.d
服务运行时不同,运行应用程序,PID 文件和控制台日志文件的用户由systemd
本身 Management,因此必须通过在“服务”脚本中使用适当的字段进行配置。有关更多详细信息,请咨询服务单元配置手册页。
要将应用程序标记为在系统启动时自动启动,请使用以下命令:
1 | $ systemctl enable myapp.service |
有关更多详细信息,请参考man systemctl
。
自定义启动脚本
由 Maven 或 Gradle 插件编写的默认嵌入式启动脚本可以通过多种方式进行自定义。对于大多数人来说,使用默认脚本和一些自定义设置通常就足够了。如果发现无法自定义所需的内容,请使用embeddedLaunchScript
选项完全编写自己的文件。
编写后自定义启动脚本
在将启动脚本写入 jar 文件时,自定义启动脚本的元素通常很有意义。例如,init.d 脚本可以提供“描述”。由于您已经预先了解了描述(并且无需更改),因此在生成 jar 时也可以提供它。
要自定义书面元素,请使用 Spring Boot Maven 插件的embeddedLaunchScriptProperties
选项或Spring Boot Gradle 插件的 launchScript 的 properties 属性。
默认脚本支持以下属性替换:
Name | Description | Gradle default | Maven default |
---|---|---|---|
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 文件名在PID_FOLDER 中的默认值。仅对init.d 服务有效 |
||
useStartStopDaemon |
start-stop-daemon 命令(如果可用)是否应用于控制过程 |
true |
true |
stopWaitTime |
STOP_WAIT_TIME 的默认值,以秒为单位。仅对init.d 服务有效 |
60 | 60 |
运行时自定义脚本
对于在编写 jar 之后需要自定义脚本的项目,可以使用环境变量或config file。
默认脚本支持以下环境属性:
Variable | Description | |||
---|---|---|---|---|
MODE |
操作的“模式”。默认值取决于 jar 的构建方式,但通常为auto (这意味着它会通过检查目录init.d 中的符号链接来尝试猜测它是否为初始化脚本)。您可以将其显式设置为service ,以便`stop |
start | status | restart命令起作用,或者如果要在前台运行脚本,则可以将其设置为 run`。 |
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 |
默认情况下,通过使用PATH 发现java 可执行文件的位置,但是如果$JAVA_HOME/bin/java 处有可执行文件,则可以显式设置它。 |
|||
JAVA_OPTS |
启动 JVM 时传递给 JVM 的选项。 | |||
JARFILE |
jar 文件的显式位置,以防脚本用于启动实际上未嵌入的 jar。 | |||
DEBUG |
如果不为空,请在 shell 进程中设置-x 标志,从而易于查看脚本中的逻辑。 |
|||
STOP_WAIT_TIME |
停止应用程序之前要强制关闭的 await 时间(以秒为单位)(默认为60 )。 |
Note
PID_FOLDER
,LOG_FOLDER
和LOG_FILENAME
变量仅对init.d
服务有效。对于systemd
,使用’service’脚本进行等效的自定义。有关更多详细信息,请参见服务单元配置手册页。
除JARFILE
和APP_NAME
以外,可以使用.conf
文件配置上一节中列出的设置。该文件应位于 jar 文件的旁边,并且具有相同的名称,但后缀为.conf
而不是.jar
。例如,名为/var/myapp/myapp.jar
的 jar 使用名为/var/myapp/myapp.conf
的配置文件,如以下示例所示:
myapp.conf.
1 | JAVA_OPTS=-Xmx1024M |
Tip
如果您不喜欢将配置文件放在 jar 文件旁边,则可以设置
CONF_FOLDER
环境变量以自定义配置文件的位置。
要了解有关适当保护此文件的信息,请参阅确保 init.d 服务的准则。
MicrosoftWindows服务
可以使用winsw将 Spring Boot 应用程序作为 Windows 服务启动。
(单独维护的 samples)分步说明了如何为 Spring Boot 应用程序创建 Windows 服务。
接下来要读什么
请访问Cloud Foundry,Heroku,OpenShift和Boxfuse网站,以获取有关 PaaS 可以提供的各种功能的更多信息。这些只是最受欢迎的 Java PaaS 提供程序中的四个。由于 Spring Boot 非常适合基于云的部署,因此您也可以自由考虑其他提供商。
下一节将 continue 介绍 Spring Boot CLI,或者您可以跳至阅读有关 构建工具插件 的内容。