|
此版本仍在开发中,尚未视为稳定版。如需最新稳定版本,请使用 Spring Boot 4.0.4! |
部署到云端
Spring Boot 的可执行 JAR 文件已为大多数流行的云 PaaS(平台即服务)提供商做好了准备。 这些提供商通常要求你“自带容器”。 它们管理的是应用程序进程(并非特指 Java 应用程序),因此需要一个中间层,将你的应用程序适配到云平台对运行中进程的理解。
两个流行的云提供商,Heroku 和 Cloud Foundry,采用了“构建包(buildpack)”方法。
构建包将您的部署代码包裹在启动应用程序所需的一切之中。
它可能是一个 JDK 和对 java 的调用、一个嵌入式 Web 服务器,或是一个功能齐全的应用程序服务器。
构建包是可插拔的,但理想情况下,您应该能够尽可能少地对其进行自定义。
这减少了不受您控制的功能的范围。
它最大限度地减少了开发环境和生产环境之间的差异。
理想情况下,您的应用程序(如同 Spring Boot 可执行 jar 文件一样)应将运行所需的所有内容都打包在自身内部。
在本节中,我们将了解如何将在“入门”部分中开发的应用程序部署到云端并使其正常运行。
安全注意事项
仅当应用程序从受信任的 HTTP 代理接收流量,且只能通过受信任的网络直接访问时,才应启用对转发标头的支持。
在云平台上运行时,转发标头会自动启用。
这是基于平台将确保各个应用程序实例只能通过受信任的网络直接访问的假设。
如果您的特定平台不符合这种情况,请将spring.forward-headers-strategy设置为none。
Cloud Foundry
Cloud Foundry 提供了默认的 buildpack,当未指定其他 buildpack 时会自动启用。
Cloud Foundry 的Java buildpack对 Spring 应用(包括 Spring Boot)提供了出色的支持。
您可以部署独立的可执行 JAR 应用程序,也可以部署传统的 .war 打包应用程序。
一旦您构建了应用程序(例如,使用 mvn clean package)并安装了 cf 命令行工具,即可使用 cf push 命令部署您的应用程序,请将路径替换为您编译好的 .jar 的路径。
在推送应用程序之前,请务必先使用 cf 命令行客户端登录。
以下行展示了如何使用 cf push 命令部署应用程序:
$ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar
在前面的示例中,我们将 acloudyspringtime 替换为您为 cf 指定的应用程序名称所对应的任意值。 |
查看更多选项,请参阅 cf push 文档。
如果同一目录下存在 Cloud Foundry manifest.yml 文件,则会被考虑在内。
此时,cf 开始上传您的应用程序,并生成类似于以下示例的输出:
Uploading acloudyspringtime... OK
Preparing to start acloudyspringtime... OK
-----> Downloaded app package (8.9M)
-----> Java Buildpack Version: v3.12 (offline) | https://github.com/cloudfoundry/java-buildpack.git#6f25b7e
-----> Downloading Open Jdk JRE
Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.6s)
-----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (found in cache)
Memory Settings: -Xss349K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xms681574K -XX:MetaspaceSize=104857K
-----> Downloading Container Certificate Trust Store 1.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-certificate-trust-store/container-certificate-trust-store-1.0.0_RELEASE.jar (found in cache)
Adding certificates to .java-buildpack/container_certificate_trust_store/truststore.jks (0.6s)
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)
Checking status of app 'acloudyspringtime'...
0 of 1 instances running (1 starting)
...
0 of 1 instances running (1 starting)
...
0 of 1 instances running (1 starting)
...
1 of 1 instances running (1 running)
App started
恭喜!应用程序现已上线运行!
一旦您的应用程序上线后,您可以使用 cf apps 命令来验证已部署应用程序的状态,如下例所示:
$ cf apps
Getting applications in ...
OK
name requested state instances memory disk urls
...
acloudyspringtime started 1/1 512M 1G acloudyspringtime.cfapps.io
...
一旦 Cloud Foundry 确认您的应用程序已成功部署,您就应该能够在所提供的 URI 处访问该应用程序。
在前面的示例中,您可以访问 https://acloudyspringtime.cfapps.io/。
绑定到服务
默认情况下,有关正在运行的应用程序的元数据以及服务连接信息会以环境变量的形式(例如:$VCAP_SERVICES)暴露给应用程序。
这一架构决策源于 Cloud Foundry 的多语言特性(任何语言和平台均可作为 buildpack 被支持)。
进程作用域的环境变量与编程语言无关。
环境变量并不总能提供最易用的 API,因此 Spring Boot 会自动提取它们并将数据扁平化为可通过 Spring 的 Environment 抽象访问的属性,如下例所示:
-
Java
-
Kotlin
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class MyBean implements EnvironmentAware {
private String instanceId;
@Override
public void setEnvironment(Environment environment) {
this.instanceId = environment.getProperty("vcap.application.instance_id");
}
// ...
}
import org.springframework.context.EnvironmentAware
import org.springframework.core.env.Environment
import org.springframework.stereotype.Component
@Component
class MyBean : EnvironmentAware {
private var instanceId: String? = null
override fun setEnvironment(environment: Environment) {
instanceId = environment.getProperty("vcap.application.instance_id")
}
// ...
}
所有 Cloud Foundry 属性均以 vcap 为前缀。
您可以使用 vcap 属性来访问应用信息(例如应用的公共 URL)和服务信息(例如数据库凭证)。
请参阅 CloudFoundryVcapEnvironmentPostProcessor API 文档以获取完整详情。
| Java CFEnv 项目更适合用于配置 DataSource 等任务。 |
Kubernetes
Spring Boot 通过检查环境中是否存在 "*_SERVICE_HOST" 和 "*_SERVICE_PORT" 变量,自动检测 Kubernetes 部署环境。
您可以通过 spring.main.cloud-platform 配置属性来覆盖此检测行为。
Spring Boot 帮助您管理应用程序的状态,并通过使用 Actuator 的 HTTP Kubernetes 探针将其导出。
Kubernetes 容器生命周期
当 Kubernetes 删除一个应用程序实例时,关闭过程会同时涉及多个子系统:关闭钩子(shutdown hooks)、注销服务、将实例从负载均衡器中移除…… 由于这种关闭处理是并行进行的(并且由于分布式系统的特性),在此期间存在一个时间窗口,流量可能会被路由到一个已经开始执行关闭处理的 Pod。
你可以在 preStop 处理程序中配置一段休眠时间,以避免请求被路由到已经开始关闭的 Pod。 这段休眠时间应足够长,确保新请求不再被路由到该 Pod,其具体时长会因部署环境不同而有所差异。 该延迟时间至少应等于处理一个正在执行中的请求所需的最长时间。 你不应仅依赖 Spring Boot 的优雅关闭期,因为在应用程序关闭期间,平台将无法获取任何存活状态(liveness)数据。
如果你使用的是 Kubernetes 1.32 或更高版本,可以通过在 Pod 的配置文件中使用 PodSpec 来配置 preStop 处理程序,如下所示:
spec:
containers:
- name: "example-container"
image: "example-image"
lifecycle:
preStop:
sleep:
seconds: 10
如果你尚未使用 Kubernetes 1.32,可以使用 exec 命令来调用 sleep。
spec:
containers:
- name: "example-container"
image: "example-image"
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]
| 容器需要有一个外壳才能使此功能正常工作。 |
一旦预停止钩子(pre-stop hook)执行完成,SIGTERM 信号将被发送到容器,并开始优雅关闭,以允许所有仍在处理中的请求完成。
当 Kubernetes 向 Pod 发送 SIGTERM 信号时,它会等待一段指定的时间,称为终止宽限期(termination grace period),默认为 30 秒。
如果容器在宽限期结束后仍在运行,它们将收到 SIGKILL 信号并被强制移除。
如果你的 Pod 关闭时间超过 30 秒(例如因为你增加了 spring.lifecycle.timeout-per-shutdown-phase 的值),请务必通过在 Pod 的 YAML 文件中设置 terminationGracePeriodSeconds 选项来增加终止宽限期。 |
Heroku
Heroku 是另一个流行的 PaaS 平台。
要自定义 Heroku 的构建过程,你需要提供一个 Procfile 文件,其中包含部署应用程序所需的命令。
Heroku 会为 Java 应用程序分配一个 port(端口),并确保外部 URI 的路由能够正常工作。
您必须配置您的应用程序以监听正确的端口。
以下示例展示了我们入门级 REST 应用程序的 Procfile:
web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar
Spring Boot 使 -D 个参数可作为属性从 Spring Environment 实例中访问。
server.port 配置属性被传递给嵌入式的 Tomcat 或 Jetty 实例,后者在启动时使用该端口。
$PORT 环境变量由 Heroku PaaS 分配给我们。
这应该包含了您所需的一切。
Heroku 部署最常见的工作流程是将代码通过 git push 推送到生产环境,如下例所示:
$ git push heroku main
这将产生以下结果:
Initializing repository, done.
Counting objects: 95, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (78/78), done.
Writing objects: 100% (95/95), 8.66 MiB | 606.00 KiB/s, done.
Total 95 (delta 31), reused 0 (delta 0)
-----> Java app detected
-----> Installing OpenJDK... done
-----> Installing Maven... done
-----> Installing settings.xml... done
-----> Executing: mvn -B -DskipTests=true clean install
[INFO] Scanning for projects...
Downloading: https://repo.spring.io/...
Downloaded: https://repo.spring.io/... (818 B at 1.8 KB/sec)
....
Downloaded: https://s3pository.heroku.com/jvm/... (152 KB at 595.3 KB/sec)
[INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/...
[INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 59.358s
[INFO] Finished at: Fri Mar 07 07:28:25 UTC 2014
[INFO] Final Memory: 20M/493M
[INFO] ------------------------------------------------------------------------
-----> Discovering process types
Procfile declares types -> web
-----> Compressing... done, 70.4MB
-----> Launching... done, v6
https://agile-sierra-1405.herokuapp.com/ deployed to Heroku
To [email protected]:agile-sierra-1405.git
* [new branch] main -> main
您的应用程序现在应该已在 Heroku 上成功运行。 更多详情,请参阅 将 Spring Boot 应用程序部署到 Heroku。
OpenShift
OpenShift 提供了大量资源,介绍如何部署 Spring Boot 应用程序,包括:
亚马逊云服务 (AWS)
亚马逊云服务(Amazon Web Services)提供了多种适用于运行基于 Spring Boot 应用程序的选项,这些应用程序可以作为容器、传统的 Web 应用程序(war 包)或独立的可执行 jar 文件运行。 常见的选项包括:
-
亚马逊弹性容器服务(ECS)
-
AWS 弹性Beanstalk
亚马逊弹性容器服务(ECS)
官方的Amazon ECS 开发者指南全面概述了该平台的功能,并包含入门指南,逐步指导您完成让容器启动并运行所需的各项步骤。
| Spring Boot 应用程序可以使用容器镜像中描述的技术打包到 Docker 容器中。 |
除了开发者指南外,AWS 还提供了一份专题指南,用于指导如何使用 AWS Fargate 在 Amazon ECS 上部署容器化的 Java 服务。
Spring Boot 通过检查环境中是否存在 AWS_EXECUTION_ENV 变量来自动检测 AWS ECS 部署环境。
您可以使用 spring.main.cloud-platform 配置属性来覆盖此自动检测。 |
AWS 弹性Beanstalk
如官方Elastic Beanstalk Java 指南中所述,部署 Java 应用程序主要有两种选项。 您可以使用“Tomcat 平台”或“Java SE 平台”。
使用 Tomcat 平台
此选项适用于生成 war 文件的 Spring Boot 项目。 请遵循官方指南和Tomcat 上的 Java 教程。
| 在传统部署中描述了如何为 Spring Boot 应用程序创建可部署的 WAR 文件。 |
CloudCaptain 和亚马逊云服务(Amazon Web Services)
CloudCaptain 的工作原理是将您的 Spring Boot 可执行 JAR 或 WAR 文件转换为一个极简的虚拟机镜像,该镜像无需任何更改即可直接部署到 VirtualBox 或 AWS 上。 CloudCaptain 与 Spring Boot 深度集成,并利用您 Spring Boot 配置文件中的信息自动配置端口和健康检查 URL。 CloudCaptain 在其生成的镜像以及所配置的所有资源(如实例、安全组、弹性负载均衡器等)中都会利用这些信息。
一旦您创建了CloudCaptain 账户,将其连接到您的 AWS 账户,安装了最新版本的 CloudCaptain 客户端,并确保应用程序已通过 Maven 或 Gradle 构建完成(例如,使用 mvn clean package),您就可以使用类似以下的命令将您的 Spring Boot 应用程序部署到 AWS:
$ boxfuse run myapp-1.0.jar -env=prod
查看更多选项,请参阅 boxfuse run 文档。
如果当前目录中存在 boxfuse.conf 文件,则会被考虑。
默认情况下,CloudCaptain 在启动时会激活一个名为 boxfuse 的 Spring 配置文件。
如果您的可执行 jar 或 war 包中包含 application-boxfuse.properties 文件,CloudCaptain 将基于该文件中包含的属性进行配置。 |
此时,CloudCaptain 会为您的应用程序创建一个镜像,将其上传,并在 AWS 上配置和启动所需的资源,从而产生类似于以下示例的输出:
Fusing Image for myapp-1.0.jar ...
Image fused in 00:06.838s (53937 K) -> axelfontaine/myapp:1.0
Creating axelfontaine/myapp ...
Pushing axelfontaine/myapp:1.0 ...
Verifying axelfontaine/myapp:1.0 ...
Creating Elastic IP ...
Mapping myapp-axelfontaine.boxfuse.io to 52.28.233.167 ...
Waiting for AWS to create an AMI for axelfontaine/myapp:1.0 in eu-central-1 (this may take up to 50 seconds) ...
AMI created in 00:23.557s -> ami-d23f38cf
Creating security group boxfuse-sg_axelfontaine/myapp:1.0 ...
Launching t2.micro instance of axelfontaine/myapp:1.0 (ami-d23f38cf) in eu-central-1 ...
Instance launched in 00:30.306s -> i-92ef9f53
Waiting for AWS to boot Instance i-92ef9f53 and Payload to start at https://52.28.235.61/ ...
Payload started in 00:29.266s -> https://52.28.235.61/
Remapping Elastic IP 52.28.233.167 to i-92ef9f53 ...
Waiting 15s for AWS to complete Elastic IP Zero Downtime transition ...
Deployment completed successfully. axelfontaine/myapp:1.0 is up and running at https://myapp-axelfontaine.boxfuse.io/
您的应用程序现在应该已在 AWS 上成功运行。
请参阅有关在 EC2 上部署 Spring Boot 应用的博客文章,以及CloudCaptain Spring Boot 集成的文档,以开始使用 Maven 构建来运行该应用。
Azure
本入门指南将引导您将Spring Boot应用程序部署到Azure Spring Cloud或Azure 应用服务。
谷歌云
Google Cloud 提供了多种可用于部署 Spring Boot 应用程序的选项。 最简单易用的可能是 App Engine,但你也可以通过 Container Engine 在容器中运行 Spring Boot,或在 Compute Engine 的虚拟机上运行。
要将您的第一个应用部署到 App Engine 标准环境,请按照本教程操作。
或者,App Engine Flex 要求您创建一个 app.yaml 文件来描述您的应用所需的资源。
通常,您将此文件放在 src/main/appengine 目录下,其内容应类似于以下文件:
service: "default"
runtime: "java17"
env: "flex"
handlers:
- url: "/.*"
script: "this field is required, but ignored"
manual_scaling:
instances: 1
health_check:
enable_health_check: false
env_variables:
ENCRYPT_KEY: "your_encryption_key_here"
您可以通过将项目 ID 添加到构建配置中来部署该应用(例如,使用 Maven 插件),如下例所示:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>2.4.4</version>
<configuration>
<project>myproject</project>
</configuration>
</plugin>
然后使用 mvn appengine:deploy 进行部署(您需要先进行身份验证,否则构建会失败)。