导入现有 AWS CloudFormation 模板 - AWS Cloud Development Kit (AWS CDK) v2

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

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

导入现有 AWS CloudFormation 模板

使用cloudformation-include.CfnInclude构造将资源转换为 L1 结构,将资源从 AWS CloudFormation 模板导入到您的 AWS Cloud Development Kit (AWS CDK) 应用程序中。

导入后,您可以在应用程序中使用这些资源,方法与最初在 AWS CDK 代码中定义这些资源的方式相同。你也可以在更高级别 AWS CDK 的构造中使用这些 L1 结构。例如,这可以让你将 L2 权限授予方法与它们定义的资源一起使用。

cloudformation-include.CfnInclude构造本质上是为 AWS CloudFormation 模板中的任何资源添加 AWS CDK API包装器。使用此功能一次将现有 AWS CloudFormation 模板导入到 AWS CDK 一个片段中。通过这样做,你可以使用 AWS CDK 构造来管理现有资源,从而利用更高级别的抽象的好处。您还可以使用此功能通过提供 AWS CDK 构造API将 AWS CloudFormation 模板出售给 AWS CDK 开发人员。

注意

AWS CDK 还包括 v1 aws-cdk-lib.CfnInclude,它以前用于相同的通用用途。但是,它缺少的许多功能cloudformation-include.CfnInclude

导入 AWS CloudFormation 模板

以下是示例 AWS CloudFormation 模板,我们将使用该模板在本主题中提供示例。复制并保存模板,my-template.json以便后续操作。完成这些示例后,您可以使用任何现有已部署的 AWS CloudFormation 模板进一步探索。您可以从 AWS CloudFormation 控制台获取它们。

{ "Resources": { "MyBucket": { "Type": "AWS::S3::Bucket", "Properties": { "BucketName": "MyBucket", } } } }

您可以使用JSON或YAML模板中的任意一个。JSON如果可用,我们建议使用,因为YAML解析器接受的内容可能略有不同。

以下是如何使用将示例模板导入 AWS CDK 应用程序的示例cloudformation-include。模板是在CDK堆栈的上下文中导入的。

TypeScript
import * as cdk from 'aws-cdk-lib'; import * as cfninc from 'aws-cdk-lib/cloudformation-include'; import { Construct } from 'constructs'; export class MyStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const template = new cfninc.CfnInclude(this, 'Template', { templateFile: 'my-template.json', }); } }
JavaScript
const cdk = require('aws-cdk-lib'); const cfninc = require('aws-cdk-lib/cloudformation-include'); class MyStack extends cdk.Stack { constructor(scope, id, props) { super(scope, id, props); const template = new cfninc.CfnInclude(this, 'Template', { templateFile: 'my-template.json', }); } } module.exports = { MyStack }
Python
import aws_cdk as cdk from aws_cdk import cloudformation_include as cfn_inc from constructs import Construct class MyStack(cdk.Stack): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) template = cfn_inc.CfnInclude(self, "Template", template_file="my-template.json")
Java
import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import software.amazon.awscdk.cloudformation.include.CfnInclude; import software.constructs.Construct; public class MyStack extends Stack { public MyStack(final Construct scope, final String id) { this(scope, id, null); } public MyStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); CfnInclude template = CfnInclude.Builder.create(this, "Template") .templateFile("my-template.json") .build(); } }
C#
using Amazon.CDK; using Constructs; using cfnInc = Amazon.CDK.CloudFormation.Include; namespace MyApp { public class MyStack : Stack { internal MyStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var template = new cfnInc.CfnInclude(this, "Template", new cfnInc.CfnIncludeProps { TemplateFile = "my-template.json" }); } } }

默认情况下,导入资源会保留模板中资源的原始逻辑 ID。此行为适用于将 AWS CloudFormation 模板导入到 AWS CDK,其中IDs必须保留逻辑。 AWS CloudFormation 需要这些信息才能将这些导入的资源识别为 AWS CloudFormation 模板中的相同资源。

