1. 總覽
本系列程式碼研究室 (可自行調整進度的實作教學課程) 旨在協助 Google App Engine (標準) Java 開發人員完成一系列遷移作業,以便將應用程式改為新一代應用程式。按照這些步驟操作,您可以更新應用程式,讓應用程式更具可攜性,並決定將應用程式容器化,以便在 Cloud Run (Google Cloud 的容器代管服務,也是 App Engine 的姊妹服務) 和其他容器代管服務中執行。
本教學課程將說明如何將 App Engine 應用程式容器化,並透過 Dockerfile 部署至 Cloud Run 全代管服務。Dockerfile 是這項遷移作業最實用的部署方法,同時也提供最多的選項,可用於自訂建構程序。
除了說明從 App Engine 遷移至 Cloud Run 的必要步驟,您還會瞭解如何將 Java 8 App Engine 應用程式升級至 Java 17。
如果您想遷移的應用程式大量使用 App Engine 舊版套裝服務或其他 App Engine 特定功能,比起這個程式碼研究室,您或許更適合從「存取 Java 11/17 適用的 App Engine 套裝服務」指南開始著手。
在接下來的研究室中
- 使用 Cloud Shell
- 啟用 Cloud Run、Artifact Registry 和 Cloud Build API
- 使用 Docker、Dockerfile 和 Cloud Build 將應用程式容器化
- 將容器映像檔部署至 Cloud Run
軟硬體需求
- Google Cloud Platform 專案:已啟用 GCP 帳單帳戶,且已啟用 App Engine
- 具備常見 Linux 指令的實務知識
- 具備開發和部署 App Engine 應用程式的基本知識
- 您想遷移至 Java 17 並部署至 Cloud Run 的 Java 8 Servlet 應用程式 (這可以是 App Engine 上的應用程式,或僅為來源)
問卷調查
您要如何使用這個教學課程?
您覺得 Java 的使用體驗如何?
針對使用 Google Cloud 服務的經驗,您會給予什麼評價?
2. 背景
App Engine 和 Cloud Functions 等 PaaS 系統可為您的團隊和應用程式提供許多便利功能,例如讓系統管理員和開發人員專注於建構解決方案。有了無伺服器的平台,應用程式就能視需要自動調度資源、透過「用多少付多少」的計費方式將資源縮減至零,藉此控管成本,並使用各種常見的開發語言。
不過,容器的彈性也相當吸引人。容器能選擇任何語言、任何程式庫和二進位檔,帶來兩大優勢:無伺服器的便利性加上容器的靈活彈性。這就是 Google Cloud Run 的用途。
本程式碼研究室不涵蓋如何使用 Cloud Run 的內容,請參閱 Cloud Run 說明文件。我們的目標是讓您瞭解如何為 Cloud Run (或其他容器託管服務) 將 App Engine 應用程式容器化。繼續操作前,請先瞭解幾點重要事項,尤其是使用者體驗會有些許不同。
在本程式碼研究室中,您將瞭解如何建構及部署容器。您將瞭解如何使用 Dockerfile 將應用程式容器化、從 App Engine 設定遷移,以及 (選擇性) 定義 Cloud Build 的建構步驟。這項作業會移除特定 App Engine 專屬功能。如果不想遵循這個路徑,仍可改為升級至 Java 11/17 執行階段,並改為將應用程式保留在 App Engine 上。
3. 設定/事前作業
1. 設定專案
在這個教學課程中,您將針對全新專案使用 appengine-java-migration-samples 存放區的範例應用程式。確認專案具備有效的帳單帳戶。
如要將現有的 App Engine 應用程式移至 Cloud Run,可以改用該應用程式。
執行下列指令,為專案啟用必要的 API:
gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
2. 取得基準範例應用程式
在自己的電腦或 Cloud Shell 上複製範例應用程式,然後前往「baseline」資料夾。
這個範例是 Java 8 的 Servlet Datastore 應用程式,可在 App Engine 上部署。請按照 README 中的操作說明,瞭解如何為 App Engine 部署作業準備這個應用程式。
3. (選用) 部署基準應用程式
只有在您想確認應用程式在遷移至 Cloud Run 前可在 App Engine 上運作時,才需要執行下列步驟。
請參閱 README.md 中的步驟:
- 安裝/重新熟悉
gcloud
CLI - 使用
gcloud init
為專案初始化 gcloud CLI - 使用
gcloud app create
建立 App Engine 專案 - 將應用程式範例部署至 App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
- 確認應用程式在 App Engine 上執行,不會出現任何問題
4. 建立 Artifact Registry 存放區
將應用程式容器化後,您需要在某個地方推送及儲存圖片。如要在 Google Cloud 上解決這個問題,建議您使用 Artifact Registry。
使用 gcloud 建立名為 migration
的存放區,如下所示:
gcloud artifacts repositories create migration --repository-format=docker \
--description="Docker repository for the migrated app" \
--location="northamerica-northeast1"
請注意,這個存放區使用 docker
格式類型,但您可以使用多種存放區類型。
此時,您已擁有基準 App Engine 應用程式,且 Google Cloud 專案已準備好將其遷移至 Cloud Run。
4. 修改應用程式檔案
如果您的應用程式大量使用 App Engine 的舊版套裝組合服務、設定或其他 App Engine 專屬功能,建議您在升級至新執行階段時繼續存取這些服務。本程式碼研究室將示範遷移路徑,適用於已使用獨立服務的應用程式,或可透過其他方法重構以執行此作業。
1. 升級至 Java 17
如果您的應用程式使用 Java 8,建議您升級至較新的 LTS 候選版本 (例如 11 或 17),以便持續取得安全性更新,並使用新的語言功能。
請先更新 pom.xml
中的屬性,加入下列項目:
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
這會將專案版本設為 17,並告知編譯器外掛程式您想要存取 Java 17 語言功能,以及希望編譯的類別與 Java 17 JVM 相容。
2. 加入網路伺服器
在 App Engine 和 Cloud Run 之間移動時,請務必考慮這些差異。其中一個差異在於,App Engine 的 Java 8 執行階段會為其代管的應用程式提供及管理 Jetty 伺服器,但 Cloud Run 則不會。我們將使用 Spring Boot 向我們提供網路伺服器和 JDK 容器。
新增下列相依項目:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.6</version>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>2.6.6</version>
</dependency>
<!-- ... -->
</dependencies>
Spring Boot 會預設嵌入 Tomcat 伺服器,但這個範例會排除該構件,並使用 Jetty,盡量減少遷移後的預設行為差異。
3. Spring Boot 設定
雖然 Spring Boot 可在不修改的情況下重複使用 servlet,但仍需要進行一些設定,確保 servlet 可供偵測。
在 com.example.appengine
套件中建立下列 MigratedServletApplication.java
類別:
package com.example.appengine;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan
@SpringBootApplication
@EnableAutoConfiguration
public class MigratedServletApplication {
public static void main(String[] args) {
SpringApplication.run(MigratedServletApplication.class, args);
}
}
請注意,這包括 @ServletComponentScan
註解,該註解會在 目前套件中尋找任何 @WebServlets
,並讓這些元素如預期般可用。
4. 將應用程式封裝為 JAR
雖然您可以從戰爭開始將應用程式容器化,但將應用程式封裝為可執行的 JAR 會比較簡單。這項作業不需要太多設定,特別是對於使用 Maven 做為建構工具的專案而言,因為 JAR 封裝是預設行為。
移除 pom.xml
檔案中的 packaging
標記:
<packaging>war</packaging>
接著,請新增 spring-boot-maven-plugin
:
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.6</version>
</plugin>
<!-- ... -->
</plugins>
5. 捨棄 App Engine 設定、服務和依附元件
如程式碼研究室一開始所述,Cloud Run 和 App Engine 的設計宗旨就是提供不同的使用者體驗。App Engine 提供的某些功能 (例如 Cron 和 工作佇列 服務) 需要手動重新建立,我們會在後續模組中詳細說明。
範例應用程式不會使用舊版套裝服務,但如果應用程式使用舊版套裝服務,使用者可以參考下列指南:
- 從服務套件遷移,找出合適的獨立服務。
- 將 XML 設定檔遷移至 YAML,適用於想在 App Engine 上遷移至 Java 11/17 執行階段的使用者。
由於您將從現在開始部署至 Cloud Run,因此可以移除 appengine-maven-plugin
:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<!-- can be set w/ -DprojectId=myProjectId on command line -->
<projectId>${app.projectId}</projectId>
<!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
<version>GCLOUD_CONFIG</version>
</configuration>
</plugin>
5. 將應用程式容器化
此時,您可以告訴 Cloud Build 如何實際建構應用程式的容器。使用這種容器化方法時,不需要單獨的建構設定檔 (cloudbuild.yaml)。我們可以直接定義最少的 Dockerfile 做為起點:
來源為月蝕
ARG JAR_FILE=JAR_FILE_MUST_BE_SPECIFIED_AS_BUILD_ARG
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar","/app.jar"]
這個 Dockerfile 會在單一層級中將春季啟動服務的超級 JAR 版本套件打包。這是 Dockerfile 容器化最簡單的方法,但有許多缺點,特別是在比較依附元件相對穩定的情況下重複執行次數時。這類疑慮正是這種容器化方法被視為較先進的原因。不過,自行編寫 Dockerfile 的好處是,您可以完全控管基礎映像檔,並編寫精心分層的映像檔,享受其帶來的效能優勢。
2**. 執行建構程序**
您已告知 Cloud Build 所需的建構步驟,您現在可以一鍵部署,
執行下列指令:
gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME
將上述指令中的預留位置值替換為以下內容:
- LOCATION:存放區的區域或多區域位置。
- PROJECT_ID:您的 Cloud 專案 ID。
- REPOSITORY:Artifact Registry 存放區的名稱。
- IMAGE_NAME:容器映像檔的名稱。
程序完成後,系統會建構容器映像檔、儲存在 Artifact Registry 中,並部署至 Cloud Run。
完成本程式碼研究室後,您的應用程式應與 mod4-migrate-to-cloud-run 資料夾中的應用程式相同。
這樣就大功告成囉!您已成功將 Java 8 App Engine 應用程式遷移至 Java 17 和 Cloud Run,並且可以更清楚瞭解切換及選擇託管選項時的相關工作。
6. 摘要/清理
恭喜,您已完成應用程式的升級、容器化和遷移作業,本教學課程到此結束!
接下來,您可以進一步瞭解 CI/CD 和軟體供應鏈安全性功能,這些功能現在已可透過 Cloud Build 部署:
選用:清理及/或停用服務
如果您在本教學課程中在 App Engine 上部署範例應用程式,請務必停用應用程式,以免產生費用。當您準備好轉移至下一個程式碼研究室時,可以重新啟用該研究室。停用 App Engine 應用程式後,不會獲得任何流量的費用,不過如果 Datastore 用量超過免費配額,就可能要計費,所以刪除後必須超過限制。
7. 其他資源
App Engine 遷移模組程式碼研究室問題/意見回饋
如果您在本程式碼研究室中發現任何問題,請先搜尋您的問題,再提交。搜尋及建立新問題的連結:
遷移資源
線上資源
以下為可能與本教學課程相關的線上資源:
App Engine
- App Engine 說明文件
- App Engine 定價和配額資訊
- 比較第一代和第二代平台
- 對舊版執行階段的長期支援
其他雲端資訊
- Google Cloud「一律免費」級別
- Google Cloud CLI (
gcloud
CLI) - 所有 Google Cloud 說明文件
影片
授權
這項內容採用的是創用 CC 姓名標示 2.0 通用授權。