1. 概览
本系列 Codelab(自定进度的实操教程)旨在指导 Google App Engine(标准环境)开发者完成一系列迁移,从而对应用进行现代化改造。最重要的步骤是摆脱原始的运行时捆绑服务,因为下一代运行时更加灵活,为用户提供了更多的服务选项。移至新一代运行时,您可以更轻松地与 Google Cloud 产品集成,使用更多支持的服务,并支持当前的语言版本。
本可选教程向开发者介绍了如何从 Cloud NDB 迁移到 Cloud Datastore 作为客户端库,以便与 Datastore 服务通信。偏爱 NDB 的开发者可以使用 NDB,因为它与 Python 3 兼容,因此这是可选迁移。此迁移仅适用于希望与已在使用 Cloud Datastore 的其他应用构建一致的代码库和共享库的用户。详情请参阅部分。
您将了解如何
- 使用 Cloud NDB(如果您不熟悉)
- 从 Cloud NDB 迁移到 Cloud Datastore
- 进一步将应用迁移到 Python 3
所需条件
- 具备具有有效 GCP 结算账号的 Google Cloud Platform 项目
- 基本 Python 技能
- 基本 Linux 命令的实践知识
- 具备开发和部署 App Engine 应用的基础知识
- 可运行的模块 2 App Engine 2.x 或 3.x 应用。
调查问卷
如何使用此 Codelab?
<ph type="x-smartling-placeholder">2. 背景
虽然 Cloud NDB 是适用于长期 App Engine 开发者的出色 Datastore 解决方案,有助于过渡到 Python 3,但它并不是 App Engine 开发者访问 Datastore 的唯一方式。当 App Engine 的 Datastore 于 2013 年成为自己的产品时,Google Cloud Datastore 创建了一个新的客户端库,以便所有用户都能使用 Datastore。
已引导 Python 3 App Engine 和非 App Engine 开发者使用 Cloud Datastore(而非 Cloud NDB)。我们鼓励 Python 2 App Engine 开发者从 ndb
迁移到 Cloud NDB,并从该处移植到 Python 3,但他们也可以选择进一步迁移到 Cloud Datastore。这一决策尤其适合已在使用 Cloud Datastore 的代码(例如刚刚提到的那些)并希望跨所有应用创建共享库的开发者。与代码一致性一样,代码重用也是一种最佳做法,并且两者都有助于降低整体的维护成本,总结如下:
从 Cloud NDB 迁移到 Cloud Datastore
- 让开发者只需专注于单个代码库,即可访问 Datastore
- 避免使用 Cloud NDB 维护部分代码,使用 Cloud Datastore 维护其他代码
- 提高代码库的一致性和更好的代码可重用性
- 支持使用通用/共享库,从而降低整体维护成本
此次迁移包括以下主要步骤:
- 设置/准备工作
- 将 Cloud NDB 替换为 Cloud Datastore 客户端库
- 更新应用
3. 设置/准备工作
在开始学习本教程的主要部分之前,让我们设置项目、获取代码,然后部署基准应用,以便我们知道我们从工作代码开始。
1.设置项目
如果您已完成第 2 单元 Codelab,我们建议您重复使用同一项目(和代码)。或者,您可以创建一个全新的项目或重复使用另一个现有项目。确保该项目具有有效的结算账号,并且已启用 App Engine(应用)。
2. 获取基准示例应用
前提条件之一是拥有有效的模块 2 示例应用。如果您已完成该教程,请使用您的解决方案。您可以立即完成(上面的链接),如果想要跳过,请复制第 2 单元的代码库(链接如下)。
无论您使用我们的代码还是我们的代码,我们都将从第 2 单元的代码开始。第 3 单元 Codelab 将逐步引导您完成每个步骤,完成后,它应该类似于“完成”处的代码。本教程提供 Python 2 和 Python 3 版本,因此请从下面获取正确的代码库。
Python 2
Python 2 模块 2 启动文件(您或我们的文件)的目录应如下所示:
$ ls
README.md appengine_config.py requirements.txt
app.yaml main.py templates
如果您已完成第 2 单元的教程,还会得到一个包含 Flask 及其依赖项的 lib
文件夹。如果您没有 lib
文件夹,请使用 pip install -t lib -r requirements.txt
命令创建该文件夹,以便我们在下一步中部署此基准应用。如果您同时安装了 Python 2 和 Python 3,我们建议您使用 pip2
(而不是 pip
),以避免与 Python 3 混淆。
Python 3
Python 3 第 2 单元开始文件(您自己的或我们的)的目录应如下所示:
$ ls
README.md main.py templates
app.yaml requirements.txt
lib
和 appengine_config.py
均不用于 Python 3。
3. (重新)部署模块 2 应用
现在需要执行的其余准备工作步骤:
- 熟悉
gcloud
命令行工具(必要的话) - (重新)将模块 1 代码部署到 App Engine(必要的话)
当您成功执行这些步骤并确认操作有效后,我们将在本教程中进行本教程,从配置文件开始。
4. 将 Cloud NDB 替换为 Cloud Datastore 客户端库
唯一的配置更改是 requirements.txt
文件中的次要软件包交换。
1. 更新 requirements.txt
完成模块 2 后,您的 requirements.txt
文件将如下所示:
- 之前(Python 2 和 3):
Flask==1.1.2
google-cloud-ndb==1.7.1
通过将 Cloud NDB 库 (google-cloud-ndb
) 替换为最新版本的 Cloud Datastore 库 (google-cloud-datastore
) 来更新 requirements.txt
,使 Flask 的条目保持不变,但请注意,与 Python 2 兼容的最终 Cloud Datastore 版本是 1.15.3:
- 之后 (Python 2):
Flask==1.1.2
google-cloud-datastore==1.15.3
- 之后 (Python 3):
Flask==1.1.2
google-cloud-datastore==2.1.0
请注意,代码库的维护频率比本教程更高,因此 requirements.txt
文件可能会反映更新的版本。我们建议使用每个库的最新版本,但如果这些库无法正常运行,您可以回滚到旧版本。上面的版本号是此 Codelab 上次更新时的最新版本号。
2. 其他配置文件
其他配置文件(app.yaml
和 appengine_config.py
)应与先前迁移步骤保持不变:
app.yaml
应(仍)引用第三方捆绑软件包grpcio
和setuptools
。appengine_config.py
应(仍)将pkg_resources
和google.appengine.ext.vendor
指向lib
中的第三方资源。
现在,我们来看看应用文件。
5. 更新应用文件
template/index.html
没有任何变化,但 main.py
有几项更新。
1. 导入
导入部分的起始代码应如下所示:
- 之前:
from flask import Flask, render_template, request
from google.cloud import ndb
将 google.cloud.ndb
导入替换为 Cloud Datastore 的导入:google.cloud.datastore
。由于 Datastore 客户端库不支持在 Entity 中自动创建时间戳字段,因此还应导入标准库 datetime
模块,以手动创建一个字段。按照惯例,标准库导入高于第三方软件包导入。完成这些更改后,它应如下所示:
- 之后:
from datetime import datetime
from flask import Flask, render_template, request
from google.cloud import datastore
2. 初始化和数据模型
初始化 Flask 后,第 2 单元的示例应用创建一个 NDB 数据模型类及其字段 lok,如下所示:
- 之前:
app = Flask(__name__)
ds_client = ndb.Client()
class Visit(ndb.Model):
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
Cloud Datastore 库没有这样的类,因此请删除 Visit
类声明。您仍然需要一个客户端才能与 Datastore 通信,因此请将 ndb.Client()
更改为 datastore.Client()
。数据存储区库更“灵活”无需“预先声明”即可创建实体,结构,例如 NDB。完成此更新后,main.py
的这一部分应如下所示:
- 之后:
app = Flask(__name__)
ds_client = datastore.Client()
3. Datastore 访问权限
迁移到 Cloud Datastore 需要更改(在用户级)创建、存储和查询 Datastore 实体的方式。对于您的应用,此迁移的难度取决于 Datastore 代码的复杂程度。在示例应用中,我们尝试使更新尽可能简单明了。我们的起始代码如下:
- 之前:
def store_visit(remote_addr, user_agent):
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
with ds_client.context():
return (v.to_dict() for v in Visit.query().order(
-Visit.timestamp).fetch_page(limit)[0])
使用 Cloud Datastore 创建一个通用实体,使用“键”识别该实体中已分组的对象。使用键值对的 JSON 对象 (Python dict
) 创建数据记录,然后使用预期的 put()
将其写入 Datastore。Datastore 的查询与此类似,但更为直接。下面介绍了等效的 Datastore 代码的不同之处:
- 之后:
def store_visit(remote_addr, user_agent):
entity = datastore.Entity(key=ds_client.key('Visit'))
entity.update({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
ds_client.put(entity)
def fetch_visits(limit):
query = ds_client.query(kind='Visit')
query.order = ['-timestamp']
return query.fetch(limit=limit)
如上所述,更新 store_visit()
和 fetch_visits()
的函数正文,使其签名与上一个版本相同。主处理程序 root()
没有任何更改。完成这些更改后,您的应用就可以使用 Cloud Datastore 了,可以进行测试了。
6. 摘要/清理
部署应用
使用 gcloud app deploy
重新部署您的应用,并确认应用能正常运行。您的代码现在应与模块 3 代码库文件夹中的内容相匹配:
如果您跳过本系列,但未执行任何上述 Codelab,则应用本身不会更改;它会记录对主网页 (/
) 的所有访问,在您访问过该网站后,将如下所示:
恭喜您完成此 Codelab 第 3 单元。您现在已经知道,可以同时使用 Cloud NDB 和 Cloud Datastore 客户端库来访问 Datastore。现在,迁移到后者可为您带来诸多好处,包括共享库、通用代码和代码重复使用,以确保一致性并降低维护成本。
可选:清理
何不准备好清理,以避免在进入下一个迁移 Codelab 时继续计费?作为现有开发者,您应该已经了解了 App Engine 的价格信息。
可选:停用应用
如果您尚未准备好学习下一个教程,请停用您的应用,以免产生费用。当您准备好继续学习下一个 Codelab 时,可以重新启用它。应用停用期间,不会产生任何流量费用。不过,如果您的 Datastore 用量超出免费配额,您需要另外付费,因此请删除足够多的流量,使其不超过该限额。
另一方面,如果您不继续迁移并希望彻底删除所有内容,可以关停项目。
后续步骤
在这里,您可以随意浏览接下来的迁移模块:
- 单元 3 额外知识点:继续学习奖章部分,了解如何移植到 Python 3 和下一代 App Engine 运行时。
- 模块 7:App Engine 推送任务队列(如果您使用 [推送] 任务队列,此为必需参数)
- 向模块 1 应用添加了 App Engine
taskqueue
推送任务 - 在第 8 单元中,帮助用户做好迁移到 Cloud Tasks 的准备
- 向模块 1 应用添加了 App Engine
- 第 4 单元:迁移到 Cloud Run with Docker
- 使用 Docker 将应用容器化,以便在 Cloud Run 上运行
- 让您可以继续使用 Python 2
- 模块 5:使用 Cloud Buildpack 迁移到 Cloud Run
- 使用 Cloud Buildpack 将应用容器化,以便在 Cloud Run 上运行
- 无需了解 Docker、容器或
Dockerfile
的任何知识 - 要求您已将应用迁移到 Python 3
- 模块 6:迁移到 Cloud Firestore
- 迁移到 Cloud Firestore 以使用 Firebase 功能
- 虽然 Cloud Firestore 支持 Python 2,但此 Codelab 仅在 Python 3 中提供。
7. 额外好处:迁移到 Python 3
要使用最新的 App Engine 运行时和功能,我们建议您迁移到 Python 3。在我们的示例应用中,Datastore 是我们使用的唯一内置服务,而且自从我们已从 ndb
迁移到 Cloud NDB,我们现在就可以移植到 App Engine 的 Python 3 运行时。
概览
虽然移植到 Python 3 不在 Google Cloud 教程的范围内,但 Codelab 的这一部分可帮助开发者了解 Python 3 App Engine 运行时的不同之处。新一代运行时的一个突出功能是简化对第三方软件包的访问:无需在 app.yaml
中指定内置软件包,也无需复制或上传非内置库;它们是通过在 requirements.txt
中列出的隐式安装的。
由于我们的示例非常基本,并且 Cloud Datastore 与 Python 2-3 兼容,因此应用代码无需明确移植到 3.x:该应用在 2.x 和 3.x 上运行且未经修改,这意味着在这种情况下,所需的更改仅是在配置中:
- 简化了
app.yaml
以引用 Python 3,并移除对捆绑的第三方库的引用。 - 删除
appengine_config.py
和lib
文件夹,因为它们不再需要。
main.py
和 templates/index.html
应用文件保持不变。
更新 requirements.txt
支持 Python 2 的最终 Cloud Datastore 版本是 1.15.3。将 requirements.txt
更新为 Python 3 的最新版本(现在可能较新版本)。在编写本教程时,最新版本为 2.1.0,因此请将该行修改为以下内容(或任何最新版本):
google-cloud-datastore==2.1.0
简化 app.yaml
之前:
此示例应用的唯一实际更改是大幅缩短了 app.yaml
。请注意,以下是我们在第 3 单元结束时的 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
之后:
在 Python 3 中,threadsafe
、api_version
和 libraries
指令都已废弃;所有应用都假定为线程安全应用,并且 api_version
未在 Python 3 中使用。App Engine 服务中不再预安装内置的第三方软件包,因此也废弃了 libraries
。如需详细了解这些变更,请参阅有关 app.yaml
变更的文档。因此,您应从 app.yaml
中删除所有这三个版本,并更新到受支持的 Python 3 版本(见下文)。
可选:使用 handlers
指令
此外,用于将流量引导到 App Engine 应用的 handlers
指令也已被弃用。由于下一代运行时需要 Web 框架管理应用路由,因此所有“处理程序脚本”必须更改为“auto
”。结合上述更改,您得到了以下 app.yaml
:
runtime: python38
handlers:
- url: /.*
script: auto
如需详细了解 script: auto
,请参阅 app.yaml
参考页面。
移除 handlers
指令
由于 handlers
已废弃,因此您也可以移除整个部分,只留下单行 app.yaml
:
runtime: python38
默认情况下,这将启动 Gunicorn WSGI Web 服务器,该服务器适用于所有应用。如果您熟悉 gunicorn
,以下是默认情况下使用准系统 app.yaml
启动时执行的命令:
gunicorn main:app --workers 2 -c /config/gunicorn.py
可选:使用 entrypoint
指令
不过,如果您的应用需要特定的启动命令(可以使用 entrypoint
指令指定),就会生成如下所示的 app.yaml
:
runtime: python38
entrypoint: python main.py
此示例明确要求使用 Flask 开发服务器,而不是 gunicorn
。此外,您还必须将启动开发服务器的代码添加到应用中,以在端口 8080 上的 0.0.0.0
接口上启动,具体方法是将这小部分添加到 main.py
的底部:
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
如需详细了解 entrypoint
,请参阅 app.yaml
参考页面。如需查看更多示例和最佳做法,请参阅 App Engine 标准环境启动文档和 App Engine 柔性环境启动文档。
删除 appengine_config.py
和 lib
删除 appengine_config.py
文件和 lib
文件夹。在迁移到 Python 3 时,App Engine 会获取并安装 requirements.txt
中列出的软件包。
appengine_config.py
配置文件用于识别第三方库/软件包,无论您是自己复制的,还是使用 App Engine 服务器(内置)上已有的库/软件包。迁移到 Python 3 后,重大变更的摘要如下:
- 没有捆绑复制的第三方库(列在
requirements.txt
中) - 没有
pip install
到lib
文件夹中,即无lib
文件夹期限 - 未在
app.yaml
中列出内置的第三方库 - 无需将应用引用到第三方库,因此不需要
appengine_config.py
文件
只需在 requirements.txt
中列出所有必需的第三方库即可。
部署应用
重新部署您的应用,确保其可以正常运行。您还可以确认您的解决方案与模块 3 示例 Python 3 代码有多接近。如需直观呈现与 Python 2 之间的差异,请将该代码与其 Python 2 版本进行比较。
恭喜您完成第 3 单元中的奖励步骤!访问关于为 Python 3 运行时准备配置文件的文档。最后,请查看上文的摘要,了解后续步骤和清理。
准备您的应用
当需要迁移应用时,您必须将 main.py
和其他应用文件移植到 3.x,因此,最佳做法是尽量编写 2.x 版应用以“向前兼容”的方式传送。
网上有很多资源可以帮助您实现这个目标,但其中一些要点如下:
- 确保所有应用依赖项均与 3.x 完全兼容
- 确保您的应用至少在 2.6 版(最好是 2.7 版)上运行
- 确保应用通过整个测试套件的测试(覆盖率至少达到 80%)
- 使用兼容性库,例如
six
、Future 和/或 Modernize - 了解 2.x 与 3.x 向后不兼容的关键区别
- 任何 I/O 都可能导致 Unicode 与字节字符串不兼容
设计示例应用时要牢记所有这些,因此为什么该应用可以直接在 2.x 和 3.x 上运行,所以我们可以集中精力向您展示使用下一代平台需要更改的内容。
8. 其他资源
App Engine 迁移模块 Codelab 问题/反馈
如果您在此 Codelab 中发现任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:
迁移时可参考的资源
下表列出了模块 2(START)和模块 3 (FINISH) 对应的代码库文件夹的链接。您还可以从所有 App Engine 迁移的代码库访问这些迁移项目,您可以克隆或下载 ZIP 文件。
Codelab | Python 2 | Python 3 |
模块 3 |
App Engine 资源
以下是有关此特定迁移的其他资源:
- Python Cloud NDB 和 Cloud Datastore 参考
- 迁移到 Python 3 和 GAE 下一代运行时
- 常规