在 Python 中使用 AWS CDK - AWS Cloud Development Kit (AWS CDK) v2

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

在 Python 中使用 AWS CDK

Python 是一种 AWS Cloud Development Kit (AWS CDK) 完全支持的且视为稳定的客户端语言。在 Python 中使用 AWS CDK 采用了熟悉的工具,包括标准 Python 实现(CPython)、带 virtualenv 的虚拟环境和 Python 包安装程序 pip。通过 pypi.org 来分发构成 AWS 构造库的模块。AWS CDK 的 Python 版本甚至使用了 Python 风格的标识符(例如,snake_case 方法名称)。

您可以使用任何编辑器或 IDE。许多 AWS CDK 开发人员都使用 Visual Studio 代码(或其开源等效版本 VSCodium),该编辑器通过官方扩展为 Python 提供良好的支持。Python 附带的 IDLE 编辑器足以帮助您入门。AWS CDK 的 Python 模块确实有类型提示,这些提示对于支持类型验证的检查工具或 IDE 非常有用。

开始使用 Python

要使用 AWS CDK,您必须拥有 AWS 账户和凭证,并已安装 Node.js 和 AWS CDK Toolkit。请参阅 开始使用 AWS CDK

Python AWS CDK 应用程序需要使用 Python 3.6 或更高版本。如果尚未安装,请在 python.org 上为您的操作系统下载兼容版本。如果您运行的是 Linux,则您的系统自带兼容版本,或者您可以使用发行版的包管理器(yumapt 等)进行安装。Mac 用户可能会对 Homebrew 感兴趣,这是一款适用于 macOS 的 Linux 风格的包管理器。

注意

第三方语言弃用:语言版本仅在供应商或社区共享其 EOL(生命周期终止)之前才受支持,如有更改,会另行通知。

还需要使用 Python 包安装程序 pip 和虚拟环境管理器 virtualenv。在 Windows 上安装兼容的 Python 版本需要使用这些工具。在 Linux 上,pipvirtualenv 可以在软件包管理器中作为单独的软件包进行提供。或者,您可以使用以下命令进行安装:

python -m ensurepip --upgrade python -m pip install --upgrade pip python -m pip install --upgrade virtualenv

如果遇到权限错误,请运行带有 --user 标志的上述命令,以便将模块安装在您的用户目录中,或者使用 sudo 来获取在系统范围内安装模块的权限。

注意

Linux 发行版通常使用可执行文件名称 python3 表示 Python 3.x,使用 python 表示 Python 2.x 安装。有些发行版有一个可以安装的可选包,可让 python 命令表示 Python 3。如果失败,您可以通过在项目的主目录中编辑 cdk.json 来调整用于运行应用程序的命令。

注意

在 Windows 上,您可能需要使用 py 可执行文件(适用于 Windows 的 >Python 启动器)来调用 Python(和 pip)。除此之外,启动器还允许您轻松指定要使用的 Python 安装版本。

如果在命令行键入 python 后会显示一条关于从 Windows 应用商店安装 Python 的消息,即使安装了 Windows 版本的 Python,也请打开 Windows 的“管理应用程序执行别名”设置面板并关闭 Python 的两个应用程序安装程序条目。

创建项目

您可以通过在空目录中调用 cdk init 来创建一个新的 AWS CDK 项目。使用 --language 选项并指定 python

mkdir my-project cd my-project cdk init app --language python

cdk init 使用项目文件夹的名称来命名项目的各种元素,包括类、子文件夹和文件。文件夹名称中的连字符都将转换为下划线。但是,名称应遵循 Python 标识符的形式;例如,名称不应以数字开头,也不应包含空格。

要使用新项目,请激活其虚拟环境。这允许将项目的依赖项安装在本地项目文件夹中,而不是全局安装。

source .venv/bin/activate
注意

您可将其视为用于激活虚拟环境的 Mac/Linux 命令。Python 模板包含一个批处理文件 source.bat,该文件允许在 Windows 上使用相同的命令。也可以使用传统的 Windows 命令 .\venv\Scripts\activate

如果您使用 CDK Toolkit v1.70.0 或更早版本来初始化 AWS CDK 项目,则您的虚拟环境位于 .env 目录中,而不是 .venv

重要

无论何时开始处理项目,都要激活该项目的虚拟环境。否则,您将无法访问安装在那里的模块,并且您安装的模块将进入 Python 全局模块目录(或将导致权限错误)。

首次激活虚拟环境后,请安装应用程序的标准依赖项:

python -m pip install -r requirements.txt

管理 AWS 构造库模块

使用 Python 软件包安装程序 pip 来安装和更新供您应用程序使用的 AWS 构造库模块以及您需要的其他软件包。pip 还会自动安装这些模块的依赖项。如果您的系统无法识别 pip 为独立命令,请将 pip 作为 Python 模块进行调用,如下所示:

python -m pip PIP-COMMAND

