第 11 单元:从 Google App Engine 迁移到 Cloud Functions

1. 概览

无服务器迁移站系列 Codelab(自定进度的实操教程)和相关视频旨在指导 Google Cloud 无服务器开发者完成一次或多次迁移(主要是从旧服务迁移),从而实现应用的现代化改造。这样做可以提高应用的可移植性,为您提供更多选择和灵活性,让您能够集成并访问更广泛的 Cloud 产品,并更轻松地升级到较新版本。虽然本系列最初主要面向的是最早接触 Cloud 的用户(主要是 App Engine(标准环境)开发者),但涵盖的范围非常广泛,涵盖了 Cloud FunctionsCloud Run 等其他无服务器平台,或其他无服务器平台(如适用)。

在有些情况下,您还没有“整个应用”需要 App EngineCloud Run 的资源。如果您的代码仅包含微服务或简单函数,那么 Cloud Functions 可能更适合您。在此 Codelab 中,您将学习如何迁移简单的 App Engine 应用(或将较大的应用拆分成多个微服务),并将其部署到 Cloud Functions,这是专为此类用例打造的另一个无服务器平台。

在接下来的实验中

  • 使用 Cloud Shell
  • 启用 Google Cloud Translation API
  • 对 API 请求进行身份验证
  • 转换小型 App Engine 应用以便在 Cloud Functions 上运行
  • 将代码部署到 Cloud Functions

所需条件

调查问卷

您将如何使用本教程?

仅阅读教程内容 阅读并完成练习

您如何评价使用 Python 的体验?

新手水平 中等水平 熟练水平

您如何评价自己在使用 Google Cloud 服务方面的经验水平?

<ph type="x-smartling-placeholder"></ph> 新手 中级 熟练

2. 背景

Google App Engine 和 Cloud Functions 等 PaaS 系统可为用户提供许多便利。借助这些无服务器平台,您的技术团队可以专注于打造业务解决方案,而无需花时间调查平台以使用和确定所需硬件数量。应用程序可以根据需要自动扩容、缩容至零,通过按用量计费模式控制成本,并且支持当今的多种常用开发语言。

然而,虽然全栈 Web 应用开发或针对移动应用的复杂后端非常适合 App Engine,但通常情况下,开发者主要尝试将一些功能放到线上,例如更新新闻信息流或提取主队季后赛的最新得分。虽然这两种场景都有编码逻辑,但它们都不是成熟的“应用”需要 App Engine 的强大功能。这正是 Cloud Functions 的用武之地。

Cloud Functions 用于部署一小段代码,以便:

  • 不是整个应用的一部分
  • 不需在整个开发堆栈中使用
  • 位于专注于某件事的应用或单个移动应用后端中

您还可以使用 Cloud Functions 将大型单体式应用分解为多项微服务,每项微服务都使用共享的通用数据库,例如 Cloud FirestoreCloud SQL。如果您希望自己的函数或微服务在 Cloud Run 上实现容器化并以无服务器方式执行,您也可以使用它。

我们在几乎所有迁移教程中都会介绍我们的示例 App Engine 应用,它是一个具备基本功能的简短应用,在 Cloud Functions 中也能正常运行。在本教程中,您将学习如何修改该应用以便在 Cloud Functions 上运行。从 App Engine 的角度来看,由于函数比整个应用更简单,因此入门体验应该更轻松、更快,并且“开销”更少。此迁移具有以下步骤:

  • 设置/准备工作
  • 移除配置文件
  • 修改应用文件

3. 设置/准备工作

此 Codelab 将从 Python 3 版本的 Module 2 Cloud NDB App Engine 示例应用开始,因为 Cloud Functions 不支持 Python 2。首先,我们设置项目,获取代码,然后部署基准应用,以确认我们开始使用可正常工作的代码。

1. 设置项目

如果您已完成第 2 单元 Codelab(并将其移植到 Python 3 中),我们建议您重复使用同一项目(和代码)。或者,您也可以创建一个全新的项目或重复使用其他现有项目。确保项目具有已启用 App Engine 服务的有效结算账号。

2. 获取基准示例应用

学习此 Codelab 的前提条件之一是拥有一个可正常运行的模块 2 示例应用。如果您还没有账号,请先完成上面链接的任一教程,然后再继续本文。或者,如果您已经熟悉其内容,则可以先获取下面的模块 2 代码。

无论您使用的是还是我们的代码,我们都将从模块 2 Python 3 代码入手。在此 Codelab 中,我们将逐步引导您完成每个步骤,最后使用与模块 11 代码库文件夹 (FINISH) 中的代码类似的代码。

Python 3 第 2 单元开始文件(您自己的或我们的)的目录应如下所示:

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. (重新)部署基准应用

现在需要执行的其余准备工作步骤:

  1. 重新熟悉 gcloud 命令行工具
  2. 使用 gcloud app deploy 重新部署示例应用
  3. 确认应用在 App Engine 上运行没有任何问题

成功执行这些步骤后,您就可以将其转换为 Cloud Functions 函数了。

