AWS Lambda无法连接到RDS实例,但我在本地可以连接?

28

我正在尝试从Lambda连接到我的RDS实例。我本地编写并进行了本地测试,一切都正常。但是当我部署到Lambda上时,它突然间失效了。下面是我运行的代码,如果有帮助的话,我是通过Kinesis流来调用Lambda的。

'use strict';

exports.handler = (event, context, handlerCallback) => {
    console.log('Recieved request for kinesis events!');
    console.log(event);
    console.log(context);

    const connectionDetails = {
        host:     RDS_HOST,
        port:     5432,
        database: RDS_DATABASE,
        user:     RDS_USER,
        password: RDS_PASSWORD
    };

    const db = require('pg-promise')({promiseLib: require('bluebird')})(connectionDetails);

    db
            .tx(function () {
                console.log('Beginning query');

                return this.query("SELECT 'foobar'")
                           .then(console.log)
                           .catch(console.log)
                           .finally(console.log);
            })
            .finally(() => handlerCallback());
};

这里是来自 CloudWatch 的日志,如果有帮助的话:

START RequestId: *********-****-****-****-********* Version: $LATEST 
2016-05-31T20:58:25.086Z    *********-****-****-****-*********  Recieved request for kinesis events! 
2016-05-31T20:58:25.087Z    *********-****-****-****-*********  { Records:  [ { kinesis: [Object], eventSource: 'aws:kinesis', eventVersion: '1.0', eventID: 'shardId-000000000000:**********************************', eventName: 'aws:kinesis:record', invokeIdentityArn: 'arn:aws:iam::******************:role/lambda_kinesis_role', awsRegion: 'us-east-1', eventSourceARN: 'arn:aws:kinesis:us-east-1:****************:stream/route-registry' } ] } 
2016-05-31T20:58:25.283Z    *********-****-****-****-*********  { callbackWaitsForEmptyEventLoop: [Getter/Setter], done: [Function], succeed: [Function], fail: [Function], logGroupName: '/aws/lambda/apiGatewayRouteRegistry-development', logStreamName: '2016/05/31/[$LATEST]******************', functionName: 'apiGatewayRouteRegistry-development', memoryLimitInMB: '128', functionVersion: '$LATEST', getRemainingTimeInMillis: [Function], invokeid: '*********-****-****-****-*********', awsRequestId: '*********-****-****-****-*********', invokedFunctionArn: 'arn:aws:lambda:us-east-1:*************:function:apiGatewayRouteRegistry-development' } 
END RequestId: *********-****-****-****-********* 
REPORT RequestId: *********-****-****-****-*********    Duration: 20003.70 ms   Billed Duration: 20000 ms Memory Size: 128 MB   Max Memory Used: 22 MB   
2016-05-31T20:58:45.088Z *********-****-****-****-********* Task timed out after 20.00 seconds

你是否为Lambda函数启用了VPC访问? - Mark B
@MarkB 不是的。我已经将下拉菜单设置为“无VPC”。 - LordZardeck
1
@MarkB 是的,我可以直接从我的笔记本电脑访问RDS。整个Lambda在我的本地机器上完美运行。 - LordZardeck
20秒似乎是足够的时间,但如果您暂时将Lambda超时时间增加到60秒,它是否有效? - jarmod
1
你真的应该将这个连接到(希望)你的RDS实例所在的VPC。否则,你的RDS实例必须允许来自0.0.0.0/0的访问 - 这真的听起来目前不是这种情况,但如果是的话,从安全角度来看,这是一个可怕的想法。 - Michael - sqlbot
显示剩余4条评论
4个回答

27

@MarkB和@Michael-sqlbot在评论中是正确的,问题确实与安全组有关。

我最终得到了AWS支持团队的回复,指出RDS安全组确实是私有的,只能被特定IP访问。这没有道理,因为我从未进行此配置,而且我可以从本地计算机和弹性Beanstalk访问数据库。我将0.0.0.0/0添加到安全组中,现在Lambda可以连接了。感谢大家的帮助!


你好,能详细说明一下吗?你在哪里以及将0.0.0.0/0添加到了什么地方? - UncleAdam
13
将0.0.0.0/0添加到安全组的入站规则中意味着向全世界打开连接。你不担心这个吗? - Nativ
3
@Nativ 它是为开发和测试目的而设置的。后来它被锁定到了正确的安全组。是的,对于生产使用来说,将连接打开到全球并不是一个好主意。 - LordZardeck
那么,你最终将 Lambda 添加到 VPC 中了吗? - Trevor
1
@LordZardeck 在创建RDS实例的同时,AWS会自动将您的公共IP配置为安全组中的入站IP。这就是为什么代码在您的计算机上可以工作,但在其他地方无法工作的原因。我也遇到了同样的问题! :) - Juan M. Molina

22

以下是我如何解决这个问题的方法。

在创建数据库实例时,会要求您选择虚拟专用云(VPC)。即使您选择默认值,它也将您系统的公共IP作为默认入站IP。另一方面,Lambda函数有自己的IP设置。这就是为什么您可以通过任何IDE或本地访问,但不能通过Lambda函数访问。

添加IP限制:

  1. 进入您的实例的安全组。选择默认安全组后,单击它。在新页面中,向下滚动以查找入站和出站设置。

  2. 在入站设置中,单击编辑。您可以在此更改IP。(0.0.0.0/0使其对世界开放)

  3. 如果您在此处添加公共IP,则IDE或本地连接将起作用。

  4. 为使Lambda函数正常工作,请添加Lambda函数的IP。 进入 Lambda 函数,网络 --> VPC -->(如果没有选择VPC,则选择与DB函数相同的VPC),并在此处注意IP。

  5. 在入站设置中输入此IP,这将显示自动填充器。

保存后测试Lambda函数。


1
如果我将“Publicly Accessible”设置为true,这是否适用? - nxmohamad
1
你是救命恩人。非常感谢! - Hashir Baig
1
子网怎么样?选择什么有关系吗? - thanos.a

9

以下是没有全球访问权限的答案。

允许AWS Lambda访问RDS数据库

重复Mark的答案:

  1. 为lambda函数添加VPC访问权限。
  2. 创建一个新的lambda安全组。
  3. 将RDS安全组添加到lambda的SG。

这会给答案添加什么内容? - stdunbar
1
我更喜欢这个答案,因为第一个会向全世界开放你的RDS实例,而第二个则不起作用,或者至少对我来说是这样。这个答案既优雅又有参考价值。 - MarcoSantana
子网掩码怎么样?选择什么有关系吗? - thanos.a

0
对我来说,问题在于我在客户端设置中没有使用ssl:true属性。
var client = new Client({
      user: RDS_USER,
      host: RDS_HOST,
      database: RDS_DB,
      password: RDS_PASSWORD,
      ssl: true
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接