大多数 AWS CDK 构造都在 aws-cdk-lib 中。实验性模块位于名称类似于 aws-cdk.SERVICE-NAME.alpha 的单独模块中。服务名称包含 aws 前缀。如果您不确定某个模块的名称,请在 PyPI 上进行搜索。例如,以下命令可安装 AWS CodeStar 库。

python -m pip install aws-cdk.aws-codestar-alpha

某些服务的构造位于多个命名空间中。例如,除 aws-cdk.aws-route53 之外,还有另外三个 Amazon Route 53 命名空间,aws-route53-targetsaws-route53-patternsaws-route53resolver

注意

CDK API Reference 的 Python 版本也显示了包名称。

用于将 AWS 构造库模块导入 Python 代码的名称如下所示。

import aws_cdk.aws_s3 as s3 import aws_cdk.aws_lambda as lambda_

在应用程序中导入 AWS CDK 类和 AWS 构造库模块时,我们建议采用以下做法。遵循这些准则将有助于让您的代码与其他 AWS CDK 应用程序保持一致并更易于理解。

  • 通常,从顶层 aws_cdk 中导入单个类。

    from aws_cdk import App, Construct
  • 如果您需要 aws_cdk 中的许多类,则可以使用 cdk 的命名空间别名,而不是导入单个类。避免同时执行这两项操作。

    import aws_cdk as cdk
  • 通常,使用短命名空间别名来导入 AWS 构造库。

    import aws_cdk.aws_s3 as s3

安装模块后,请更新项目的 requirements.txt 文件,其中列出了项目的依赖项。最好手动执行此操作,而不是使用 pip freezepip freeze 会捕获 Python 虚拟环境中安装的所有模块的当前版本,这在将项目捆绑到其他地方运行时非常有用。

但是,通常情况下,您的 requirements.txt 应该只列出顶级依赖项(您的应用程序直接依赖的模块),而不会列出这些库的依赖项。这种策略让更新依赖项变得更加简单。

您可以编辑 requirements.txt 以允许升级;只需将版本号前面的 == 替换为 ~= 即可升级到更高的兼容版本,或者完全删除版本要求以指定模块的最新可用版本。

适当编辑 requirements.txt 以允许升级后,可以随时发出以下命令来升级项目中已安装的模块:

pip install --upgrade -r requirements.txt

在 Python 中管理依赖项

在 Python 中,您可以在应用程序的 requirements.txt 或构造库的 setup.py 中输入依赖项来指定依赖项。然后使用 PIP 工具来管理依赖关系。通过以下方式之一来调用 PIP:

pip command options python -m pip command options

python -m pip 调用适用于大多数系统;pip 要求 PIP 的可执行文件位于系统路径上。如果 pip 不起作用,请尝试将其替换为 python -m pip

cdk init --language python 命令会为您的新项目创建一个虚拟环境。这样每个项目就都有自己的依赖项版本,还有一个基本 requirements.txt 文件。每次开始使用项目时,都必须运行 source .venv/bin/activate 来激活此虚拟环境。在 Windows 上,改为运行 .\venv\Scripts\activate

CDK 应用程序

下面是一个 requirements.txt 示例文件。由于 PIP 不具备依赖锁定功能,我们建议您使用 == 运算符为所有依赖项指定确切的版本,如下所示。

aws-cdk-lib==2.14.0 aws-cdk.aws-appsync-alpha==2.10.0a0

使用 pip install 来安装模块不会自动将其添加到 requirements.txt。必须自己动手添加。如果要升级到依赖项的更高版本,请在 requirements.txt 中编辑其版本号。

要在创建或编辑 requirements.txt 后安装或更新项目的依赖项,请运行以下命令:

python -m pip install -r requirements.txt
提示

pip freeze 命令以可写入文本文件的格式输出所有已安装依赖项的版本。这可以用作 pip install -r 的需求文件。此文件便于将所有依赖项(包括传递依赖项)固定到您测试过的确切版本。为避免以后升级软件包时出现问题,请为此使用单独的文件,例如 freeze.txt(不是 requirements.txt)。然后,在升级项目的依赖项时重新生成此文件。

第三方构造库

在库中,依赖项在 setup.py 中进行指定,以便应用程序使用包时会自动下载传递依赖项。否则,每个想要使用包的应用程序都需要将您的依赖项复制到其 requirements.txt 中。此处显示了一个示例 setup.py

from setuptools import setup setup( name='my-package', version='0.0.1', install_requires=[ 'aws-cdk-lib==2.14.0', ], ... )

要使用包进行开发,请创建或激活虚拟环境,然后运行以下命令。

python -m pip install -e .

尽管 PIP 会自动安装传递依赖项,但每个包只能安装一个副本。已选择依赖项树中指定的最高版本;应用程序对安装哪个版本的软件包始终拥有最终决定权。

Python 中的 AWS CDK 习语

