在aws cdk中,如何将管道中的lambda连接到管道堆栈后写入的堆栈

In aws cdk, how to connect lambda in pipeline to stack written after pipeline stack

我正在使用此 code 创建到 lambda 的管道。 我能够在管道之前使用 vpc 在应用程序中创建堆栈并将其用于 lambda,但是当我尝试在管道之后将带有网关的堆栈放在应用程序中并将 lambda 作为授权方连接到它时,它试图部署 lambda堆栈,我得到 failed: Error: The following CloudFormation Parameters are missing a value: FirstLambdaLambdaSourceBucketNameParameter4BB158A3, FirstLambdaLambdaSourceObjectKeyParameter65E28DA5.

我知道这是因为这条线 const lambdaCode = lambda.Code.fromCfnParameters(); 并且参数填充发生在 lambdaCode.assign(lambdaBuildOutput.s3Location) 的管道中而不是在 lambda 中。

有什么解决方案而不是将所有代码都放在管道中吗?

编辑:

代码示例:

cdk.ts:

const lambdaPipelineStack = new LambdaPipelineStack(app, 'LambdaPipelineStack')
const connections = new ConnectionsStack(app, 'ConnectionsStack', {
    lambdaPipelineStack
})

管道 + lambda:

declare const vpc: ec2.Vpc

export class LambdaPipelineStack extends Stack {
    public readonly lambdasDeployStage: LambdasDeployStage
    constructor(scope: Construct, id: string, props: InfraStackProps) {
        super(scope, id, props)

        const pipeline = new CodePipeline(this, 'lambdasPipeline', {
            codeBuildDefaults: {
                rolePolicy: [
                    new PolicyStatement({
                        actions: ['sts:AssumeRole'],
                        resources: ['*'],
                        conditions: {
                            StringEquals: {
                                'iam:ResourceTag/aws-cdk:bootstrap-role': 'lookup'
                            }
                        }
                    })
                ]
            },
            dockerEnabledForSynth: true,
            selfMutation: true,
            synth: new ShellStep('Synth', {
                input: CodePipelineSource.connection('ORG/cdk', 'master', {
                    connectionArn: CONNECTION_ARN
                }),
                additionalInputs: {
                    spend: CodePipelineSource.connection('ORG/REPO', 'dev', {
                        connectionArn: CONNECTION_ARN
                    })
                },
                commands: ['npm ci', 'npm run build', 'npx cdk synth'],
                env: { vpcId: vpc.vpcId }
            })
        })

        this.lambdasDeployStage = new LambdasDeployStage(this, 'LambdaDeploy', props)
        pipeline.addStage(lambdasDeployStage)
    }
}

export class LambdasDeployStage extends Stage {
    public readonly lambdaStack: LambdasStack
    constructor(scope: Construct, id: string, props: StackProps) {
        super(scope, id, props)

        this.lambdaStack = new LambdasStack(this, 'LambdaStack', props)
    }
}
export class LambdasStack extends Stack {
    public readonly authorizerLambda: nodeLambda.NodejsFunction
    constructor(scope: Construct, id: string, props: StackProps) {
        super(scope, id, props)

        const vpcId = process.env.vpcId
        this.authorizerLambda = new nodeLambda.NodejsFunction(this, 'FirstLambda', {
            vpc: ec2.Vpc.fromLookup(this, 'Vpc', { vpcId }),
            vpcSubnets: {
                subnetType: SubnetType.PRIVATE_ISOLATED
            },
            entry: './lambda/functions/auth.js',
            handler: 'handler',
            runtime: lambda.Runtime.NODEJS_14_X
        })
    }
}

网关:

declare const localVpcLink: VpcLink
declare const cloudMapService: cloudmap.IService

export class ConnectionsStack extends Stack {
    constructor(scope: Construct, id: string, props: ConnectionStackProps) {
        super(scope, id, props)

        // GATEWAY
        const httpApi = new apigwv2.HttpApi(this, 'httpGW', {})
        const integration = new HttpServiceDiscoveryIntegration(
            'integration',
            cloudMapService,
            { vpcLink: localVpcLink }
        )

        const authorizer = new HttpLambdaAuthorizer('lambda-auth', props.lambdaPipelineStack.lambdasDeployStage.lambdaStack.authorizerLambda,, { responseTypes: [HttpLambdaResponseType.SIMPLE] })

        httpApi.addRoutes({
            path: '/ql',
            methods: [HttpMethod.ANY],
            integration,
            authorizer
        })
    }
}

你可以看到我在这段代码中做的不好是试图从阶段添加依赖到应用程序,因此得到 dependency cannot cross stage boundaries。我试图了解将管道与 lambda 堆栈连接到 App 堆栈的正确方法是什么(我可以使用服务管道做的事情)。

我的理解:您想在管道中部署 ConnectionsStackLambdasStack

当您使用管道部署堆栈时,堆栈是 cdk.Stage 的子级、PipelineStack 的孙级和 cdk.App 的曾孙级。管道可以有多个阶段。一个阶段可以有很多堆栈。管道(通常类似于构造)旨在随着需求的增加而多次修改和重新部署。在构思您的管道应用程序时考虑 App > Pipeline Stack > Stage > Stacks 层次结构。

您的顶级应用程序定义不在 OP 中,但我猜您没有正确组合。这是组成管道的惯用方法:

(1) 添加管道堆栈作为应用程序的入口点,as in the workshop:

// cdk.ts
const app = new cdk.App();
new LambdaPipelineStack(app, 'MyPipelineStack');

(2) 将应用程序的 2 个堆栈添加到舞台:

// deploy stage
export class LambdasDeployStage extends Stage {
    constructor(scope: Construct, id: string, props: StackProps) {
        super(scope, id, props)

        // refactor the lambdas stack property to expose the authorizerLambda Function
        // ConnectionStack should take a authorizerLambda: Function  as a prop instead of the whole lambda stack
        const { authorizerLambda } = new LambdasStack(this, 'LambdaStack', props)
        new ConnectionsStack(this, 'ConnectionsStack', {...props, authorizerLambda})
    }
}

(3) 将阶段添加到管道:您的 LambdaPipelineStack 正在正确组合!