使用 Buildpacks 從 Google App Engine Java 應用程式遷移至 Cloud Run

1. 總覽

本系列程式碼研究室 (可自行調整進度的實作教學課程) 旨在協助 Google App Engine (標準) Java 開發人員完成一系列遷移作業,以便將應用程式改為新一代應用程式。按照這些步驟操作,您就能更新應用程式,讓應用程式更具可攜性,並決定要為 Cloud Run 進行容器化,這是 Google Cloud 的容器代管服務,也是 App Engine 的姊妹服務,以及其他容器代管服務。

本教學課程將說明如何使用 Buildpack 將 App Engine 應用程式容器化,以便部署至 Cloud Run 全代管服務。Buildpacks 是 CNCF 專案,可讓您直接將應用程式從原始碼轉換為可在任何雲端執行的高度可攜式映像檔。

除了指導您從 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
  • 在 Cloud Build 使用 Buildpacks 將應用程式容器化
  • 將容器映像檔部署至 Cloud Run

軟硬體需求

問卷調查

您要如何使用這個教學課程?

只閱讀 閱讀並完成練習

您對使用 Java 的體驗評價為何?

初級 中級 實用

請評估你使用 Google Cloud 服務的體驗。

新手 中級 熟練

2. 背景

App Engine 和 Cloud Functions 等 PaaS 系統可為您的團隊和應用程式提供許多便利性,例如讓 SysAdmins 和 DevOps 能夠專注於建構解決方案。有了無伺服器的平台,應用程式就能視需要自動調度資源、透過「用多少付多少」的計費方式將資源縮減至零,藉此控管成本,並使用各種常見的開發語言。

不過,容器的彈性也相當吸引人。容器可讓您選擇任何語言、任何程式庫和任何二進位檔,因此可同時享有無伺服器運算的便利性和容器的彈性。這就是 Google Cloud Run 的用途。

瞭解如何使用 Cloud Run 不在本程式碼研究室的範圍內;詳情請參閱 Cloud Run 說明文件。本課程的目標是讓您熟悉如何為 Cloud Run (或其他容器代管服務) 容器化 App Engine 應用程式。繼續操作前,請先瞭解幾點重要事項,尤其是使用者體驗會有些許不同。

在本程式碼研究室中,您將瞭解如何建構及部署容器。您將瞭解如何使用 Buildpacks 將應用程式容器化、從 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」資料夾。

這個範例是用於在 App Engine 上部署的 Java 8 (以 會為基礎) Datastore 應用程式。按照 README 中的操作說明,為 App Engine 部署做好準備。

3. (選用) 部署基準應用程式

只有在您想確認應用程式在遷移至 Cloud Run 前可在 App Engine 上運作時,才需要執行下列步驟。

請參閱 README.md 中的步驟:

  1. 安裝/重新熟悉 gcloud CLI
  2. 使用 gcloud init 為專案初始化 gcloud CLI
  3. 使用 gcloud app create 建立 App Engine 專案
  4. 將應用程式範例部署至 App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. 確認應用程式在 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 提供網路伺服器和 servlet 容器。

新增下列相依項目:

<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. 建構設定

接下來,請移除設定,將應用程式封裝為 WAR。您不需要進行太多設定 (特別是使用 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工作佇列 服務) 需要手動重新建立,我們會在後續模組中詳細說明。

範例應用程式不會使用舊版套裝服務,但如果應用程式使用舊版套裝服務,使用者可以參考下列指南:

由於您將從現在開始部署至 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 Run。這是一個非常實用的選項,可在幕後使用 Cloud Build 提供免動手部署體驗。請注意,如要使用這項功能,您必須擁有具備下列至少一項權限的帳戶,並按照環境設定步驟操作,或是使用 Cloud Shell

完成這些必要條件後,只要在來源目錄中執行下列指令即可:

gcloud run deploy SERVICE --source .

執行部署指令時,系統會提示您執行下列操作:

  • 提供原始碼位置
  • 提供服務名稱
  • 啟用 Cloud Run API
  • 選取所在區域

回覆這些提示後,建構和部署程序就會開始,Cloud Build 會在這個過程中執行以下操作:

  • 壓縮,並將來源儲存在 Cloud Storage 值區中
  • 會在背景使用 Cloud Native Computing Foundation Buildpacks 建構映像檔
  • 建立註冊表來儲存產生的容器映像檔 (如果尚未存在)
  • 並建立 Cloud Run 服務來代管應用程式 (如果尚未存在)

建構和部署作業完成後,您應該會收到訊息,說明新修訂版本已上線,並處理 100% 的流量。

6. 摘要/清理

恭喜,您已完成應用程式的升級、容器化和遷移作業,本教學課程到此結束!

接下來,我們要進一步瞭解 CI/CD 和軟體供應鏈安全防護功能,您現在可透過 Cloud Build 進行部署:

選用:清除及/或停用服務

如果您在本教學課程中在 App Engine 上部署範例應用程式,請務必停用應用程式,以免產生費用。當您準備好前往下一個程式碼研究室時,即可重新啟用。在 App Engine 應用程式停用期間,不會產生任何流量費用,但如果 Datastore 用量超過免費配額,就可能會產生費用,因此請刪除足夠的資料,讓用量低於該限制。

另一方面,如果您不打算繼續遷移作業,並想完全刪除所有內容,可以刪除服務關閉專案

7. 其他資源

App Engine 遷移模組程式碼研究室問題/意見回饋

如果您在本程式碼研究室中發現任何問題,請先搜尋您的問題,再提交。搜尋及建立新問題的連結:

遷移資源

線上資源

以下是與本教學課程相關的線上資源:

App Engine

其他 Cloud 資訊

影片

授權

這項內容採用的授權為 Creative Commons 姓名標示 2.0 通用授權。