1. 概览
本系列 Codelab(自定进度的实操教程)旨在指导 Google App Engine(标准)Java 开发者完成一系列迁移,从而对应用进行现代化改造。按照以下步骤操作,您可以更新应用以提高其可移植性,并决定将其容器化以支持 Cloud Run(App Engine 的 Google Cloud 容器托管姊妹服务)和其他容器托管服务。
本教程教您如何使用 Jib 容器化 App Engine 应用,以便部署到 Cloud Run 全代管式服务。借助 Jib,您可以创建 Docker 映像,这是一个业界知名的平台,可用于在容器中开发、交付和运行应用。
除了介绍从 App Engine 迁移到 Cloud Run 所需的步骤外,您还将了解如何将 Java 8 App Engine 应用升级到 Java 17。
如果您的应用大量使用 App Engine 旧版捆绑服务或其他 App Engine 功能,我们建议您先迁移这些捆绑服务或替换这些功能,然后再迁移到 Cloud Run。如果您需要更多时间来研究迁移选项或想要暂时继续使用旧版捆绑服务,可以在升级到较新版本的运行时时继续访问适用于 Java 11/17 的 App Engine 捆绑服务。当您的应用变得更加可移植后,请返回此 Codelab,了解如何将这些说明应用于您的应用。
在接下来的实验中
- 使用 Cloud Shell
- 启用 Cloud Run API、Artifact Registry API 和 Cloud Build API
- 使用 Jib 和 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. 背景
PaaS 系统(例如 App Engine 和 Cloud Functions)为您的团队和应用提供了许多便利,例如让系统管理员和开发运维团队专注于构建解决方案。借助无服务器平台,您的应用可根据需要自动扩缩,使用按用量计费的结算方式有助于缩减至零,并使用多种常见的开发语言。
不过,容器的灵活性也具有吸引力。容器可让您选择任何语言、任何库和任何二进制文件,从而兼具无服务器的便利性和容器的灵活性。这正是 Cloud Run 的精髓。
了解如何使用 Cloud Run 不在本 Codelab 的范围之内,而是在 Cloud Run 文档中介绍。本课程的目标是让您熟悉如何为 Cloud Run(或其他容器托管的服务)容器化 App Engine 应用。在继续前进之前,您需要了解一些事项,主要是您的用户体验会略有不同。
在此 Codelab 中,您将学习如何构建和部署容器。您将了解如何:
- 使用 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 中克隆示例应用,然后进入基准文件夹。
该示例是一个基于 Servlet 的 Java 8 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 的功能,我们建议您在升级到新运行时时继续访问这些服务。此 Codelab 演示了已在使用独立服务或可以重构为使用独立服务的应用的迁移路径。
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 和 Cloud Run 之间的一些差异。一个区别是,虽然 App Engine 的 Java 8 运行时为其托管的应用提供和管理 Jetty 服务器,但 Cloud Run 不会。我们将使用 Spring Boot 向我们提供 Web 服务器和 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,以最大限度地减少迁移后默认行为的差异。我们还可以直接配置 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 能够在不进行修改的情况下重复使用 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 文件
虽然您可以使用 Jib 从 WAR 文件开始将应用容器化,但如果将应用打包为可执行 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 配置、服务和依赖项
如本 Codelab 开头所述,Cloud Run 和 App Engine 旨在提供不同的用户体验。App Engine 提供的一些开箱即用功能(例如 Cron 和 Task Queue 服务)需要手动重新创建,我们将在后续模块中对此进行详细介绍。
该示例应用未使用旧版捆绑服务,但如果您的应用使用了旧版捆绑服务,则可以参阅以下指南:
- 从捆绑服务迁移,以查找合适的独立服务。
- 将 XML 配置文件迁移到 YAML,适用于迁移到 Java 11/17 运行时,同时继续使用 App Engine 的用户。
由于从现在开始您将部署到 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 按照这些步骤操作后,它将执行以下操作:
- 使用
./mvnw test
运行测试 - 使用 Jib 构建映像、将其推送到 Artifact Registry 并为其添加标记
- 使用
gcloud run deploy
将映像部署到 Cloud Run
请注意,‘visitors'
是作为所需服务名称提供给 Cloud Run 的。借助 –allow-unauthenticated
标志,用户无需进行身份验证即可访问 Web 应用。请务必在 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。
学完此 Codelab 后,您的应用看起来应与 java17-and-cloud-run/finish 中的应用相同。
好了,大功告成!您已成功将 Java 8 App Engine 应用迁移到 Java 17 和 Cloud Run,现在更清楚地了解了切换和在托管选项之间进行选择时所涉及的工作。
6. 摘要/清理
恭喜,您已升级、容器化和迁移应用,至此本教程已结束!
接下来,您可以详细了解目前可通过 Cloud Build 部署的 CI/CD 和软件供应链安全功能:
可选:清理和/或停用服务
如果您在本教程中在 App Engine 上部署了示例应用,请务必停用该应用,以免产生费用。当您准备好进入下一个 Codelab 时,可以重新启用该功能。App Engine 应用被停用后,不会产生任何流量产生费用,但如果超出免费配额,则 Datastore 使用量可能会计费,因此请删除足够的数据以使其不超出此限制。
7. 其他资源
App Engine 迁移模块 Codelab 问题/反馈
如果您发现此 Codelab 存在任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:
迁移资源
在线资源
以下是与本教程可能相关的在线资源:
App Engine
- App Engine 文档
- App Engine 价格和配额信息
- 比较第一代和第二代平台
- 对旧版运行时的长期支持
其他云信息
- Google Cloud“始终免费”层级
- Google Cloud CLI (
gcloud
CLI) - 所有 Google Cloud 文档
视频
许可
此作品已获得 Creative Commons Attribution 2.0 通用许可授权。