1. 概览
无服务器迁移站系列 Codelab(自定进度的实操教程)和相关视频旨在指导 Google Cloud 无服务器开发者完成一次或多次迁移(主要是从旧服务迁移),从而实现应用的现代化改造。这样做可以提高应用的可移植性,为您提供更多选择和灵活性,让您能够集成并访问更广泛的 Cloud 产品,并更轻松地升级到较新版本。虽然本系列最初主要面向的是最早接触 Cloud 的用户(主要是 App Engine(标准环境)开发者),但涵盖的范围非常广泛,涵盖了 Cloud Functions 和 Cloud Run 等其他无服务器平台,或其他无服务器平台(如适用)。
此 Codelab 旨在向 Python 2 App Engine 开发者展示如何从 App Engine Memcache 迁移到 Cloud Memorystore(适用于 Redis)。此外,我们还提供从 App Engine ndb
到 Cloud NDB 的隐式迁移,但这在第 2 单元 Codelab 中主要介绍;了解更多分步说明。
在接下来的实验中
- (通过 Cloud Console 或
gcloud
工具)设置 Cloud Memorystore 实例 - 设置 Cloud Serverless VPC Access 连接器(通过 Cloud Console 或
gcloud
工具) - 从 App Engine Memcache 迁移到 Cloud Memorystore
- 在示例应用中使用 Cloud Memorystore 实现缓存
- 从 App Engine
ndb
迁移到 Cloud NDB
所需条件
- 具有有效结算账号的 Google Cloud 项目(这并非免费 Codelab)
- 基本 Python 技能
- 常用 Linux 命令的实践知识
- 具备开发和部署 App Engine 应用的基础知识
- 一个可正常运行的模块 12 App Engine 应用(建议完成第 12 单元 Codelab [推荐],或从代码库中复制 Module 12 应用)
调查问卷
您打算如何使用本教程?
<ph type="x-smartling-placeholder">您如何评价使用 Python 的体验?
您如何评价自己在使用 Google Cloud 服务方面的经验水平?
<ph type="x-smartling-placeholder">2. 背景
此 Codelab 演示了如何将示例应用从 App Engine Memcache(和 NDB)迁移到 Cloud Memorystore(和 Cloud NDB)。此过程涉及替换 App Engine 捆绑服务的依赖项,从而提高应用的可移植性。您可以选择继续使用 App Engine,也可以考虑改用上述任何替代方案。
与本系列中的其他迁移相比,此迁移需要更多工作量。建议使用 Cloud Memorystore 来替代 App Engine Memcache,这是一项全托管式云端缓存服务。Memorystore 支持一对常用的开源缓存引擎,即 Redis 和 Memcached。此迁移模块使用 Cloud Memorystore for Redis。如需了解详情,请参阅 Memorystore 和 Redis 概览。
由于 Memorystore 需要一个正在运行的服务器,因此还需要 Cloud VPC。具体来说,必须创建无服务器 VPC 访问通道连接器,以便 App Engine 应用可以通过其专用 IP 地址连接到 Memorystore 实例。完成本练习后,您将更新应用,使其行为和以前一样,Cloud Memorystore 将成为缓存服务,取代 App Engine 的 Memcache 服务。
本教程首先介绍 Python 2 中的模块 12 示例应用,然后视需要额外次要升级到 Python 3。如果您已熟悉如何通过 Python 3 App Engine SDK 从 Python 3 访问 App Engine 捆绑服务,则可以从Python 3 版模块 12 示例应用开始学习。如果这样做,就需要停止使用 SDK,因为 Memorystore 不是 App Engine 捆绑服务。了解如何使用 Python 3 App Engine SDK 不在本教程的讨论范围内。
本教程包含以下关键步骤:
- 设置/准备工作
- 设置缓存服务
- 更新配置文件
- 更新主应用
3. 设置/准备工作
准备 Cloud 项目
我们建议您重复使用用于完成第 12 单元 Codelab 的项目。或者,您也可以创建一个全新的项目或重复使用其他现有项目。本系列中的每个 Codelab 都有一个“START”(起始基准代码)和“FINISH”(迁移后的应用)。我们提供 FINISH 代码,是为了便于您在遇到问题时将自己的解决方案与我们的解决方案进行比较。如果出现问题,您可以随时回滚到 START。这些检查点旨在确保您成功学会如何执行迁移。
无论您使用哪个 Cloud 项目,都请确保该项目具有有效的结算账号。此外,还要确保已启用 App Engine。查看并确保您了解学习这些教程时对费用的一般影响。不过,与本系列中的其他内容不同,此 Codelab 使用的 Cloud 资源不具有免费层级,因此完成本练习会产生一些费用。此外,我们还将提供更具体的费用信息,并提供减少用量的建议,包括最后介绍如何释放资源以最大限度降低结算费用的说明。
获取基准示例应用
此 Codelab 将从我们开始着手的基准模块 12 代码中逐步完成迁移过程。完成后,您将得到一个可正常运行的模块 13 应用,该应用与其中一个 FINISH 文件夹中的代码非常相似。这些资源如下:
- START:Module 12 Python 2 (
mod12
) 或 Python 3 (mod12b
) 应用 - 完成:Module 13 Python 2 (
mod13a
) 或 Python 3 (mod13b
) 应用 - 整个迁移代码库(克隆或下载 ZIP 文件)
START 文件夹应包含以下文件:
$ ls README.md app.yaml main.py requirements.txt templates
如果您是从 Python 2 版本开始,则还会看到一个 appengine_config.py
文件,如果您已完成第 12 单元 Codelab,还可能有一个 lib
文件夹。
(Re)部署模块 12 应用
剩余的准备工作步骤:
- 重新熟悉
gcloud
命令行工具(如有必要) - 将第 12 单元的代码(重新)部署到 App Engine(如有必要)
Python 2 用户应使用以下命令删除并重新安装 lib
文件夹:
rm -rf ./lib; pip install -t lib -r requirements.txt
现在,所有人(Python 2 和 3 用户)都应使用以下命令将代码上传到 App Engine:
gcloud app deploy
成功部署后,确认应用的外观和功能与模块 12 中的应用相似,这是一个跟踪访问的 Web 应用,为同一用户缓存 1 小时:
由于已缓存最近的访问记录,因此网页刷新应该会非常快速地加载。
4. 设置缓存服务
Cloud Memorystore 不是无服务器的。必须选择实例;在本示例中是一个运行 Redis与 Memcache 不同,Memorystore 是一款独立的 Cloud 产品,不具有免费层级,因此请务必先查看 Memorystore for Redis 价格信息,然后再继续操作。为了最大限度地降低本练习的费用,我们建议您将操作资源的数量降到最低:一个基本服务层级和 1 GB 容量。
Memorystore 实例与您的 App Engine 应用(实例)位于不同的网络上,因此,您必须创建无服务器 VPC 访问通道连接器,以便 App Engine 可以访问您的 Memorystore 资源。为了最大限度地降低 VPC 费用,请选择实例类型 (f1-micro
) 和请求的数量下限(我们建议最少 2 个,最多 3 个)。另请参阅 VPC 价格信息页面。
在引导您创建所需的各项资源时,我们会重复这些降低成本的建议。此外,在 Cloud 控制台中创建 Memorystore 和 VPC 资源时,您会在右上角看到每个产品的价格计算器,其中包含估算的每月费用(请参见下图)。如果您更改选项,这些值会自动调整。您应该会看到以下内容:
这两种资源都是必需的,先创建哪个并不重要。如果您先创建 Memorystore 实例,那么如果没有 VPC 连接器,您的 App Engine 应用将无法访问该实例。同样,如果您先创建 VPC 连接器,则该 VPC 网络上不会有任何可供 App Engine 应用通信的内容。本教程会让您先创建 Memorystore 实例,然后再创建 VPC 连接器。
一旦这两个资源都上线,您便需要将相关信息添加到 app.yaml
,以便您的应用可以访问缓存。您还可以参考官方文档中的 Python 2 或 Python 3 指南。Cloud NDB 迁移页面(Python 2 或 Python 3)上的数据缓存指南也值得参考。
创建 Cloud Memorystore 实例
由于 Cloud Memorystore 没有免费层级,因此我们建议您为完成此 Codelab 分配最少的资源。您可以使用以下设置将费用控制在最低水平:
- 选择最低的服务层级:基本(控制台默认设置:“标准”,
gcloud
默认为“基本”)。 - 选择存储空间量下限:1 GB(控制台默认设置:16 GB;
gcloud
默认为 1 GB)。 - 通常,最新版软件需要最多的资源,但可能也不建议选择最旧版本。目前的第二个最新版本为 Redis 版本 5.0(控制台默认版本:6.x)
记住这些设置后,下一部分将引导您通过 Cloud 控制台创建实例。如果您希望通过命令行执行此操作,请跳过此步骤。
在 Cloud 控制台中
前往 Cloud 控制台中的 Cloud Memorystore 页面(系统可能会提示您输入结算信息)。如果您尚未启用 Memorystore,系统会提示您执行此操作:
启用(可能伴随结算)后,您会进入 Memorystore 信息中心。您可以在此处查看项目中创建的所有实例。下方显示的项目没有任何可显示的行,因此您会看到“没有可显示的行”。如需创建 Memorystore 实例,请点击顶部的创建实例:
此页面包含一个表单,其中包含创建 Memorystore 实例所需的设置:
为了降低本教程及其示例应用的费用,请遵循前面介绍过的建议。完成选择后,点击创建。创建过程需要几分钟时间。完成后,复制实例的 IP 地址和端口号以添加到 app.yaml
。
通过命令行
虽然通过 Cloud 控制台创建 Memorystore 实例可以直观地提供信息,但有些人更喜欢使用命令行。在继续操作之前,请务必先安装并初始化 gcloud
。
与 Cloud 控制台一样,必须启用 Cloud Memorystore for Redis。发出 gcloud services enable redis.googleapis.com
命令并等待该命令运行完成,如以下示例所示:
$ gcloud services enable redis.googleapis.com Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
如果该服务已启用,则(再次)运行该命令不会产生(负面)副作用。启用该服务后,我们来创建一个 Memorystore 实例。该命令如下所示:
gcloud redis instances create NAME --redis-version VERSION \ --region REGION --project PROJECT_ID
为您的 Memorystore 实例选择一个名称;本实验使用的是“demo-ms
”项目 ID 和项目 ID“my-project
”。此示例应用的区域为 us-central1
(与 us-central
相同),但如果您担心延迟时间问题,可以使用离您更近的区域。您必须选择与 App Engine 应用相同的区域。您可以选择任何偏好的 Redis 版本,但我们目前使用的是之前建议的版本 5。基于这些设置,您需要发出以下命令(以及相关输出):
$ gcloud redis instances create demo-ms --region us-central1 \ --redis-version redis_5_0 --project my-project Create request issued for: [demo-ms] Waiting for operation [projects/my-project/locations/us-central1/operations/operation-xxxx] to complete...done. Created instance [demo-ms].
与 Cloud Console 默认设置不同,gcloud
默认为最小资源。结果是该命令中既不需要服务层级,也不需要存储容量。创建 Memorystore 实例需要几分钟时间,创建完成后,请记下实例的 IP 地址和端口号,因为不久之后,这些信息将添加到 app.yaml
中。
确认已创建实例
通过 Cloud Console 或命令行
无论您是通过 Cloud 控制台还是命令行创建实例,都可以使用以下命令确认该实例是否可用且可供使用:gcloud redis instances list --region REGION
以下命令用于检查 us-central1
区域中的实例,以及显示我们刚刚创建的实例的预期输出:
$ gcloud redis instances list --region us-central1 INSTANCE_NAME VERSION REGION TIER SIZE_GB HOST PORT NETWORK RESERVED_IP STATUS CREATE_TIME demo-ms REDIS_5_0 us-central1 BASIC 1 10.aa.bb.cc 6379 default 10.aa.bb.dd/29 READY 2022-01-28T09:24:45
当系统要求您提供实例信息或配置您的应用时,请务必使用 HOST
和 PORT
(而非 RESERVED_IP
)。Cloud 控制台中的 Cloud Memorystore 信息中心现在应该会显示该实例:
来自 Compute Engine 虚拟机
如果您拥有 Compute Engine 虚拟机 (VM),还可以从虚拟机发送 Memorystore 实例的直接命令,以确认其是否正常运行。请注意,使用虚拟机可能会产生相关费用,与您已经在使用的资源无关。
创建无服务器 VPC 访问通道连接器
与 Cloud Memorystore 一样,您可以在 Cloud 控制台或命令行中创建无服务器 Cloud VPC 连接器。同样,Cloud VPC 也不提供免费层级,因此我们建议您为完成此 Codelab 分配最少的资源,以便将费用降至最低,而这可以通过以下设置来实现:
- 选择实例数上限下限:3(控制台和
gcloud
默认值:10) - 选择费用最低的机器类型:
f1-micro
(控制台默认设置:e2-micro
,无gcloud
默认值)
下一部分将引导您使用上述 Cloud VPC 设置从 Cloud 控制台创建连接器。如果您希望通过命令行执行此操作,请跳到下一部分。
通过 Cloud 控制台
转到 Cloud 网络“无服务器 VPC 访问通道”页面(系统可能会提示您输入结算信息)。如果您尚未启用该 API,系统会提示您执行此操作:
启用该 API(也可能是结算功能)后,您会转到显示已创建的所有 VPC 连接器的信息中心。以下屏幕截图中使用的项目没有任何项目,因此显示“No rows to show”(没有可显示的行)。在控制台中,点击顶部的创建连接器:
使用所需设置填写表单:
为自己的应用选择适当的设置。对于本教程及其具有最低需求的示例应用,可以最大限度地降低费用,因此请遵循之前介绍的建议。完成选择后,点击创建。获取 VPC 连接器需要几分钟才能完成。
通过命令行
在创建 VPC 连接器之前,请先启用 Serverless VPC Access API。发出以下命令后,您应该会看到类似输出:
$ gcloud services enable vpcaccess.googleapis.com Operation "operations/acf.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
启用 API 后,系统会使用如下所示的命令创建 VPC 连接器:
gcloud compute networks vpc-access connectors create CONNECTOR_NAME \ --range 10.8.0.0/28 --region REGION --project PROJECT_ID
请为您的连接器选择一个名称,以及一个未使用的 /28
CIDR 块起始 IP 地址。本教程做出以下假设:
- Project ID:
my-project
- VPC 连接器名称:
demo-vpc
- 实例数下限:2(默认值),实例数上限:3
- 实例类型:
f1-micro
- 区域:
us-central1
- IPv4 CIDR 地址块:
10.8.0.0/28
(在 Cloud 控制台中建议)
如果按照上述假设条件执行以下命令,则预计会输出类似于以下内容的输出:
$ gcloud compute networks vpc-access connectors create demo-vpc \ --max-instances 3 --range 10.8.0.0/28 --machine-type f1-micro \ --region us-central1 --project my-project Create request issued for: [demo-vpc] Waiting for operation [projects/my-project/locations/us-central1/operations/xxx] to complete...done. Created connector [demo-vpc].
上面的命令会忽略指定默认值,例如最小实例数 2 和名为 default
的网络。VPC 连接器创建过程需要几分钟才能完成。
确认已创建连接器
此过程完成后,发出以下 gcloud
命令(假设区域为 us-central1
),以确认它已创建且可供使用:
$ gcloud compute networks vpc-access connectors list --region us-central1 CONNECTOR_ID REGION NETWORK IP_CIDR_RANGE SUBNET SUBNET_PROJECT MIN_THROUGHPUT MAX_THROUGHPUT STATE demo-vpc us-central1 default 10.8.0.0/28 200 300 READY
同样,信息中心现在应该会显示您刚刚创建的连接器:
记下 Cloud 项目 ID、VPC 连接器名称和区域。
现在,您已经通过命令行或控制台创建了必要的其他 Cloud 资源,是时候更新应用配置以支持这些资源的使用了。
5. 更新配置文件
第一步是对配置文件进行所有必要的更新。此 Codelab 的主要目标是帮助 Python 2 用户进行迁移,不过,在内容后面通常会在下面的每部分中提供有关进一步移植到 Python 3 的信息。
requirements.txt
在本部分中,我们将添加软件包来支持 Cloud Memorystore 和 Cloud NDB。对于 Cloud Memorystore for Redis,只需使用适用于 Python 的标准 Redis 客户端 (redis
),因为本身没有 Cloud Memorystore 客户端库。将 redis
和 google-cloud-ndb
都附加到 requirements.txt
,从模块 12 联接 flask
:
flask
redis
google-cloud-ndb
此 requirements.txt
文件不含任何版本号,这意味着已选择最新版本。如果出现任何不兼容的情况,请指定要在有效版本中锁定的版本号。
app.yaml
可添加的新版块
使用 Cloud NDB 等 Cloud API 时,Python 2 App Engine 运行时需要特定的第三方软件包,即 grpcio
和 setuptools
。Python 2 用户必须列出此类内置库以及 app.yaml
中的可用版本。如果您还没有 libraries
部分,请创建一个并添加两个库,如下所示:
libraries:
- name: grpcio
version: latest
- name: setuptools
version: latest
迁移应用时,您的应用可能已包含 libraries
部分。如果支持,并且缺少 grpcio
和 setuptools
,只需将其添加到现有的 libraries
部分即可。
接下来,我们的示例应用需要 Cloud Memorystore 实例和 VPC 连接器信息,因此无论您使用哪种 Python 运行时,请在 app.yaml
中添加以下两个新部分:
env_variables:
REDIS_HOST: 'YOUR_REDIS_HOST'
REDIS_PORT: 'YOUR_REDIS_PORT'
vpc_access_connector:
name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR
以上就是必要的更新。更新后的 app.yaml
现在应如下所示:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: grpcio
version: 1.0.0
- name: setuptools
version: 36.6.0
env_variables:
REDIS_HOST: 'YOUR_REDIS_HOST'
REDIS_PORT: 'YOUR_REDIS_PORT'
vpc_access_connector:
name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR
下面是“前后对比”说明您应对 app.yaml
应用的更新:
*Python 3 差异
本部分为可选内容,且仅当您要移植到 Python 3 时才进行。为此,您需要对 Python 2 配置进行多项更改。如果您暂时不想升级,请跳过此部分。
threadsafe
和 api_version
均不用于 Python 3 运行时,因此请删除这两项设置。最新的 App Engine 运行时不支持内置第三方库,也不支持复制非内置库。第三方软件包的唯一要求是在 requirements.txt
中列出这些软件包。因此,可以删除 app.yaml
的整个 libraries
部分。
接下来,Python 3 运行时需要使用能够自行路由的 Web 框架,因此我们向开发者介绍了在第 1 单元中如何从 webp2 迁移到 Flask。因此,必须将所有脚本处理程序都改为 auto
。由于此应用不提供任何静态文件,因此没有意义列出处理程序(因为它们全部为 auto
),因此也可以移除整个 handlers
部分。因此,针对 Python 3 调整的新缩写 app.yaml
应缩短为如下所示:
runtime: python39
env_variables:
REDIS_HOST: 'YOUR_REDIS_HOST'
REDIS_PORT: 'YOUR_REDIS_PORT'
vpc_access_connector:
name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR
总结了移植到 Python 3 时 app.yaml
中的区别:
- 删除
threadsafe
和api_version
设置 - 删除“
libraries
”部分 - 删除
handlers
部分(或者,如果应用提供静态文件,则仅删除script
处理程序)
替换值
新部分中 Memorystore 和 VPC 连接器中的值只是占位符。将这些大写的值 (YOUR_REDIS_HOST, YOUR_REDIS_PORT, PROJECT_ID, REGION, CONNECTOR_NAME
) 替换为您之前创建这些资源时保存的值。对于 Memorystore 实例,请务必使用 HOST
(而非 RESERVED_IP
)和 PORT
。下面是获取 HOST
和 PORT
的快速命令行方法,假设实例名称为 demo-ms
,REGION
为 us-central1
:
$ gcloud redis instances describe demo-ms --region us-central1 \ --format "value(host,port)" 10.251.161.51 6379
如果我们的示例 Redis 实例 IP 地址为 10.10.10.10
,使用我们位于区域 us-central1
中的项目 my-project
中的端口 6379
且 VPC 连接器名称为 demo-vpc
,则 app.yaml
中的这些部分将如下所示:
env_variables:
REDIS_HOST: '10.10.10.10'
REDIS_PORT: '6379'
vpc_access_connector:
name: projects/my-project/locations/us-central1/connectors/demo-vpc
创建或更新 appengine_config.py
添加对内置第三方库的支持
就像我们之前对 app.yaml
执行的操作一样,添加对 grpcio
和 setuptools
库的用法。修改 appengine_config.py
以支持内置的第三方库。如果这似乎很熟悉,这是因为从 App Engine ndb
迁移到 Cloud NDB 时,第 2 单元中也有这项要求。所需的确切更改是将 lib
文件夹添加到 setuptools.pkg_resources
工作集:
*Python 3 差异
本部分为可选内容,且仅当您要移植到 Python 3 时才进行。第 2 代 App Engine 变化值得称赞,那就是不再需要复制(有时称为“建立供应商”)第三方(非内置)第三方软件包,也不再需要在 app.yaml
中引用内置第三方软件包,这意味着您可以删除整个 appengine_config.py
文件。
6. 更新应用文件
只有一个应用文件 main.py
,因此本部分中的所有更改都只会影响该文件。我们以图形方式显示了如何将此应用迁移到 Cloud Memorystore。这些信息仅作说明之用,不供您仔细分析。所有工作都在更改代码上完成。
让我们从最上层开始,逐个学习这些部分。
更新导入作业
第 12 单元的 main.py
中的导入部分使用 Cloud NDB 和 Cloud Tasks;导入的方式如下:
之前:
from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb
切换到 Memorystore 需要读取环境变量,这意味着我们需要 Python os
模块和 redis
(Python Redis 客户端)。由于 Redis 无法缓存 Python 对象,因此使用 pickle
编组最近的访问列表,因此也要导入该列表。Memcache 的一个优势是对象序列化自动进行,而 Memorystore 更像是“DIY”。最后,将 google.appengine.ext.ndb
替换为 google.cloud.ndb
,从 App Engine ndb
升级到 Cloud NDB。完成这些更改后,您的导入现在应如下所示:
之后:
import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis
更新初始化
模块 12 的初始化包括实例化 Flask 应用对象 app
以及为一小时的缓存设置常量:
更改前:
app = Flask(__name__)
HOUR = 3600
使用 Cloud API 需要客户端,因此请在 Flask 之后立即实例化 Cloud NDB 客户端。接下来,从您在 app.yaml
中设置的环境变量获取 Memorystore 实例的 IP 地址和端口号。利用这些信息,实例化 Redis 客户端。完成这些更新后,您的代码如下所示:
之后:
app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)
*Python 3 迁移
此部分为可选内容,如果您从 Python 3 版本的 Module 12 应用起步,则为可选内容。如果是这样,需要进行一些与导入和初始化相关的更改。
首先,由于 Memcache 是 App Engine 捆绑服务,因此它在 Python 3 应用中使用需要 App Engine SDK,特别是封装 WSGI 应用(以及其他必要的配置):
之前:
from flask import Flask, render_template, request
from google.appengine.api import memcache, wrap_wsgi_app
from google.appengine.ext import ndb
app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600
由于我们要迁移到 Cloud Memorystore(不是 Memcache 等 App Engine 捆绑服务),因此必须停止使用 SDK。这很简单,因为您只需要删除同时导入 memcache
和 wrap_wsgi_app
的整行代码即可。同时删除调用 wrap_wsgi_app()
的代码行。这些更新会使应用的这一部分(实际上是整个应用)与 Python 2 版本完全相同。
之后:
import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis
app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)
最后,从 app.yaml
(删除 app_engine_apis: true
行)和 requirements.txt
(删除 appengine-python-standard
行)中取消对该 SDK 的使用。
迁移到 Cloud Memorystore(和 Cloud NDB)
Cloud NDB 的数据模型旨在与 App Engine ndb
兼容,这意味着 Visit
对象的定义保持不变。模拟第 2 单元到 Cloud NDB 的迁移,store_visit()
和 fetch_visits()
中的所有 Datastore 调用都进行了增强,并嵌入到新的 with
块中(因为必须使用 Cloud NDB 上下文管理器)。以下是此次变更之前的调用:
之前:
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
向这两个函数添加 with ds_client.context()
块,并将 Datastore 调用放入其中(并缩进)。在这种情况下,无需对调用本身进行任何更改:
之后:
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
接下来,我们来看看缓存更改。以下是第 12 单元中的 main()
函数:
之前:
@app.route('/')
def root():
'main application (GET) handler'
# check for (hour-)cached visits
ip_addr, usr_agt = request.remote_addr, request.user_agent
visitor = '{}: {}'.format(ip_addr, usr_agt)
visits = memcache.get('visits')
# register visit & run DB query if cache empty or new visitor
if not visits or visits[0].visitor != visitor:
store_visit(ip_addr, usr_agt)
visits = list(fetch_visits(10))
memcache.set('visits', visits, HOUR) # set() not add()
return render_template('index.html', visits=visits)
Redis 支持“get”命令和“set”就像 Memcache 一样我们只需要交换相应的客户端库,对吧?很接近。如前所述,我们无法使用 Redis 缓存 Python 列表(因为需要先序列化,而 Memcache 会自动处理列表),因此在 set()
调用中,使用“pickle”将访问转换为带有 pickle.dumps()
的字符串。同样,从缓存中检索访问时,您需要紧跟在 get()
之后使用 pickle.loads()
将其取消选取。以下是实现这些更改后的主要处理程序:
之后:
@app.route('/')
def root():
'main application (GET) handler'
# check for (hour-)cached visits
ip_addr, usr_agt = request.remote_addr, request.user_agent
visitor = '{}: {}'.format(ip_addr, usr_agt)
rsp = REDIS.get('visits')
visits = pickle.loads(rsp) if rsp else None
# register visit & run DB query if cache empty or new visitor
if not visits or visits[0].visitor != visitor:
store_visit(ip_addr, usr_agt)
visits = list(fetch_visits(10))
REDIS.set('visits', pickle.dumps(visits), ex=HOUR)
return render_template('index.html', visits=visits)
以上就是将示例应用使用的 Memcache 转换为 Cloud Memorystore 的 main.py
所需更改。该 HTML 模板如何并移植到 Python 3 呢?
要将 HTML 模板文件和端口更新为 Python 3 吗?
有惊喜!此时无需执行任何操作,因为该应用旨在同时在 Python 2 和 3 上运行,而无需更改任何代码或兼容库。您会看到 main.py
。在 mod13a
(2.x) 和 mod13b
(3.x)“FINISH”中完全相同文件夹中。requirements.txt
也是如此,不过版本号(如果使用的话)存在任何差异。由于界面保持不变,因此 templates/index.html
也未更新。
在 Python 3 App Engine 上运行该应用的所有必要操作均已在之前的配置中完成:从 app.yaml
中移除了不必要的指令,并且 appengine_config.py
和 lib
文件夹均被删除,因为它们在 Python 3 中未使用。
7. 摘要/清理
在此 Codelab 的最后,本部分将部署应用,验证应用是否按预期以及任何反映的输出中正常运行。应用验证完成后,请执行所有清理操作,并考虑后续步骤。
部署并验证应用
最后一项检查始终是部署示例应用。Python 2 开发者:使用以下命令删除并重新安装 lib
。(如果您在系统上同时安装了 Python 2 和 Python 3,则可能需要明确运行 pip2
。)
rm -rf ./lib pip install -t lib -r requirements.txt
Python 2 和 Python 3 开发者现在都应该使用以下命令部署他们的应用:
gcloud app deploy
由于您只是在后台为完全不同的缓存服务重新连接了代码,因此应用本身的运行方式应与模块 12 应用相同:
此步骤已完成 Codelab。我们邀请您将更新的示例应用与模块 13 文件夹中的任一文件夹进行比较:mod13a
(Python 2) 或 mod13b
(Python 3)。
清理
常规
如果您目前已完成,我们建议您停用 App Engine 应用,以免产生费用。不过,如果您希望测试或实验更多内容,App Engine 平台有免费配额,因此只要您不超过该使用量水平,您就不必支付费用。这只是计算费用,但相关 App Engine 服务可能也会产生费用,因此请查看其价格页面了解详情。如果此迁移涉及其他 Cloud 服务,这些服务单独计费。无论是哪种情况(如适用),请参阅“此 Codelab 的具体说明”部分。
为了全面披露,部署到像 App Engine 这样的 Google Cloud 无服务器计算平台会产生少量构建和存储费用。Cloud Build 和 Cloud Storage 都有自己的免费配额。该映像的存储会占用部分配额。但是,如果您居住的区域没有这样的免费层级,请留意您的存储空间用量,以最大限度地降低潜在费用。特定的 Cloud Storage“文件夹”您应检查以下内容:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
- 上述存储空间链接取决于您的
PROJECT_ID
和 *LOC
*格式,例如“us
”。
另一方面,如果您不打算继续学习此应用或其他相关的迁移 Codelab,而是想彻底删除所有内容,请关停项目。
此 Codelab 的具体内容
下列服务是此 Codelab 独有的服务。有关详情,请参阅各个产品的文档:
- Cloud Memorystore 需要实例,但没有免费层级;如需详细了解使用费,请参阅其价格页面。
- Cloud Serverless VPC Access 连接器需要实例,并且没有免费层级;如需详细了解使用费用,请参阅 Cloud VPC 价格页面上的相关部分。
- Cloud Datastore(Datastore 模式的 Cloud Firestore)提供免费层级;如需了解详情,请参阅其价格页面。
本教程介绍如何使用四种 Cloud 产品:
- App Engine
- Cloud Datastore
- Cloud Memorystore
- Cloud VPC
以下是释放这些资源和避免/最大限度降低结算费用的说明。
关停 Memorystore 实例和 VPC 连接器
这些产品没有免费层级,因此您现在会产生费用。如果您未关停 Cloud 项目(请参阅下一部分),则必须同时删除 Memorystore 实例和 VPC 连接器才能停止计费。与创建这些资源时类似,您也可以通过 Cloud 控制台或命令行进行释放。
通过 Cloud 控制台
如需删除 Memorystore 实例,请返回 Memorystore 信息中心,然后点击实例 ID:
进入该实例的详情页面后,点击“删除”并确认:
要删除 VPC 连接器,请转到其信息中心,选中要删除的连接器旁边的复选框,然后点击“删除”并确认:
从命令行
以下几对 gcloud
命令可分别删除 Memorystore 实例和 VPC 连接器:
gcloud redis instances delete INSTANCE --region REGION
gcloud compute networks vpc-access connectors delete CONNECTOR --region REGION
如果您尚未使用 gcloud config set project
设置项目 ID,则可能需要提供 --project PROJECT_ID
。如果您的 Memorystore 实例名为 demo-ms
,VPC 连接器名为 demo-vpc
,并且两者都位于 us-central1
区域中,请发出下面这对命令并确认:
$ gcloud redis instances delete demo-ms --region us-central1 You are about to delete instance [demo-ms] in [us-central1]. Any associated data will be lost. Do you want to continue (Y/n)? Delete request issued for: [demo-ms] Waiting for operation [projects/PROJECT/locations/REGION/operations/operation-aaaaa-bbbbb-ccccc-ddddd] to complete...done. Deleted instance [demo-ms]. $ $ gcloud compute networks vpc-access connectors delete demo-vpc --region us-central1 You are about to delete connector [demo-vpc] in [us-central1]. Any associated data will be lost. Do you want to continue (Y/n)? Delete request issued for: [demo-vpc] Waiting for operation [projects/PROJECT/locations/REGION/operations/aaaaa-bbbb-cccc-dddd-eeeee] to complete...done. Deleted connector [demo-vpc].
每个请求的运行需要几分钟时间。如果您按照上文所述选择关停整个 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
App Engine 不再是 Google Cloud 中唯一的无服务器平台。如果您有一个小型 App Engine 应用或功能有限的应用,并希望将其转换为独立的微服务,或者您希望将单体式应用拆分为多个可重复使用的组件,那么这些都是考虑迁移到 Cloud Functions 的充分理由。如果容器化已成为应用开发工作流的一部分,特别是当它由 CI/CD(持续集成/持续交付或部署)流水线组成时,请考虑迁移到 Cloud Run。以下模块介绍了这些场景:
- 从 App Engine 迁移到 Cloud Functions:请参阅单元 11
- 从 App Engine 迁移到 Cloud Run:请参阅第 4 单元,了解如何使用 Docker 将应用容器化;请参阅第 5 单元,在不具备容器、Docker 知识或
Dockerfile
的情况下实现容器化
您可以自行选择是否切换到其他无服务器平台,我们建议您先考虑最适合您的应用和用例的方案,然后再做任何更改。
无论您接下来考虑使用哪种迁移模块,都可以通过其开源代码库访问所有 Serverless Migration Station 内容(Codelab、视频、源代码 [如果有])。代码库的 README
还提供了有关应考虑哪些迁移以及任何相关“顺序”的指南。迁移模块
8. 其他资源
下面列出的其他资源可帮助开发者进一步探索此迁移模块或相关迁移模块及相关产品。这包括提供有关此内容的反馈、代码链接以及各种可能对您有用的文档的地方。
Codelab 问题/反馈
如果您在此 Codelab 中发现任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:
迁移时可参考的资源
下表列出了模块 12(START)和模块 13 (FINISH) 对应的代码库文件夹的链接。您还可以从所有 App Engine Codelab 迁移的代码库访问这些库,您可以克隆或下载 ZIP 文件。
Codelab | Python 2 | Python 3 |
第 13 单元(此 Codelab) |
在线参考
以下是可能与本教程相关的在线资源:
App Engine
- App Engine 文档
- Python 2 App Engine(标准环境)运行时
- 在 Python 2 App Engine 上使用 App Engine 内置库
- Python 3 App Engine(标准环境)运行时
- Python 2 与3 个 App Engine(标准环境)运行时
- Python 2 到 3 App Engine(标准环境)迁移指南
- App Engine 价格和配额信息
App Engine NDB 和 Cloud NDB
- App Engine NDB 概览
- App Engine NDB Datastore 用量
- Google Cloud NDB 文档
- Google Cloud NDB 代码库
- Cloud Datastore 价格信息
App Engine Memcache 和 Cloud Memorystore
- App Engine Memcache 概览
- Python 2 App Engine
memcache
参考文档 - Python 3 App Engine
memcache
参考文档 - App Engine
memcache
到 Cloud Memorystore 迁移指南 - Cloud Memorystore 文档
- Cloud Memorystore for Redis 文档
- Cloud Memorystore for Redis 价格信息
- Cloud Memorystore 支持的 Redis 版本
- Cloud Memorystore 首页
- 在 Cloud 控制台中创建新的 Memorystore 实例
- Python Redis 客户端首页
- Python Redis 客户端库文档
Cloud VPC
其他 Cloud 信息
- 在 Google Cloud Platform 上使用 Python 应用
- Google Cloud Python 客户端库
- Google Cloud“始终免费”计划层级
- Google Cloud SDK(
gcloud
命令行工具) - 所有 Google Cloud 文档
许可
此作品已获得 Creative Commons Attribution 2.0 通用许可授权。