CDK:可以将为 EdgeFunction 资源创建的堆栈放在另一个(跨区域)堆栈中吗?

CDK: Possible to put the stack created for EdgeFunction resource in another (cross-region) stack?

问题陈述

我在 eu-west-1 中有我的主要 CDK 堆栈,但在 us-east-1 中创建了一个 EdgeFunction

我注意到 EdgeFunction 有两个奇怪的地方:

  1. 即使在 NestedStack 中声明,它们也会在 cdk ls 中显示为 edge-lambda-stack-nnnnnnnnn(除非给出明确的名称)。
  2. 删除主堆栈时,我们称之为 primary,它不会删除 lambda 堆栈。可能是因为上面的 (1) 告诉我它不是 NestedStack.
  3. 的一部分

我曾尝试将 EdgeFunction 明确地放在 us-east-1 中创建的单独堆栈中,然后从 primary 交叉引用它,但失败并显示“无法在交叉中使用资源” -环境时尚”(以及其他)。

问题

我问的原因是因为我有很多环境和很多 lambda,堆栈的组合爆炸让事情变得有点笨拙。

例子

CDK 版本 1.116

import "source-map-support/register";
import * as cdk from "@aws-cdk/core";
import * as cloudfront from "@aws-cdk/aws-cloudfront";
import * as lambda from "@aws-cdk/aws-lambda";
import * as path from "path";

class PrimaryStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
        new SecondaryStack(this, "secondary-stack");
    }
}

class SecondaryStack extends cdk.NestedStack {
    constructor(scope: cdk.Construct, id: string) {
        super(scope, id);

        new cloudfront.experimental.EdgeFunction(this, "my-lambda", {
            runtime: lambda.Runtime.NODEJS_14_X,
            functionName: "my-lambda",
            handler: "index.handler",
            code: lambda.Code.fromAsset(
                path.join(__dirname, "..", "lib", "my-lambda"),
            ),
        });
    }
}


const app = new cdk.App();

new PrimaryStack(app, "primary", {
    env: { account: "123", region: "eu-west-1" },
});

cdk ls 输出:

edge-lambda-stack-cnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
primary

我与 AWS 高级支持人员进行了交谈,得到的答复是 CDK 似乎无法通过使用嵌套堆栈来处理此问题。

相反,在 us-east-1 中为 EdgeLambdas 创建一个单独的堆栈,然后将 lambdas 的 ARN 导出到 SSM。

在另一个堆栈中,import the ARNs from SSM and use those

这将导致要处理的堆栈数量最少。您仍然需要分别部署这两个堆栈。

我最终使用的代码如下所示:

export function exportLambdaSsm(
    func: cloudfront.experimental.EdgeFunction,
): ssm.StringParameter {
    const funcName = // ...
    return new ssm.StringParameter(this, `${funcName}-param`, {
        // Parameter with slash must start with a slash
        parameterName: `/${funcName}`,
        stringValue: func.functionArn,
    });
}

export function importLambdaFromSsm(stack: Stack): lambda.IVersion {
    const funcName = // ...
    const funcResource = new cr.AwsCustomResource(stack, `${funcName}-param`, {
        policy: cr.AwsCustomResourcePolicy.fromStatements([
            new iam.PolicyStatement({
                effect: iam.Effect.ALLOW,
                actions: ["ssm:GetParameter*"],
                resources: [
                    stack.formatArn({
                        service: "ssm",
                        region: "us-east-1",
                        resource: "parameter",
                        resourceName: funcName,
                    }),
                ],
            }),
        ]),
        onUpdate: {
            // will also be called for a CREATE event
            service: "SSM",
            action: "getParameter",
            parameters: {
                Name: `/${funcName}`,
            },
            region: "us-east-1",
            // Update physical id to always fetch the latest version
            physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString()),
        },
    });

    return lambda.Version.fromVersionArn(stack, funcName, funcResource.getResponseField("Parameter.Value"));
}

请注意,在获取和存储 SSM 值时,有很多关于斜线位置的规则。我试图保持上面的代码正确。