4. 移除配置文件

app.yaml 文件是一个未与 Cloud Functions 搭配使用的 App Engine 工件,因此请立即将其删除。如果您不记得或忘记这样做,也没有什么坏处,因为 Cloud Functions 不会使用它。这是唯一的配置变更,因为 requirements.txt 与模块 2 中的配置完全相同。

如果您还要将 Python 2 App Engine 应用移植到 Python 3,请删除 appengine_config.pylib 文件夹(如果有)。它们是 Python 3 运行时中未使用的 App Engine 工件。

5. 修改应用文件

只有一个应用文件,即 main.py,因此迁移到 Cloud Functions 所需的所有更改都发生在此文件中。

导入

由于我们仅使用函数,因此不需要 Web 应用框架。不过,为方便起见,在调用基于 Python 的 Cloud Functions 函数时,系统会自动向这些函数传递一个请求对象,以供代码根据需要使用。(Cloud Functions 团队选择将其作为传递给函数的 Flask 请求对象。)

由于 Web 框架不属于 Cloud Functions 环境,因此除非您的应用使用其他 Flask 功能,否则无法从 Flask 进行导入。的确如此,因为在转换为函数后,模板渲染仍在进行,这意味着仍然需要调用 flask.render_template(),因此它从 Flask 导入。没有 Web 框架意味着不需要实例化 Flask 应用,因此请删除 app = Flask(__name__)。在应用更改前后,您的代码应如下所示:

之前

from flask import Flask, render_template, request
from google.cloud import ndb

app = Flask(__name__)
ds_client = ndb.Client()

之后

from flask import render_template
from google.cloud import ndb

ds_client = ndb.Client()

如果您依赖于应用对象 (app) 或任何其他 Web 框架基础架构,则需要解析所有这些依赖项,找到适当的解决方法,或者完全停止使用它们或查找代理。然后,您才能将代码转换为 Cloud Functions 函数。否则,您最好继续使用 App Engine 或针对 Cloud Run 将应用容器化

更新主处理程序函数签名

函数签名所需的更改如下所示:

  1. 将应用转换为 Cloud Functions 函数后,不再使用 Flask,因此请移除路由修饰器。
  2. Cloud Functions 会自动将 Flask Request 对象作为参数传入,因此为其创建变量。在示例应用中,我们将其命名为 request
  3. 必须命名已部署的 Cloud Functions 函数。我们的主处理程序在 App Engine 中适当地命名为 root() 来描述它是什么(根应用处理程序)。对于 Cloud Functions 函数,使用该名称没有意义。而是使用 visitme 名称部署 Cloud Functions 函数,因此也请使用该名称作为 Python 函数的名称。同样,在模块 4 和模块 5 中,我们还将 Cloud Run 服务命名为 visitme

以下是这些更新前后的对比:

之前

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

之后

def visitme(request):
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

所有必要的更新到此结束。请注意,所做的更改仅影响应用的“基础架构”代码。无需对核心应用代码进行任何更改,并且应用的功能也不会改变。为体现这一点,我们所做的更改如下图所示:

668f30e3865b27a9

本地开发和测试

App Engine 使用 dev_appserver.py 本地开发服务器,而 Cloud Functions 使用 Functions 框架。借助此框架,您可以在本地进行开发和测试。您的代码可以部署到 Cloud Functions,也可以部署到其他计算平台,例如 Compute EngineCloud Run,甚至是支持 Knative 的本地或混合云系统。有关 Functions 框架的其他链接,请参阅下文。

6. 构建和部署

部署到 Cloud Functions 与部署到 App Engine 略有不同。由于未在 requirements.txt 之外使用任何配置文件,因此您必须在命令行中指定有关代码的更多信息。使用以下命令部署在 Python 3.10 下运行的新 HTTP 触发 Cloud Functions 函数:

$ gcloud functions deploy visitme --runtime python310 --trigger-http --allow-unauthenticated

您应会看到如下所示的输出:

Deploying function (may take a while - up to 2 minutes)...⠛
For Cloud Build Logs, visit: https://console.cloud.google.com/cloud-build/builds;region=REGION/f5f6fc81-1bb3-4cdb-8bfe?project=PROJECT_ID
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
buildId: f5f6fc81-1bb3-4cdb-8bfe
buildName: projects/PROJECT_ID/locations/REGION/builds/f5f6fc81-1bb3-4cdb-8bfe
dockerRegistry: CONTAINER_REGISTRY
entryPoint: visitme
httpsTrigger:
  securityLevel: SECURE_OPTIONAL
  url: https://REGION-PROJECT_ID.cloudfunctions.net/visitme
ingressSettings: ALLOW_ALL
labels:
  deployment-tool: cli-gcloud
name: projects/PROJECT_ID/locations/REGION/functions/visitme
runtime: python310
serviceAccountEmail: PROJECT_ID@appspot.gserviceaccount.com
sourceUploadUrl: https://storage.googleapis.com/uploads-853031211983.REGION.cloudfunctions.appspot.com/8c923758-cee8-47ce-8e97-5720a5301c34.zip
status: ACTIVE
timeout: 60s
updateTime: '2022-05-16T18:28:06.153Z'
versionId: '8'

