解决 AWS CDK CloudFormation 堆栈之间的循环依赖关系

use*_*256 8 amazon-web-services aws-cloudformation aws-cdk

上下文,我有一个带有两个堆栈的 CDK 应用程序,使用以下设置:

Stack_A:
    StateMachine_A
    Lambda_A
    S3Bucket_A
    IAMRole_A

Stack_B:
    StateMachine_B
    SageMakerTrainJob_B
    IAMRole_B
Run Code Online (Sandbox Code Playgroud)

StateMachine_A 使用执行角色 IAMRole_A 运行 Lambda_A。StateMachine_A 中的一个单独步骤将数据写入 S3Bucket_A。StateMachine_B 使用执行角色 IAMRole_B 运行 SageMakerTrainJob_B。Lambda_A 的目的是开始执行 StateMachine_B,其 SageMakerTrainJob_B 需要从 S3Bucket_A 读取。因此,我们必须配置以下权限:

  • IAMRole_A 需要 StateMachine_B 的 startExecution 权限。
  • IAMRole_B 需要对 S3Bucket_A 的读取权限。

我们尝试通过在 Stack_B 中创建一个对 Stack_A 的直接依赖,在 Stack_B 的定义中使用对 IAMRole_A 和 S3Bucket_A 的引用来在代码中授予所需的权限,从而在 CDK 中对此进行建模。但是,这产生了以下错误:

Error: 'Stack_B' depends on 'Stack_A' (dependency added using stack.addDependency()). Adding this dependency (Stack_A -> Stack_B/IAMRole_B/Resource.Arn) would create a cyclic reference.

同样,尝试对另一个方向的依赖项进行建模也会出现相同的错误:

Error: 'Stack_A' depends on 'Stack_B' (dependency added using stack.addDependency()). Adding this dependency (Stack_B -> Stack_A/S3Bucket_A/Resource.Arn) would create a cyclic reference.

有没有办法使用代码依赖来解决这个问题?对于这种情况,是否有任何推荐的最佳做法?我们考虑过的一些选项包括:

  • 使用依赖于两者的第三个堆栈来让 Stack_A 和 Stack_B 访问彼此的资源。
  • 为每个堆栈中的必要资源创建额外的访问角色,并为 CDK 之外某处的 Lambda/SageMaker 角色维护代入角色权限。
  • 将它们全部放在一个堆栈中。不利于组织并使资源真正紧密耦合——我们可能不希望 StateMachine_A 成为未来 StateMachine_B 的唯一入口点。

此外,我发现在使用CodeCommit/CodePipelineAPIGateway/Lambda 的CDK 开发过程中也存在类似的问题。这是一个相关的错误,还是我们只是试图做一些不受支持的事情?

Jas*_*rth 7

循环引用总是很棘手。这不是 CDK 独有的问题。当你从逻辑上解释问题时,你会看到事情开始崩溃的地方。CloudFormation 必须先创建另一个资源所依赖的任何资源,然后才能创建依赖资源。没有一种解决方案适合所有方法,但我会给出一些可行的想法。

  1. 将共享资源提升到另一个堆栈。在您的情况下,两个堆栈都需要使用 S3 存储桶,因此如果它位于在您可以创建 S3 存储桶之前运行的堆栈中,请使用堆栈 B 中的导出/导入来引用 S3 存储桶,并使用和导出/import 在堆栈 A 中引用 S3 存储桶和 B 中的状态机。
  2. 在权限中使用通配符。通常,您可以知道资源的名称或足够多的名称以在您的权限中使用通配符。您希望严格限定权限范围,但通常部分名称匹配就足够了。当然,请谨慎使用此选项。还要记住,许多资源可以由您命名。许多人不喜欢这样做,有些资源你不应该这样做(比如和 S3 存储桶),但我经常发现命名更容易。
  3. 创建自定义资源以将事物联系在一起。如果您有一个无法解决的真正循环依赖(即使在同一个堆栈中),您可能需要使用自定义资源来为您完成工作。这方面的一个主要例子是S3 存储桶事件