如果您正在为模板开发 AWS CDK 构造封装器,以便其他 AWS CDK 开发人员可以使用,请IDs改用 AWS CDK 生成新资源。通过这样做,可以在堆栈中多次使用该构造,而不会出现名称冲突。为此,请在导入模板false时将该preserveLogicalIds属性设置为。以下是 示例:

TypeScript
const template = new cfninc.CfnInclude(this, 'MyConstruct', { templateFile: 'my-template.json', preserveLogicalIds: false });
JavaScript
const template = new cfninc.CfnInclude(this, 'MyConstruct', { templateFile: 'my-template.json', preserveLogicalIds: false });
Python
template = cfn_inc.CfnInclude(self, "Template", template_file="my-template.json", preserve_logical_ids=False)
Java
CfnInclude template = CfnInclude.Builder.create(this, "Template") .templateFile("my-template.json") .preserveLogicalIds(false) .build();
C#
var template = new cfnInc.CfnInclude(this, "Template", new cfn_inc.CfnIncludeProps { TemplateFile = "my-template.json", PreserveLogicalIds = false });

要将导入的资源置于您的 AWS CDK 应用程序的控制之下,请将堆栈添加到App

TypeScript
import * as cdk from 'aws-cdk-lib'; import { MyStack } from '../lib/my-stack'; const app = new cdk.App(); new MyStack(app, 'MyStack');
JavaScript
const cdk = require('aws-cdk-lib'); const { MyStack } = require('../lib/my-stack'); const app = new cdk.App(); new MyStack(app, 'MyStack');
Python
import aws_cdk as cdk from mystack.my_stack import MyStack app = cdk.App() MyStack(app, "MyStack")
Java
import software.amazon.awscdk.App; public class MyApp { public static void main(final String[] args) { App app = new App(); new MyStack(app, "MyStack"); } }
C#
using Amazon.CDK; namespace CdkApp { sealed class Program { public static void Main(string[] args) { var app = new App(); new MyStack(app, "MyStack"); } } }

要验证堆栈中的 AWS 资源不会发生任何意想不到的更改,您可以执行差异。使用 AWS CDK CLIcdk diff命令并省略任何 AWS CDK特定的元数据。以下是 示例:

cdk diff --no-version-reporting --no-path-metadata --no-asset-metadata

导入 AWS CloudFormation 模板后,该 AWS CDK 应用程序应成为您导入资源的真实来源。要对资源进行更改,请在 AWS CDK 应用程序中对其进行修改,然后使用 AWS CDK CLIcdk deploy命令进行部署。

访问导入的资源

示例代码template中的名称代表导入的 AWS CloudFormation 模板。要从中访问资源,请使用对象getResource()的方法。要将返回的资源作为特定类型的资源进行访问,请将结果转换为所需的类型。在 Python 中或者,这不是必需 JavaScript的。以下是 示例:

TypeScript
const cfnBucket = template.getResource('MyBucket') as s3.CfnBucket;
JavaScript
const cfnBucket = template.getResource('MyBucket');
Python
cfn_bucket = template.get_resource("MyBucket")
Java
CfnBucket cfnBucket = (CfnBucket)template.getResource("MyBucket");
C#
var cfnBucket = (CfnBucket)template.GetResource("MyBucket");

从这个例子中,现在cfnBucket是该aws-s3.CfnBucket类的实例。这是代表相应 AWS CloudFormation 资源的 L1 结构。你可以像对待任何其他同类资源一样对待它。例如,您可以通过bucket.attrArn属性获取其ARN值。

要改为将 L1 CfnBucket 资源封装在 L2 aws-s3.Bucket实例中,请使用静态方法fromBucketArn()fromBucketAttributes()、或。fromBucketName()通常,该fromBucketName()方法最方便。以下是 示例:

