部署到雲端
Spring Boot 的可執行 jar 檔已為大多數流行的雲端 PaaS(平台即服務)供應商做好準備。這些供應商傾向於要求您「自備容器」。他們管理應用程式程序(而非特定於 Java 的應用程式),因此他們需要一個中介層來調整您的應用程式以適應雲端對執行程序的概念。
兩個受歡迎的雲端供應商 Heroku 和 Cloud Foundry 採用「建置包 (buildpack)」方法。建置包將您部署的程式碼包裝在啟動您的應用程式所需的任何內容中。它可能是一個 JDK 和一個 java
呼叫、一個嵌入式 Web 伺服器或一個功能完善的應用程式伺服器。建置包是可插拔的,但理想情況下,您應該能夠盡可能少地對其進行自訂。這減少了不受您控制的功能的佔用空間。它最大限度地減少了開發環境和生產環境之間的差異。
理想情況下,您的應用程式(如 Spring Boot 可執行 jar 檔)已將執行所需的一切都封裝在其中。
在本節中,我們將了解如何讓在「入門指南」章節中開發的應用程式在雲端中啟動並執行。
Cloud Foundry
如果沒有指定其他建置包,Cloud Foundry 會提供預設建置包。Cloud Foundry Java 建置包對 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 的多語言(任何語言和平台都可以作為建置包支援)特性。程序範圍的環境變數與語言無關。
環境變數並不總是能提供最簡單的 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 協助您管理應用程式的狀態,並使用 HTTP Kubernetes 探針 (使用 Actuator) 匯出它。
Kubernetes 容器生命週期
當 Kubernetes 刪除應用程式實例時,關閉程序會同時涉及多個子系統:關閉掛鉤、取消註冊服務、從負載平衡器中移除實例… 由於此關閉處理是並行發生的(並且由於分散式系統的性質),因此在流量可以路由到也已開始其關閉處理的 Pod 的期間存在一個窗口。
您可以在 preStop 處理程序中配置睡眠執行,以避免請求路由到已開始關閉的 Pod。此睡眠時間應足夠長,以停止將新請求路由到 Pod,並且其持續時間會因部署而異。可以使用 Pod 組態檔案中的 PodSpec 配置 preStop 處理程序,如下所示
spec:
containers:
- name: "example-container"
image: "example-image"
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]
一旦 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 或 Undertow 實例,然後它們在啟動時使用該端口。$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 應用程式,包括
Amazon Web Services (AWS)
Amazon Web Services 提供了多種安裝基於 Spring Boot 的應用程式的方式,可以作為傳統 Web 應用程式 (war) 或具有嵌入式 Web 伺服器的可執行 jar 檔案。選項包括
-
AWS Elastic Beanstalk
-
AWS Code Deploy
-
AWS OPS Works
-
AWS Cloud Formation
-
AWS Container Registry
每個都有不同的功能和定價模型。在本文檔中,我們描述了使用 AWS Elastic Beanstalk 的方法。
AWS Elastic Beanstalk
如官方 Elastic Beanstalk Java 指南 中所述,部署 Java 應用程式主要有兩個選項。您可以使用「Tomcat 平台」或「Java SE 平台」。
使用 Java SE 平台
此選項適用於產生 jar 檔案並執行嵌入式 Web 容器的 Spring Boot 專案。Elastic Beanstalk 環境在端口 80 上執行 nginx 實例,以代理在端口 5000 上運行的實際應用程式。要配置它,請將以下行添加到您的 application.properties
檔案
-
Properties
-
YAML
server.port=5000
server:
port: 5000
上傳二進制檔案而不是原始碼
預設情況下,Elastic Beanstalk 上傳原始碼並在 AWS 中編譯它們。但是,最好上傳二進制檔案。為此,請將類似於以下幾行的內容添加到您的
|
透過設定環境類型來降低成本
預設情況下,Elastic Beanstalk 環境是負載平衡的。負載平衡器具有相當大的成本。為了避免這種成本,請將環境類型設定為「單一實例」,如 Amazon 文件 中所述。您也可以使用 CLI 和以下命令建立單一實例環境
|
總結
這是進入 AWS 最簡單的方法之一,但還有更多內容需要涵蓋,例如如何將 Elastic Beanstalk 整合到任何 CI/CD 工具、使用 Elastic Beanstalk Maven 外掛程式而不是 CLI 等等。有一篇部落格文章更詳細地介紹了這些主題。
CloudCaptain 和 Amazon Web Services
CloudCaptain 的工作原理是將您的 Spring Boot 可執行 jar 檔或 war 檔轉換為最小的 VM 映像,該映像可以不經更改地部署在 VirtualBox 或 AWS 上。CloudCaptain 針對 Spring Boot 進行了深度整合,並使用來自您的 Spring Boot 組態檔案的資訊來自動配置端口和健康檢查 URL。CloudCaptain 將此資訊用於它產生的映像以及它配置的所有資源(實例、安全群組、彈性負載平衡器等等)。
一旦您建立了一個 CloudCaptain 帳戶,將其連接到您的 AWS 帳戶,安裝了最新版本的 CloudCaptain Client,並確保應用程式已由 Maven 或 Gradle 建置(例如,使用 mvn clean package
),您可以使用類似於以下命令的命令將您的 Spring Boot 應用程式部署到 AWS
$ boxfuse run myapp-1.0.jar -env=prod
有關更多選項,請參閱 boxfuse run
文件。如果目前目錄中存在 boxfuse.conf
檔案,則會將其納入考量。
預設情況下,CloudCaptain 在啟動時啟用名為 boxfuse 的 Spring Profile。如果您的可執行 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
部署(您需要先進行身份驗證,否則建置會失敗)。