【问题标题】:Is it possible to deploy AWS CDK stacks from within a Lambda?是否可以从 Lambda 中部署 AWS CDK 堆栈?
【发布时间】:2020-03-05 23:41:35
【问题描述】:

我想使用 Lambda 函数部署 AWS CDK 堆栈。用例是支持与Trek10's Serverless CI/CD pipeline中描述的功能相似的功能,其中相关代码为here

简而言之,AWS CodePipelines 仅支持监听单个 Git 分支中的更改。我想收听与创建存储库和分支相关的 GitHub 事件,并创建 CodePipeline 实例以响应这些事件,以便每个 Git 存储库的每个分支都有一个管道。我想要一个 Lambda 来监听 GitHub 事件并创建 CDK 堆栈。 Trek10 示例使用 Python 并直接调用 CloudFormation。我希望 Lambda 更简单,并改用 CDK。

这是一个使用 Typescript 的简单 Lambda,它源自 AWS CDK issue

// index.ts
import {ScheduledEvent} from 'aws-lambda';
import {CloudFormationDeploymentTarget, DEFAULT_TOOLKIT_STACK_NAME} from 'aws-cdk/lib/api/deployment-target';
import {CdkToolkit} from 'aws-cdk/lib/cdk-toolkit';
import {AppStacks} from 'aws-cdk/lib/api/cxapp/stacks';
import {Configuration} from 'aws-cdk/lib/settings';
import {execProgram} from "aws-cdk/lib/api/cxapp/exec";
import * as yargs from 'yargs';
import {SDK} from 'aws-cdk/lib/api/util/sdk';
export const handleCloudWatchEvent = async (event: ScheduledEvent): Promise<void> => {
    try {
        const aws = new SDK();
        const argv = await yargs.parse(['deploy', '--app', 'bin/pipeline.js', '--staging', '/tmp', '--verbose', '--require-approval', 'never']);

        const configuration = new Configuration(argv);
        await configuration.load();
        const appStacks = new AppStacks({
            configuration,
            aws,
            synthesizer: execProgram,
        });

        const provisioner = new CloudFormationDeploymentTarget({ aws });
        const cli = new CdkToolkit({ appStacks, provisioner });
        const toolkitStackName = configuration.settings.get(['toolkitStackName']) || DEFAULT_TOOLKIT_STACK_NAME;

        await cli.deploy({
            stackNames: [],
            exclusively: argv.exclusively as boolean,
            toolkitStackName,
            roleArn: argv.roleArn as string,
            requireApproval: configuration.settings.get(['requireApproval']),
            ci: true,
            reuseAssets: argv['build-exclude'] as string[],
            sdk: aws
        });

        return;
    } catch (e) {
        console.error(e);
        return;
    }

};

但是,我收到上述问题中所述的错误:

ERROR   { Error: Cannot find module '../package.json'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at new SDK (/var/task/node_modules/aws-cdk/lib/api/util/sdk.ts:92:39)
    at Runtime.exports.handleCloudWatchEvent [as handler] (/resources/index.ts:204:21)
    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
    at process._tickCallback (internal/process/next_tick.js:68:7) code: 'MODULE_NOT_FOUND' }

我不想修补sdk.ts:https://github.com/aws/aws-cdk/blob/master/packages/aws-cdk/lib/api/util/sdk.ts#L92,因为这似乎是一个非常肮脏的解决方案,所以我正在寻找另一个解决方案。

从 Lambda 函数中调用 CDK 的最简单的工作示例是什么?

【问题讨论】:

  • @AliHabibzadeh 请问一个简单的例子是什么样的? lambda 是否将管道文件复制到某种形式的 npm 项目结构中,运行 aws sts assume-role 以获取凭据,然后针对该结构执行 npm run build &amp;&amp; cdk synth &amp;&amp; cdk deploy 并将这些凭据用作该子进程的环境变量?
  • 这里的另一个例子github.com/imyoungyang/cdk-in-lambda
  • 在下面查看我的答案以获取解决方案以及最近的 GitHub 示例。

标签: amazon-web-services aws-lambda aws-codepipeline aws-cdk


【解决方案1】:

您是如何最终打包 cdk 以在 lambda 中运行的?是通过层完成的还是有更简单的方法?

【讨论】:

  • 我发现 CDK 和 CloudFormation 对于我们的需求来说太不成熟了,所以我最终使用了调用 Terraform 的 lambda。
  • 非常适合我们的需求,只是想知道您是如何打包 Terraform 的? Lambda 层的大小限制为 256M,这可能会很痛苦......想法?
  • 我最终不得不重新审视这一点,所以将 CDK 打包到 Lambda 层的详细信息放在这里:stackoverflow.com/a/60399178/272023
【解决方案2】:

最近,我在 Lambda 中有一个 CDK 部署程序的理想用例,但找不到任何好的和完整的示例来说明如何做到这一点。 使用kadishmal example from CDK Github,我设法将 CDK 放入 Lambda 层,从那里删除 AWS SDK 模块(Lambda 已经拥有它),将其包含到 Lambda 中,然后从那里运行 CDK 部署/销毁。 Lambda 及其所有层的大小限制为 250mb,因此我还必须使用 Webpack 来优化构建大小。

Here a Github repository 有一个基本示例 - 一个部署 S3 存储桶并销毁它的堆栈模板。

【讨论】:

    【解决方案3】:

    我创建了this repository,它使用GradleDocker 使用5 分钟的方法将CDK 安装到目标位置,并将Lambda 层zip 文件安装在您的本地系统上,您可以直接使用该文件在AWS 中手动上传控制台或与 CDK 一起使用 ie。

    带有 NodeJS 运行时和附加层的示例 Lambda 处理程序函数可能类似于:

    exports.handler = async (event) => {
        const spawnSync = require('child_process').spawnSync;
        const process = spawnSync('cdk', ['--version'], {
            stdio: 'pipe',
            stderr: 'pipe'
        });
        console.log(process.status);
        console.log(process.stdout.toString());
    };
    

    【讨论】:

      猜你喜欢
      • 2020-07-08
      • 2020-08-12
      • 1970-01-01
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-18
      • 1970-01-01
      相关资源
      最近更新 更多