部署到雲端
Spring Boot 的可執行 Jar 包已為大多數流行的雲 PaaS(平臺即服務)提供商準備就緒。這些提供商通常要求您“自帶容器”。它們管理應用程式程序(不 specifically 是 Java 應用程式),因此它們需要一箇中間層,將 您的 應用程式適配到 雲端 對執行程序的定義。
Heroku 和 Cloud Foundry 這兩個流行的雲提供商採用“構建包”方法。構建包將您部署的程式碼封裝在啟動應用程式所需的一切中。它可能是一個 JDK 和一個對 java 的呼叫、一個嵌入式 Web 伺服器或一個功能齊全的應用程式伺服器。構建包是可插拔的,但理想情況下,您應該儘可能少地對其進行自定義。這減少了不受您控制的功能的佔用空間。它最大程度地減少了開發和生產環境之間的差異。
理想情況下,您的應用程式,例如 Spring Boot 可執行 Jar 包,應包含執行所需的一切。
在本節中,我們探討如何將“入門”部分中開發的應用程式部署到雲端並執行。
Cloud Foundry
如果未指定其他構建包,Cloud Foundry 會提供預設構建包。Cloud Foundry Java 構建包對 Spring 應用程式(包括 Spring Boot)提供出色的支援。您可以部署獨立的 Java 可執行 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 的多語言(任何語言和平臺都可以作為構建包支援)特性。程序範圍的環境變數與語言無關。
環境變數並非總是最簡單的 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 Probes 匯出它。
Kubernetes 容器生命週期
當 Kubernetes 刪除應用程式例項時,關閉過程同時涉及多個子系統:關閉鉤子、登出服務、從負載均衡器中移除例項……由於此關閉處理是並行發生的(並且由於分散式系統的性質),因此存在一個時間視窗,在此期間流量可以路由到也已開始其關閉處理的 Pod。
您可以在 preStop 處理器中配置一個休眠執行,以避免請求路由到已開始關閉的 Pod。此休眠時間應足夠長,以停止將新請求路由到 Pod,並且其持續時間會因部署而異。
如果您使用的是 Kubernetes 1.32 或更高版本,preStop 處理器可以透過 Pod 配置檔案中的 PodSpec 配置,如下所示:
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"]
| 為此,容器需要有一個 shell。 |
pre-stop 鉤子完成後,SIGTERM 將傳送到容器,並開始正常關閉,允許任何剩餘的正在進行的請求完成。
當 Kubernetes 向 Pod 傳送 SIGTERM 訊號時,它會等待一個稱為終止寬限期(預設為 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 上執行。有關更多詳細資訊,請參閱 在 Heroku 上部署 Spring Boot 應用程式。
OpenShift
OpenShift 提供了許多描述如何部署 Spring Boot 應用程式的資源,包括:
Amazon Web Services (AWS)
Amazon Web Services 提供了幾種適用於執行基於 Spring Boot 應用程式的選項,無論是作為容器、傳統 Web 應用程式 (war) 還是自包含的可執行 jar 檔案。流行的選項有:
-
Amazon Elastic Container Service (ECS)
-
AWS Elastic Beanstalk
Amazon Elastic Container Service (ECS)
官方的 Amazon ECS 開發者指南 提供了平臺功能的全面概述,幷包含 入門指南,其中詳細介紹了啟動和執行容器所需的步驟。
| Spring Boot 應用程式可以使用容器映象中描述的技術打包到 Docker 容器中。 |
除了開發人員指南,AWS 還提供了使用 AWS Fargate 在 Amazon ECS 上部署容器化 Java 服務的專題指南。
Spring Boot 透過檢查環境變數中的 AWS_EXECUTION_ENV 變數來自動檢測 AWS ECS 部署環境。您可以使用 spring.main.cloud-platform 配置屬性覆蓋此檢測。 |
AWS Elastic 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 檔案轉換為一個最小的 VM 映象,該映象可以在 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 App Service。
Google Cloud
Google Cloud 提供了幾種可用於啟動 Spring Boot 應用程式的選項。最容易上手的使用可能是 App Engine,但您也可以找到使用 Container Engine 在容器中或使用 Compute Engine 在虛擬機器上執行 Spring Boot 的方法。
要將您的第一個應用程式部署到 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 部署(您需要先進行身份驗證,否則構建將失敗)。