第 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 服务方面的经验水平?

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

2. 背景

PaaS 系统(例如 Google App Engine 和 Cloud Functions)为用户提供了许多便利。这些无服务器平台使您的技术团队能够专注于创建业务解决方案,而不是花费时间来调查要使用的平台并确定所需的硬件量。应用可根据需要自动扩缩,使用按用量计费的结算方式有助于缩减至零,并支持多种当今常见的开发语言。

不过,虽然 App Engine 非常适合用于全栈 Web 应用开发或移动应用的复杂后端,但开发者通常主要只是想将某些功能在线实现,例如更新新闻信息流或拉取主队季后赛的最新得分。虽然这两种场景都有相应的编码逻辑,但似乎都不是需要 App Engine 强大功能的成熟“应用”。这时,Cloud Functions 就派上用场了。

Cloud Functions 适用于部署以下少量代码:

  • 不是整个应用的一部分
  • 在整个开发技术栈中不需要
  • 位于专注于某项功能的单个移动应用后端或应用中

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

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

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

3. 设置/准备工作

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

1. 设置项目

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

2. 获取基准示例应用

此 Codelab 的先决条件之一是拥有一个工作正常的模块 2 示例应用。如果您没有,请先完成上面链接的任一教程,然后再继续学习。或者,如果您已经熟悉其内容,可以直接从下面的模块 2 开始。

无论您是使用自己的代码还是我们的代码,我们都能在模块 2 Python 3 代码中。本模块 11 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 文件是 App Engine 制品,不适用于 Cloud Functions,因此请立即将其删除。如果您未执行或忘记执行此操作,也不会有任何影响,因为 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 Request 对象传递给您的函数。)

由于 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 Function 后,不再使用 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.png

本地开发和测试

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.png

与本系列中的大多数其他 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 等平台会产生少量 build 和存储费用。在某些区域,Cloud BuildCloud Storage 都有各自的免费配额。构建会消耗部分配额。请注意您的存储空间用量,以尽可能减少潜在费用,尤其是在您所在的地区没有此类免费层级的情况下。

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

后续步骤

除了本教程之外,您还可以查看其他迁移模块,包括为 Cloud Run 容器化 App Engine 应用。请参阅指向模块 4 和模块 5 Codelab 的链接:

  • 模块 4:使用 Docker 迁移到 Cloud Run
  • 使用 Docker 将应用容器化,以便在 Cloud Run 上运行
  • 通过此迁移,您可以继续使用 Python 2。
  • 模块 5:使用 Cloud Buildpack 迁移到 Cloud Run
  • 使用 Cloud Buildpacks 将应用容器化,以便在 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 Blobstore 迁移到 Cloud Storage
  • 模块 18-19:从 App Engine 任务队列(拉取任务)迁移到 Cloud Pub/Sub

如果容器化已成为应用开发工作流的一部分,尤其是当该工作流包含 CI/CD(持续集成/持续交付或部署)流水线时,请考虑迁移到 Cloud Run 而不是 Cloud Functions。请参阅模块 4,了解如何使用 Docker 将应用容器化;或参阅模块 5,了解如何在不使用容器、Docker 知识或 Dockerfile 的情况下将应用容器化。无论您是考虑使用 Cloud Functions 还是 Cloud Run,切换到其他无服务器平台都是可选的,我们建议您在做出任何更改之前,先考虑最适合您的应用和使用情形的选项。

无论您接下来考虑哪个迁移模块,都可以在 开源代码库中访问所有无服务器迁移站内容(Codelab、视频、源代码 [如有])。该代码库的 README 还提供了有关应考虑哪些迁移以及任何相关的迁移模块“顺序”的指南。

8. 其他资源

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

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

迁移时可参考的资源

下表中提供了指向模块 8(开始)和模块 9(完成)的 Repo 文件夹的链接。您还可以从所有 App Engine Codelab 迁移的代码库中访问这些示例,您可以克隆该代码库或下载 ZIP 文件。

Codelab

Python 3

模块 2

代码

模块 11

代码

在线资源

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

App Engine

Cloud Functions

其他云信息

视频

许可

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