部署函数后,使用部署输出中的网址并访问您的应用。网址格式如下:REGION-PROJECT_ID.cloudfunctions.net/visitme。输出应该与您之前将其部署到 App Engine 时的输出相同:

2732ae9218f011a2

与本系列中的大多数其他 Codelab 和视频一样,基准应用功能不会改变。其目的是应用一种现代化技术,让应用完全像以前一样运行,但由更新的基础架构提供支持,例如,从旧版 App Engine 旧版服务迁移到其替代的 Cloud 独立产品,或者像本教程一样,将应用迁移到另一个 Google Cloud 无服务器平台。

7. 摘要/清理

恭喜您将这个小型 App Engine 应用转换为 Cloud Functions 函数!另一个合适的使用场景:将大型单体式 App Engine 应用分解成一系列微服务,每个微服务都是一个 Cloud Functions 函数。这是一种更现代的开发技术,使得游戏更加“即插即用”组件(“JAM 堆栈”)样式。它支持混搭和代码重用,这是两个目标。但另一个好处是,这些微服务将随着时间的推移不断得到调试,这意味着代码稳定且总体维护成本更低。

清理

完成此 Codelab 后,您可以(暂时或永久)停用第 2 单元的 App Engine 应用,以免产生费用。App Engine 平台有免费配额,因此只要您的使用量未超过该使用量水平,我们便无需付费。这同样适用于 Datastore如需了解详情,请参阅 Cloud Datastore 价格页面

部署到 App Engine 和 Cloud Functions 等平台会产生少量构建和存储费用。在某些区域,Cloud BuildCloud Storage 都有自己的免费配额。构建会消耗部分配额。请留意您的存储空间用量,以尽可能降低潜在费用,尤其是当您的区域没有此类免费层级时。

遗憾的是,Cloud Functions 并没有“停用”功能,功能。备份您的代码,然后删除该函数。您日后可以随时使用相同名称重新部署该映像。不过,如果您不打算继续学习任何其他迁移 Codelab,而是想彻底删除所有内容,请关停您的 Cloud 项目

后续步骤

除了本教程外,您还需要了解其他迁移模块,包括将适用于 Cloud Run 的 App Engine 应用容器化。请参阅指向第 4 单元和第 5 单元 Codelab 的链接:

  • 第 4 单元:迁移到 Cloud Run with Docker
  • 使用 Docker 将应用容器化,以便在 Cloud Run 上运行
  • 此次迁移让您可以继续使用 Python 2。
  • 第 5 单元:使用 Cloud Buildpack 迁移到 Cloud Run
  • 使用 Cloud Buildpack 将应用容器化,以便在 Cloud Run 上运行
  • 您无需了解有关 Docker、容器或 Dockerfile 的任何知识。
  • 要求您的应用已迁移到 Python 3(Buildpack 不支持 Python 2)

其他许多单元着重向开发者展示如何从 App Engine 捆绑式服务迁移到 Cloud 独立替代服务:

  • 第 2 单元:从 App Engine ndb 迁移到 Cloud NDB
  • 模块 7-9:从 App Engine 任务队列推送任务迁移到 Cloud Tasks
  • 模块 12-13:从 App Engine Memcache 迁移到 Cloud Memorystore
  • 第 15-16 单元:从 App Engine Blob 存储区迁移到 Cloud Storage
  • 模块 18-19:从 App Engine 任务队列(拉取任务)迁移到 Cloud Pub/Sub

如果容器化已成为应用开发工作流的一部分,特别是当它由 CI/CD(持续集成/持续交付或部署)流水线组成时,请考虑迁移到 Cloud Run,而不是 Cloud Functions。如需了解如何使用 Docker 将应用容器化,请参阅第 4 单元;若要在不具备容器、Docker 知识或 Dockerfile 的情况下实现容器化,请参阅模块 5。无论考虑使用 Cloud Functions 还是 Cloud Run,切换到其他无服务器平台都是非强制性的,我们建议您先考虑适用于您的应用和用例的最佳方案,然后再做出任何更改。

无论您接下来考虑使用哪种迁移模块,都可以通过其开源代码库访问所有 Serverless Migration Station 内容(Codelab、视频、源代码 [如果有])。代码库的 README 还提供了有关应考虑哪些迁移以及任何相关“顺序”的指南。迁移模块

8. 其他资源

App Engine 迁移模块 Codelab 问题/反馈

如果您在此 Codelab 中发现任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:

迁移时可参考的资源

下表列出了模块 8(START)和模块 9 (FINISH) 对应的代码库文件夹的链接。您还可以从所有 App Engine Codelab 迁移的代码库访问这些库,您可以克隆或下载 ZIP 文件。

Codelab

Python 3

模块 2

代码

模块 11

代码

在线资源

以下是可能与本教程相关的在线资源:

App Engine

Cloud Functions

其他 Cloud 信息

视频

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。