cdk基础概念

cdk

1. 基础环境安装

以node.js为运行环境:npm install -g aws-cdk,cdk –version

还需要有aws-cli运行环境:https://aws.amazon.com/cn/cli/,https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html

初始化cdk项目

1
2
3
mkdir cdk-python-test && cd cdk-python-test
cdk init app --language python
pip install -r requirements.txt

2. 基础概念

2.1 AWS CDK L1 / L2 / L3 层级 最全详解

前置说明:L = Level,层级的意思;这三层都是 AWS CDK 中创建 AWS 云资源的方式,本质都是帮你生成 AWS CloudFormation 模板,只是封装程度、开发效率、灵活性完全不同。


2.2 核心总纲

L1 < L2 < L3 ,封装程度越来越高、代码量越来越少、开发效率越来越高、灵活性越来越低

  • L1:最底层、最灵活、最繁琐,完全对应原生 CloudFormation
  • L2:最常用、首选、99% 的开发场景都用它,AWS 官方封装的高级 API,平衡效率和灵活度
  • L3:最高层、最便捷、封装到极致,官方预制的「完整业务场景解决方案」,开箱即用

2.3 为什么会有 L1/L2/L3 三层?

AWS CDK 的核心是 「基础设施即代码 (IaC)」,最终执行cdk synth后,都会生成一份标准的 AWS CloudFormation(CFN)模板(JSON/YAML),再由 CFN 帮你在 AWS 账号中创建 / 更新 / 删除资源。

而这三层的本质,就是 CDK 对「CFN 资源定义」的 三层封装

CFN 是 AWS 的底层资源编排引擎 → L1 是 CFN 的直译L2 是 L1 的封装优化L3 是 L2 的组合封装

类比:你要做番茄炒蛋 → L1 是 “自己种番茄、养鸡取蛋、切菜、炒蛋” → L2 是 “超市买切好的番茄 + 盒装蛋液,直接炒” → L3 是 “买预制番茄炒蛋,加热即食”


2.4 分层详解

所有代码案例都是创建 AWS S3 存储桶

2.4.1 L1 - 底层构造:CFN 原生资源 (CFN Resources)

2.4.1.1 定义

官方命名:CfnXXX → 所有 L1 资源类名全部以 Cfn 开头(CloudFormation 的缩写),这是识别 L1 的绝对标志

核心定义:CDK 对 AWS CloudFormation 模板的「1:1 直译、无任何封装」。AWS 有多少个 CFN 资源类型,CDK 就有多少个对应的 L1 类,所有属性、参数、配置项,和 CFN 模板里的字段完全一致、一字不差

核心特点:

优点极致灵活、无任何限制,能实现 AWS 所有资源的所有配置,包括一些极冷门的底层属性,L2/L3 做不到的配置都能靠 L1 实现。

缺点超级繁琐、开发效率极低、极易出错,需要你完全熟记 CFN 模板的字段名,代码量巨大,还要手动处理所有依赖关系(比如创建 EC2 需要先创建子网)。

数据特点:L1 的属性值,全部是原始字符串 / 数字,没有类型校验、没有默认值、没有自动填充,填错一个字段名就会部署失败。

2.4.1.2 代码案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 导入L1的S3桶构造器,类名固定:CfnBucket
import { CfnBucket } from 'aws-cdk-lib/aws-s3';
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class MyCdkStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);

// L1 创建S3桶 - 纯CFN直译,所有字段和CFN模板一致
new CfnBucket(this, 'MyL1Bucket', {
bucketName: 'my-l1-test-bucket-123456', // 必须手动写桶名,无默认值
accessControl: 'Private', // 权限必须手动指定,CFN原生字段
versioningConfiguration: { // 版本控制,嵌套对象也是CFN原生格式
status: 'Enabled'
}
});
}
}
2.4.1.3 使用场景
  1. 你需要配置某个 AWS 资源的 极冷门的底层属性,而这个属性在 L2/L3 中没有暴露出来;
  2. AWS 刚发布了新的服务 / 新的资源属性,L2/L3 还没来得及更新封装,只能先用 L1;
  3. 极少数需要极致定制化的场景,比如深度定制 CloudFormation 的高级功能。

结论:日常开发尽量少用 L1,除非迫不得已。


2.4.2 L2 - 主力构造:AWS 托管资源 (AWS Resources)

2.4.2.1 定义

官方命名:XXX → 所有 L2 资源类名无任何前缀,比如 S3 桶就是 Bucket,EC2 实例就是 Instance,Lambda 函数就是 Function,这是识别 L2 的绝对标志。

核心定义:AWS 官方基于 L1 封装的「高级 API」,是 CDK 的核心和主力,也是 AWS CDK 团队投入最多精力维护的部分。L2 对 L1 做了大量的 人性化优化、封装、增强,本质上 L2 的底层依然是调用 L1 实现,只是帮你做了所有脏活累活。

核心特点:

优点 1:极简开发,代码量骤减 - 大量属性提供合理的默认值,不用手动配置基础属性,比如创建 S3 桶默认就是私有、开启加密、自动生成唯一桶名;

优点 2:强类型校验 - 所有属性都是 TS 强类型,写错字段名 / 属性值,写代码时就会报错,不用等到部署时才发现问题;

优点 3:自动处理依赖关系 - 比如创建 Lambda 需要依赖 IAM 角色,L2 会自动帮你创建并绑定角色,不用手动写依赖;

优点 4:内置最佳实践 - 所有默认配置都遵循 AWS 的安全最佳实践,比如 S3 默认私有、IAM 权限最小化、自动开启加密;

优点 5:兼顾灵活性 - 既保留了常用的配置项,又提供了 addPropertyOverride() 方法,可以直接覆盖底层 L1 的属性,满足定制化需求;

优点 6:丰富的辅助方法 - 比如 S3 桶的 grantRead()grantWrite(),一行代码就能给 IAM 用户 / 角色授权,不用手动写复杂的 IAM 策略。

缺点:极少数极冷门的底层属性没有暴露,需要结合 L1 补充配置。

2.4.2.2 代码案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 文件名:cdk_python_test_stack.py
from aws_cdk import (
Stack,
aws_s3 as s3 # 导入S3模块
)
from constructs import Construct

class CdkPythonTestStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

# ========== L2 创建S3桶 写法1:最简写法(推荐) ==========
# L2类名:Bucket (无Cfn前缀),一行代码搞定!
s3.Bucket(self, "MyL2BucketSimple")

# ========== L2 创建S3桶 写法2:自定义配置(按需添加) ==========
# 有默认值的属性可以不用写,只配置你需要的自定义项,简洁优雅
s3.Bucket(
self,
"MyL2BucketCustom",
versioned=True, # 开启版本控制,简洁参数名
enforce_ssl=True, # 强制HTTPS访问,内置安全最佳实践
bucket_name="my-l2-python-bucket-123456789" # 可选自定义桶名
)

对比 L1:L1 需要写十几行代码的配置,L2 一行代码就能实现,而且更安全、更不易出错!

2.4.2.3 使用场景

所有日常开发场景,无脑选 L2!

不管是创建 S3、EC2、Lambda、DynamoDB、API Gateway、VPC 等任何 AWS 资源,优先用 L2,这是 AWS 官方推荐的最佳实践,也是 CDK 的核心价值所在。


2.4.3 L3 - 顶层构造:预制组件 / 模式 (Construct Libraries / Patterns)

2.4.3.1 定义

官方命名

无固定命名规则,一般是 「业务场景化的类名」,比如 LambdaRestApi(创建 Lambda+API Gateway 的完整 RESTful API)、ApplicationLoadBalancedFargateService(创建 ECS Fargate+ALB 的完整服务),也叫 CDK Patterns/Constructs

核心定义

AWS 官方 / 社区基于 L2 封装的「业务级预制组件」,是最高层级的封装,也被称为「**CDK 模式 (Patterns)**」。

L3 是把 多个关联的 L2 资源组合成一个完整的业务场景,比如:

创建一个「带负载均衡的 ECS 服务」需要:ALB+TargetGroup+ECS Cluster+ECS Service+IAM 角色 + 安全组 → L2 需要写几十行代码,L3 一行代码搞定。

创建一个「RESTful API 接口」需要:API Gateway+Lambda+IAM 角色 → L2 需要写多行代码,L3 一行代码搞定。

核心特点

优点 1:极致效率,开箱即用 - 一行代码 = 一套完整的业务解决方案,不用手动组合多个 L2 资源,不用处理资源间的依赖和关联,开发效率直接拉满;

优点 2:内置最佳实践 + 架构规范 - L3 的所有组件都遵循 AWS 的「Well-Architected」架构规范,比如高可用、容错、安全、性能优化,你不用懂底层架构细节,也能写出合规的代码;

优点 3:无冗余代码 - 完全屏蔽底层资源的细节,专注于业务逻辑,代码可读性极高。

缺点灵活性最低,L3 封装的是「通用场景」,如果你的业务场景是高度定制化的(比如特殊的权限策略、特殊的资源配置),L3 可能无法满足,需要回退到 L2 手动组合。

2.4.3.2 代码案例

这个案例是创建一个能对外访问的 API 接口,底层需要创建:API Gateway + Lambda 函数 + IAM 角色 + 权限绑定,L2 需要写 10 + 行代码,L3 一行搞定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 文件名:cdk_python_test_stack.py
from aws_cdk import (
Stack,
aws_lambda as _lambda, # 导入Lambda模块
aws_apigateway as apigw # 导入API Gateway模块
)
from constructs import Construct

class CdkPythonTestStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