语言冲突

在 Python 中,lambda 是一个语言关键字,因此不能将其用作 AWS Lambda 构造库模块或 Lambda 函数的名称。对于此类冲突,Python 的惯例是在变量名称中使用尾随下划线,如 lambda_ 所示。

按照惯例,AWS CDK 构造的第二个参数名为 id。在编写自己的堆栈和构造时,调用参数 id 会“掩盖”Python 内置函数 id(),该函数用于返回对象的唯一标识符。此函数并不常用,但是如果您在构造中碰巧需要它,请重命名该参数,例如 construct_id

参数和属性

所有 AWS 构造库类都使用三个参数进行实例化:在其中定义构造的 scope(构造树中的父级)、idprops(构造用于配置其创建的资源的键/值对捆绑包)。其他类和方法也使用“属性捆绑包”模式作为参数。

scopeid 应始终作为位置参数而不是关键字参数进行传递,因为如果构造接受名为 scopeid 的属性,其名称就会改变。

在 Python 中,props 表示为关键字参数。如果参数包含嵌套数据结构,则使用在实例化时采用其自身关键字参数的类来表示这些结构。同样的模式也适用于采用结构化参数的其他方法调用。

例如,在 Amazon S3 存储桶的 add_lifecycle_rule 方法中,transitions 属性是 Transition 实例的列表。

bucket.add_lifecycle_rule( transitions=[ Transition( storage_class=StorageClass.GLACIER, transition_after=Duration.days(10) ) ] )

扩展某个类或重写某种方法时,您可能希望接受父类无法理解的其他参数,以满足自己的目的。在这种情况下,您应该使用 **kwargs 习语来接受您不在意的参数,并使用仅限关键字的参数来接受您感兴趣的参数。在调用父级的构造函数或重写的方法时,请仅传递所需的参数(通常只是 **kwargs)。传递父类或方法不需要的参数会导致错误。

class MyConstruct(Construct): def __init__(self, id, *, MyProperty=42, **kwargs): super().__init__(self, id, **kwargs) # ...

AWS CDK 的未来版本可能会碰巧添加一个新属性,其名称与您用于自己属性的名称相同。这不会为您的构造或方法的用户带来任何技术问题(因为您的属性不会“向上沿链”传递,所以父类或重写的方法只会使用默认值),但可能会造成困惑。您可以对属性进行命名来避免这个潜在问题,这样它们就明确属于您的构造。如果有许多新属性,请将其捆绑到一个适当命名的类中,然后将其用作单个关键字参数进行传递。

缺失值

AWS CDK 使用 None 来表示缺失值或未定义的值。使用 **kwargs 时,如果未提供属性,则使用词典的 get() 方法提供默认值。避免使用 kwargs[...],因为这会引发缺失值的 KeyError

encrypted = kwargs.get("encrypted") # None if no property "encrypted" exists encrypted = kwargs.get("encrypted", False) # specify default of False if property is missing

某些 AWS CDK 方法(例如用于获取运行时上下文值的 tryGetContext())可能会返回 None,您需要进行明确检查。

使用接口

Python 不像其他一些语言那样具有接口功能,不过其确实有类似的抽象基类。(如果您不熟悉接口,维基百科中有很好的入门教程。) TypeScript 是实现 AWS CDK 的语言,其确实提供了接口,构造和其他 AWS CDK 对象通常需要一个遵循特定接口的对象,而不是从特定类继承。因此,AWS CDK 提供了自己的接口功能,作为 JSII 层的一部分。

要表示一个类实现了特定的接口,可以使用 @jsii.implements 装饰器:

from aws_cdk import IAspect, IConstruct import jsii @jsii.implements(IAspect) class MyAspect(): def visit(self, node: IConstruct) -> None: print("Visited", node.node.path)

类型陷阱

Python 使用动态类型,其中所有变量都可以表示任何类型的值。参数和返回值可以用类型进行注释,但这些是“提示”,不会强制执行。这意味着在 Python 中,很容易将错误类型的值传递给 AWS CDK 构造。与静态类型语言不同,您不会在构建期间收到类型错误,而是在 JSII 层(在 Python 和 AWS CDK 的 TypeScript 核心之间进行转换)无法处理意外类型时收到运行时错误。

根据我们的经验,Python 程序员犯的类型错误往往属于以下类别。

  • 在构造需要容器(Python 列表或词典)的地方传递单个值,反之亦然。

  • 将与第 1 层 (CfnXxxxxx) 构造关联的类型的值传递给 L2 或 L3 构造,反之亦然。

AWS CDK Python 模块确实包含类型注释,因此您可以使用支持类型注释的工具来帮助处理类型。如果您使用的不是支持这些类型注释的 IDE,例如 PyCharm,则可能需要调用 MyPy 类型的验证器作为构建过程中的一个步骤。还有一些运行时类型检查器,可以改进类型相关错误的错误消息。