【问题标题】:How to connect a CloudFormation Template with a Lambda Function that creates a new database on an Aurora PostgreSQL Instance in RDS?如何将 CloudFormation 模板与在 RDS 中的 Aurora PostgreSQL 实例上创建新数据库的 Lambda 函数连接?
【发布时间】:2020-06-16 00:39:13
【问题描述】:

希望你能帮上忙!

目标

我正在尝试在 AWS 上配置以下场景:

  1. 在 AWC CLI 中:调用 CloudFormation 模板以创建新堆栈。
  2. 在模板中:调用Lambda 函数。
  3. 在 Lambda 函数中:通过 pg 模块连接到 RDS 中的 Aurora PostgreSQL 实例。
  4. 在 PostgresSQL 中:创建一个新数据库。

短篇小说

一旦我将我的 Lambda 函数添​​加到默认 VPC,它就无法再将响应发送回 CloudFormation 并且堆栈卡在 CREATE_IN_PROGRESS 中。当我从 Lambda 函数的配置中删除 VPC 时,它可以工作。但是后来我不能再连接到像 RDS 数据库实例这样的另一个组件了。如何处理?

长篇大论

为了让它工作,我的第一步是手动连接到 PostgreSQL 并创建一个新数据库:

  1. 将默认安全组配置为允许所有入站和所有出站流量。不用担心,仅用于测试。我稍后会更改它。
  2. 将安全组添加到 RDS 实例以接受来自同一 VPC 中其他组件的流量。第 3 步所必需的。
  3. 创建了Cloud9 环境以访问 VPC 中的终端。连接到 PostgreSQL 数据库并创建数据库即可!

现在我的目标是通过 Lambda 函数创建一个新数据库:

  1. 手动创建了一个新的 Lambda 函数,包括一个具有基本 Lambda 授权的新角色。还向角色添加了AdministratorAccess。不用担心,再次仅用于测试。 Lambda 函数在 Node.js 12.x 上运行,超时时间为 15 秒。
  2. 将我的 Lambda 脚本和 pg 模块打包到一个 zip 文件中并上传。脚本如下所示:
const { Client } = require('pg');
exports.handler = async (event, context) => {
    var databaseName = event.DatabaseName;
    var dbSuperUser = event.DBSuperUser;
    var dbSuperPassword = event.DBSuperPassword;

    const dbClient = new Client({
        host: "<Database Instance Endpoint>",
        port: 5432,
        database: "postgres",
        user: dbSuperUser,
        password: dbSuperPassword
    });

    await dbClient.connect();
    await dbClient.query("CREATE DATABASE " + databaseName);
    await dbClient.end();

    var response = {status: 'SUCCESS'};
    return response;
};
  1. 通过aws lambda invoke 从 Cloud9 调用 Lambda 脚本会导致超时。这是预期行为,因为 Lambda 函数与 RDS 数据库实例不在同一个 VPC 中。
  2. 将具有三个默认子网和默认安全组的默认 VPC 添加到 Lambda 函数配置。瞧,数据库被创建了!我们走上了正轨。

现在我尝试调用 Lambda 函数并从基本 CloudFormation 模板创建数据库:

  1. 创建了包含Custom Ressource的模板:
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "DatabaseName": {"Type": "String"}
    },
    "Resources": {
        "SampleInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "InstanceType": "t1.micro",
                "ImageId": {"Fn::GetAtt": ["CreateDatabase", "Id"]}
            }
        },
        "CreateDatabase": {
            "Type": "Custom::CreateDatabase",
            "Properties": {
                "ServiceToken": "<Lambda Function ARN>",
                "DBSuperUser": "<DBSuperUser>",
                "DBSuperPassword": "<DBSuperPassword>",
                "DatabaseName": {"Ref": "DatabaseName"}                
            }
        }
    }
}

EC2 实例只是一个示例,无论如何都无法创建,因为 ImageId 无效。它只是用来测试我是否从 Lambda 函数中得到响应。

  1. 更改了 Lambda 函数以从 CloudFormation 接收事件并发回响应。我可以使用 cfc-response 模块,但决定将其代码复制到我的 Lambda 函数中,以查看幕后情况。请点击上面的链接并向下滚动到 Module Source Code 以查看源代码。

我也改变了像这样获取输入参数:

var customerName = event.ResourceProperties.CustomerName;
var dbSuperUser = event.ResourceProperties.DBSuperUser;
var dbSuperPassword = event.ResourceProperties.DBSuperPassword; 

然后像这样向 CloudFormation 发送响应:

responseData = {Id: '1234567890'};
send(event, context, SUCCESS, responseData);
  1. 通过 AWS CLI 命令aws cloudformation create-stack 运行模板会导致堆栈卡在CREATE_IN_PROGRESS 中。但是数据库成功创建了!

  2. 我从 Lambda 函数中删除 VPC 配置后,问题就消失了。 CloudFormation 成功接收到来自函数的响应并尝试创建 EC2 示例实例。但是现在 Lambda 函数不能再访问 RDS 来创建数据库了。

这会导致以下问题:

  • Lambda 函数中的 VPC 配置是否会导致与 CloudFormation 模板的连接出现问题?
  • 如果是,我该如何解决?
  • 网络配置是否正确?还是我必须更改我的编码?

我检查过的其他事项:

  • 我在两次运行(成功和失败响应)中比较了 Lambda 脚本的以下变量和对象:event、context、responseBody、parsedUrl、options、request。它们是相同的(某些 ID 等除外)。

期待您对此的看法!

干杯

【问题讨论】:

    标签: postgresql amazon-web-services aws-lambda amazon-cloudformation amazon-vpc


    【解决方案1】:

    您发布的代码是一个简单的 Lambda,并没有按照CloudFormation custom resource 的要求报告其状态。因此,第一步是确保您遵守要求。

    如果是这样,并且您的代码在向 S3 报告状态时被阻止,那么最可能的原因是您在既没有 NAT 也没有 S3 endpoint 的子网中运行。如果您不需要 NAT,则 S3 端点是免费的,因此将是最佳解决方案。如果您已经有 NAT,请确保 Lambda 在 NAT 可用的子网中运行。

    【讨论】:

    • 感谢您将我推向正确的方向!创建 S3 端点对我有用。
    • 一些附加信息:像 exports.handler = async (event, context) =&gt; { ... 这样的异步函数和使用 await 对我不起作用。我必须像 exports.handler = function (event, context) { ... 那样声明处理函数,并使用像 return new Promise((resolve, reject) =&gt; { ...; 和 .then( ... 这样的承诺来使其工作
    猜你喜欢
    • 2020-09-24
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 2016-07-24
    • 1970-01-01
    • 2014-05-23
    • 2017-12-30
    相关资源
    最近更新 更多