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

1. 總覽

本系列的程式碼研究室 (自助教學和實作教學課程) 旨在引導 Google App Engine (標準) Java 開發人員透過一系列的遷移作業,協助他們翻新應用程式。您可以藉由下列步驟,更新應用程式以提高可攜性,並決定將應用程式容器化,以便用於 Cloud Run、Google Cloud 的容器託管主機服務,以及其他容器託管服務。

本教學課程說明如何使用 Jib 將 App Engine 應用程式容器化,以便部署至 Cloud Run 全代管服務。您可以透過 Jib 建立 Docker 映像檔。Docker 是業界的知名平台,用於在容器中開發、傳送及執行應用程式。

除了指導您從 App Engine 遷移至 Cloud Run 的必要步驟之外,您也會瞭解如何將 Java 8 App Engine 應用程式升級至 Java 17。

如果您的應用程式大量使用 App Engine 的舊版套裝組合服務或其他 App Engine 功能,建議您在遷移至 Cloud Run 之前,先從這些套裝組合服務中遷移或更換這些功能。如果您需要更多時間調查遷移選項,或是想暫時繼續使用舊版套裝組合服務,可以在升級至較新的執行階段時,繼續使用適用於 Java 11/17 的 App Engine 套裝組合服務。應用程式可攜性較高時,請回到本程式碼研究室,瞭解如何在應用程式中套用操作說明。

在接下來的研究室中

  • 使用 Cloud Shell
  • 啟用 Cloud Run、Artifact Registry 和 Cloud Build API
  • 使用 Jib 和 Cloud Build 將應用程式容器化
  • 將容器映像檔部署至 Cloud Run

軟硬體需求

問卷調查

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

僅供閱讀 閱讀並完成練習

您覺得 Java 的使用體驗如何?

新手 中級 還算容易

針對使用 Google Cloud 服務的經驗,您會給予什麼評價?

新手 中級 還算容易

2. 背景

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

不過,容器的彈性也很實用。容器能選擇任何語言、任何程式庫和二進位檔,帶來兩大優勢:無伺服器的便利性加上容器的靈活彈性。這就是 Cloud Run 的重點。

瞭解如何使用 Cloud Run 不在本程式碼研究室的範圍內。請參閱 Cloud Run 說明文件。我們的目標是讓您瞭解如何為 Cloud Run (或其他容器託管服務) 將 App Engine 應用程式容器化。開始使用前,請務必瞭解幾個注意事項,主要的使用者體驗會略有不同。

在本程式碼研究室中,您將學習如何建構及部署容器。您將學習下列內容:

  • 使用 Jib 將應用程式容器化
  • 捨棄 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. (選用) 部署基準應用程式

只有在您想先確認應用程式能在 App Engine 上正常運作,才遷移至 Cloud Run 時,才需要執行下列操作。

請參閱 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,請考慮升級至 11 或 17 等較新 LTS 候選版,以便跟上安全性更新並取得新的語言功能。

請先更新 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,盡可能減少遷移後預設行為的差異。我們也可以將 Jetty 版本設定為與 App Engine 直接提供的版本相符

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <jetty.version>9.4.46.v20220331</jetty.version>
</properties>

3. 設定 Spring Boot

雖然 Spring Boot 不需修改即可重複使用 WhatsApp,但這項功能需要進行一些設定才能偵測。

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

雖然您可以使用 Jib 從戰爭開始將應用程式容器化,但將應用程式封裝為可執行的 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工作佇列服務,因此需要手動重新建立,我們將在後續單元中詳細說明。

範例應用程式不會使用舊版套裝組合服務,但使用者所擁有應用程式的使用者可參閱下列指南:

從現在起,您即將部署至 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 提供實作部署體驗的絕佳選項。後續的單元將詳細介紹來源部署。

或者,如果您想進一步控管應用程式的部署方式,可以定義 cloudbuild.yaml 檔案,明確安排您想要的建構步驟:

1. 定義 cloudbuild.yaml 檔案

在與 pom.xml 相同的層級建立以下 cloudbuild.yaml 檔案:

steps:
  # Test your build
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: ["test"]
  # Build with Jib
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: [ "compile", "com.google.cloud.tools:jib-maven-plugin:3.2.1:build", "-Dimage=northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib"]
  # Deploy to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: [ 'run', 'deploy', 'visitors', '--image', 'northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib', '--region', 'northamerica-northeast1', '--allow-unauthenticated']

告知 Cloud Build 按照以下步驟操作後,就會:

  1. 使用 ./mvnw test 執行測試
  2. 使用 Jib 建構及推送映像檔,並標記至 Artifact Registry
  3. 透過 gcloud run deploy 將映像檔部署至 Cloud Run

請注意,系統會將 ‘visitors' 當做所需服務名稱提供給 Cloud Run。–allow-unauthenticated 標記可讓使用者在不需要驗證的情況下造訪網頁應用程式。請務必在 cloudbuild.yaml 檔案中,將 PROJECT_ID 替換為您的專案 ID。

接下來,請新增下列 IAM 政策繫結,允許 Cloud Build 服務帳戶存取 Artifact Registry:

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)" )

gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role=roles/run.admin \
--project=$PROJECT_ID
gcloud iam service-accounts add-iam-policy-binding $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role roles/iam.serviceAccountUser --project=$PROJECT_ID

2. 執行建構程序

您已告知 Cloud Build 所需的建構步驟,您現在可以一鍵部署,

執行下列指令:

gcloud builds submit

程序完成後,容器映像檔即會建構、儲存在 Artifact Registry 中,並部署至 Cloud Run。

在本程式碼研究室的結尾,應用程式的外觀應與 java17-and-cloud-run/finish 中的範例相同。

這樣就大功告成囉!您已成功將 Java 8 App Engine 應用程式遷移至 Java 17 和 Cloud Run,並且可以更清楚瞭解在切換及選擇託管選項時涉及的工作。

6. 摘要/清除

恭喜!您已升級、容器化,並遷移應用程式,教學課程到此結束!

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

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

如果您在本教學課程中使用 App Engine 部署範例應用程式,請記得停用應用程式以免產生費用。當您準備好前往下一個程式碼研究室時,即可重新啟用。停用 App Engine 應用程式後,不會獲得任何流量的費用,不過如果 Datastore 用量超過免費配額,就可能要計費,所以刪除後必須超過限制。

另一方面,如果您不想繼續進行遷移作業,想要徹底刪除所有資料,可以選擇刪除服務或完全關閉專案

7. 其他資源

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

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

遷移資源

線上資源

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

App Engine

其他 Cloud 資訊

影片

授權

這項內容採用的是創用 CC 姓名標示 2.0 通用授權。