# ========== 步骤1:先用L2创建一个Lambda函数(Python代码) ==========
my_lambda = _lambda.Function(
self,
"MyL2Lambda",
runtime=_lambda.Runtime.PYTHON_3_12, # 指定Python运行时版本
code=_lambda.Code.from_inline(
# Lambda的Python业务代码,内联写法,简单测试用
"def handler(event, context):\n return {'statusCode': 200, 'body': 'Hello AWS CDK L3 Python!'}"
),
handler="index.handler" # Lambda入口函数:文件名.函数名
)

# ========== L3 核心代码:一行创建完整的API Gateway + Lambda服务 ==========
# L3组件:LambdaRestApi 就是封装好的预制组件,一行搞定所有配置
apigw.LambdaRestApi(self, "MyL3Api", handler=my_lambda)

部署后,你会得到一个可直接访问的 HTTPS API 地址,所有底层资源都自动创建并配置好,这就是 L3 的威力!

2.4.3.3 使用场景
  1. 你的业务场景是 AWS 的通用架构模式:比如 Lambda+API Gateway、ECS+ALB、S3+CloudFront、DynamoDB+Lambda 等;
  2. 追求极致开发效率,不想手动组合多个 L2 资源;
  3. 对底层架构细节不熟悉,想直接复用 AWS 官方的最佳实践架构。

✅ 结论:能用 L3 的场景,优先用 L3,省下的时间可以专注于业务逻辑。


2.5 L1/L2/L3 核心对比表

层级 官方名称 类名特征 封装程度 代码量 开发效率 灵活性 核心优势 适用场景
L1 CFN 原生资源 Cfn开头 无封装(1:1 直译) 极低 ✅极致灵活 能实现所有配置 冷门属性、新功能、定制化底层需求
L2 AWS 托管资源 无任何前缀 高度封装(推荐) ✅极高 ✅平衡灵活与效率 强类型、默认值、最佳实践、辅助方法 99% 的日常开发场景,首选!
L3 预制组件 / Patterns 业务场景化命名 极致封装 极少 ✅天花板级 ❌灵活性低 一行代码 = 一套解决方案、内置架构规范 通用业务场景、追求极致效率

2.6 AWS CDK 三层使用的「黄金原则」

这是 AWS 官方推荐的、所有资深 CDK 开发者都遵循的原则,按这个原则写代码,永远不会出错,效率最高,代码最优雅,优先级从高到低:

原则 1:能用 L3,就优先用 L3

L3 是效率天花板,能帮你省掉大量的重复代码和踩坑,而且是官方最佳实践,稳赚不亏。

原则 2:L3 满足不了,就用 L2

L2 是 CDK 的核心,是平衡「效率」和「灵活度」的最优解,也是日常开发的主力,99% 的场景都能覆盖。

原则 3:L2 满足不了,再用 L1 补充

只有当 L2 没有暴露你需要的底层属性时,才用 L1 做补充配置,不要大面积用 L1 写代码,否则就失去了 CDK 的意义。

原则 4:混合使用完全没问题

CDK 的三层是完全兼容、可以无缝混合使用的,比如:用 L3 创建一套 API 服务,用 L2 配置细节,用 L1 补充一个冷门属性,这是最常见的写法。


2.7 补充 2 个高频问题

Q1:我怎么知道一个资源有没有 L3/L2 封装?

答:查 AWS CDK 的官方文档即可

  • L3 组件:在文档中搜索「Patterns」或直接搜业务场景名(比如 LambdaRestApi);
  • L2 资源:在文档中搜索对应的服务名(比如 S3 → Bucket,Lambda → Function);
  • L1 资源:在文档中搜索「Cfn + 服务名」(比如 CfnBucket,CfnInstance)。

Q2:用 L3 会不会被绑定死?如果后期需要定制化怎么办?

答:不会!L3 创建的所有底层资源,都可以通过属性获取到,然后用 L2 的方法做定制化修改,比如:

1
2
3
4
// L3创建API Gateway + Lambda
const api = new LambdaRestApi(this, 'MyL3Api', { handler: myLambda });
// 获取底层的API Gateway资源(L2),然后添加自定义配置
api.root.addMethod('POST'); // 给API添加POST方法,定制化需求

2.8 总结

  1. **L1 (CfnXXX)**:CFN 直译,最灵活、最繁琐,底层兜底用;
  2. **L2 (XXX)**:官方封装,主力首选,99% 场景用它,平衡效率和灵活度;
  3. **L3 (Patterns)**:场景化预制组件,效率天花板,通用场景优先用;
  4. 黄金原则L3 > L2 > L1,能用高层级就不用低层级;
  5. 核心价值:CDK 的三层封装,本质是「让你用最少的代码,写最合规、最高效的基础设施代码」,不用再像写 CFN 模板一样痛苦。

参考链接:

https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html#about-aws

https://docs.aws.amazon.com/cdk/v2/guide/home.html

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html

https://docs.aws.amazon.com/cdk/

https://github.com/aws/aws-cdk

https://constructs.dev/

https://github.com/aws-samples/aws-cdk-examples

https://catalog.us-east-1.prod.workshops.aws/workshops/10141411-0192-4021-afa8-2436f3c66bd8/en-US