TypeScript
const bucket = s3.Bucket.fromBucketName(this, 'Bucket', cfnBucket.ref);
JavaScript
const bucket = s3.Bucket.fromBucketName(this, 'Bucket', cfnBucket.ref);
Python
bucket = s3.Bucket.from_bucket_name(self, "Bucket", cfn_bucket.ref)
Java
Bucket bucket = (Bucket)Bucket.fromBucketName(this, "Bucket", cfnBucket.getRef());
C#
var bucket = (Bucket)Bucket.FromBucketName(this, "Bucket", cfnBucket.Ref);

其他 L2 构造也有类似的方法,用于从现有资源创建构造。

当你将 L1 构造封装在 L2 构造中时,它不会创建新的资源。从我们的示例来看,我们没有创建第二个 S3; 存储桶。相反,新Bucket实例封装了现有实例。CfnBucket

从示例中可以看出,现在bucket是一个 L2 Bucket 构造,其行为与任何其他 L2 构造类似。例如,您可以使用存储桶的便捷grantWrite()方法向 AWS Lambda 函数授予对该存储桶的写入权限。您不必手动定义必要的 AWS Identity and Access Management (IAM) 策略。以下是 示例:

TypeScript
bucket.grantWrite(lambdaFunc);
JavaScript
bucket.grantWrite(lambdaFunc);
Python
bucket.grant_write(lambda_func)
Java
bucket.grantWrite(lambdaFunc);
C#
bucket.GrantWrite(lambdaFunc);

替换参数

如果您的 AWS CloudFormation 模板包含参数,则可以在导入时使用parameters属性将其替换为构建时值。在以下示例中,我们将UploadBucket参数替换为 AWS CDK 代码中其他地方定义ARN的存储桶的参数。

TypeScript
const template = new cfninc.CfnInclude(this, 'Template', { templateFile: 'my-template.json', parameters: { 'UploadBucket': bucket.bucketArn, }, });
JavaScript
const template = new cfninc.CfnInclude(this, 'Template', { templateFile: 'my-template.json', parameters: { 'UploadBucket': bucket.bucketArn, }, });
Python
template = cfn_inc.CfnInclude(self, "Template", template_file="my-template.json", parameters=dict(UploadBucket=bucket.bucket_arn) )
Java
CfnInclude template = CfnInclude.Builder.create(this, "Template") .templateFile("my-template.json") .parameters(java.util.Map.of( // Map.of requires Java 9+ "UploadBucket", bucket.getBucketArn())) .build();
C#
var template = new cfnInc.CfnInclude(this, "Template", new cfnInc.CfnIncludeProps { TemplateFile = "my-template.json", Parameters = new Dictionary<string, string> { { "UploadBucket", bucket.BucketArn } } });

导入其他模板元素

您可以导入任何 AWS CloudFormation 模板元素,而不仅仅是资源。导入的元素将成为 AWS CDK 堆栈的一部分。要导入这些元素,请使用CfnInclude对象的以下方法:

这些方法中的每一个都返回一个表示特定 AWS CloudFormation 元素类型的类的实例。这些对象是可变的。您对它们所做的更改将显示在从 AWS CDK 堆栈生成的模板中。以下是从模板导入参数并修改其默认值的示例:

TypeScript
const param = template.getParameter('MyParameter'); param.default = "AWS CDK"
JavaScript
const param = template.getParameter('MyParameter'); param.default = "AWS CDK"
Python
param = template.get_parameter("MyParameter") param.default = "AWS CDK"
Java
CfnParameter param = template.getParameter("MyParameter"); param.setDefaultValue("AWS CDK")
C#
var cfnBucket = (CfnBucket)template.GetResource("MyBucket"); var param = template.GetParameter("MyParameter"); param.Default = "AWS CDK";

导入嵌套堆栈

您可以通过在导入嵌套堆栈的主模板时或稍后指定嵌套堆栈来导入它们。嵌套模板必须存储在本地文件中,但在主模板中作为NestedStack资源引用。此外, AWS CDK 代码中使用的资源名称必须与主模板中用于嵌套堆栈的名称相匹配。

鉴于主模板中的此资源定义,以下代码显示了如何双向导入引用的嵌套堆栈。

"NestedStack": { "Type": "AWS::CloudFormation::Stack", "Properties": { "TemplateURL": "https://my-s3-template-source.s3.amazonaws.com/nested-stack.json" }
TypeScript
// include nested stack when importing main stack const mainTemplate = new cfninc.CfnInclude(this, 'MainStack', { templateFile: 'main-template.json', loadNestedStacks: { 'NestedStack': { templateFile: 'nested-template.json', }, }, }); // or add it some time after importing the main stack const nestedTemplate = mainTemplate.loadNestedStack('NestedTemplate', { templateFile: 'nested-template.json', });
JavaScript
// include nested stack when importing main stack const mainTemplate = new cfninc.CfnInclude(this, 'MainStack', { templateFile: 'main-template.json', loadNestedStacks: { 'NestedStack': { templateFile: 'nested-template.json', }, }, }); // or add it some time after importing the main stack const nestedTemplate = mainTemplate.loadNestedStack('NestedStack', { templateFile: 'my-nested-template.json', });
Python
# include nested stack when importing main stack main_template = cfn_inc.CfnInclude(self, "MainStack", template_file="main-template.json", load_nested_stacks=dict(NestedStack= cfn_inc.CfnIncludeProps(template_file="nested-template.json"))) # or add it some time after importing the main stack nested_template = main_template.load_nested_stack("NestedStack", template_file="nested-template.json")
Java
CfnInclude mainTemplate = CfnInclude.Builder.create(this, "MainStack") .templateFile("main-template.json") .loadNestedStacks(java.util.Map.of( // Map.of requires Java 9+ "NestedStack", CfnIncludeProps.builder() .templateFile("nested-template.json").build())) .build(); // or add it some time after importing the main stack IncludedNestedStack nestedTemplate = mainTemplate.loadNestedStack("NestedTemplate", CfnIncludeProps.builder() .templateFile("nested-template.json") .build());
C#
// include nested stack when importing main stack var mainTemplate = new cfnInc.CfnInclude(this, "MainStack", new cfnInc.CfnIncludeProps { TemplateFile = "main-template.json", LoadNestedStacks = new Dictionary<string, cfnInc.ICfnIncludeProps> { { "NestedStack", new cfnInc.CfnIncludeProps { TemplateFile = "nested-template.json" } } } }); // or add it some time after importing the main stack var nestedTemplate = mainTemplate.LoadNestedStack("NestedTemplate", new cfnInc.CfnIncludeProps { TemplateFile = 'nested-template.json' });

您可以使用任一方法导入多个嵌套堆栈。导入主模板时,您需要提供每个嵌套堆栈的资源名称与其模板文件之间的映射。此映射可以包含任意数量的条目。要在初始导入后执行此操作,请为每个嵌套堆栈调用loadNestedStack()一次。

导入嵌套堆栈后,您可以使用主模板的getNestedStack()方法对其进行访问。

TypeScript
const nestedStack = mainTemplate.getNestedStack('NestedStack').stack;
JavaScript
const nestedStack = mainTemplate.getNestedStack('NestedStack').stack;
Python
nested_stack = main_template.get_nested_stack("NestedStack").stack
Java
NestedStack nestedStack = mainTemplate.getNestedStack("NestedStack").getStack();
C#
var nestedStack = mainTemplate.GetNestedStack("NestedStack").Stack;

getNestedStack()方法返回一个IncludedNestedStack实例。在此实例中,您可以通过stack属性访问 AWS CDK NestedStack实例,如示例所示。您也可以通过访问原始 AWS CloudFormation 模板对象includedTemplate,从中加载资源和其他 AWS CloudFormation 元素。