为什么VPC的公共子网内的AWS Lambda功能无法连接到互联网?

Bri*_*ian 9 vpc amazon-web-services aws-lambda

我已经按照此处的教程创建了具有公共和私有子网的VPC。

然后,我在公共子网中设置了一个AWS lambda函数,以测试它是否可以连接到外部互联网。

这是我用python3编写的lambda函数

import requests

def lambda_handler(event, context):
    r = requests.get('http://www.google.com')
    print(r)
Run Code Online (Sandbox Code Playgroud)

http://www.google.com当我在VPC的公共子网中进行设置时,上述函数无法获取其内容。

这是错误消息:

“ errorMessage”:“ HTTPConnectionPool(host ='www.google.com',port = 80):url超过了最大重试次数:/(由NewConnectionError(':导致:建立新连接失败:[Errno 110]连接超时',))“,” errorType“:” ConnectionError“,

我不明白为什么。

公共子网的路由表如下所示:

在此处输入图片说明

对的GET请求http://www.google.com应匹配igw-XXXXXXXXX目标。为什么Internet网关(igw)无法将请求传递到http://www.google.com网站并取回网站内容?

文章说,我必须设置专用子网内的lambda函数才能有互联网接入。

如果您的Lambda函数需要访问私有VPC资源(例如,Amazon RDS数据库实例或Amazon EC2实例),则必须将该函数与VPC关联。如果您的功能还需要互联网访问(例如,到达公共AWS服务终端节点),则您的功能必须使用NAT网关或实例。

但这并不能解释为什么我不能在公共子网中设置lambda函数。

Ali*_*son 22

您可以使 lambda 函数从 VPC 内访问公共互联网。解决方案A是实际的答案,解决方案B是一个更优雅的替代解决方案。


解决方案 A - VPC 中的 Lambda + 与 ENI 关联的公共 IP

为了访问 AWS 外部的资源,例如 Google API(如 OP 的示例),您确实需要一个公共 IP。对于 RDS 或 S3 等其他情况,您不需要公共 IP,可以使用 VPC 终端节点,因此 Lambda 和所需 AWS 服务之间的通信不会离开 AWS 网络。

默认情况下,某些 AWS 服务确实可以通过公共互联网访问,但这并非必须如此。

现在,如果您想要实际的外部资源(例如 google),则需要将弹性公共 IP 分配给链接到 lambda 的每个子网的网络接口。首先让我们弄清楚哪些子网安全组链接到您的 lambda:

拉姆达屏

接下来,转到 EC2 服务,在Network & Security下找到Public IPs菜单。为每个子网分配一个 IP(在上例中有两个子网)。

转到网络接口菜单,找到附加到您的 lambda 的网络接口(同一子网和安全组)。

网络接口

在操作菜单中为每一个关联公共 IP:

操作菜单

关联IP

就是这样,现在您的 Lambda 可以访问公共互联网了。

[编辑] 有人担心解决方案的 A 可扩展性问题,称每个 lambda 实例都有一个新的网络接口,但他们从 AWS 文档中错过了这一点

“如果多个 Lambda 函数共享相同的子网和安全组,则这些函数可以共享网络接口”

因此,无论您可能面临什么可扩展性问题,都与该解决方案以及 Lambda 如何使用 ENI 无关,您在使用 EC2、ECS、EKS 而不仅仅是 Lambda 时也会面临同样的问题。


解决方案 B - 分解为多个 Lambda

要求访问外部资源和 VPC 资源似乎对单一功能来说责任太大。您可能需要重新考虑您的设计并将单个 lambda 函数分解为至少两个 lambda 函数:

  • 拉姆达A访问外部资源(例如 Google API),获取您需要的任何数据,添加到 SQS。无需附加VPC,无需手动将弹性公网IP关联到ENI。
  • Lambda B处理来自 SQS 的消息,将结果存储到存储(db、s3、efs、另一个队列等)。它位于您的 VPC 内,不需要外部访问。

这种方式看起来更具可扩展性,更安全,每个单独的 lambda 都不那么复杂并且更易于维护,架构整体看起来更好。

当然,生活并不总是彩虹和蝴蝶,所以解决方案A很好并且具有足够的可扩展性,但改进架构就更好了。


jar*_*mod 19

即使Lambda函数在VPC的公共子网内运行,您的Lambda函数也无法访问Internet的原因是Lambda函数没有也不可以具有公共IP地址。没有公共IP,您无法将流量直接发送到Internet。您将需要通过NAT进行路由。

VPC公共子网中流量的默认路由目标是Internet网关(IGW),并且由于Lambda功能只有一个专用IP,因此从Lambda功能发送到Internet的所有数据包都将在IGW被丢弃。

如果您的Lambda函数实际上不需要访问VPC内部的私有资源,则通常不需要将Lambda部署到VPC中。但是,如果确实需要,则可以在专用子网中运行Lambda函数,并确保从该子网到公用子网中的NAT实例或NAT网关的默认路由。并配置一个IGW。

  • 谢谢!我没有意识到只有私有子网才能有 NAT GW,所以这是完全有道理的。顺便说一句,在进入这个兔子洞时,我还发现实际上可以让 lambda 从公共子网访问互联网,但需要将弹性 IP 连接到其 ENI。我知道这很傻,但很高兴知道。 (4认同)
  • 而这一切又再次改变了。AWS 已经听取了有关冷启动和 ENI 消耗问题的意见,现在支持 Lambda 的 Hyperplain,您仍然需要额外添加适当的 IAM 权限,但看起来有重大改进:https://aws.amazon.com/blogs/compute/宣布针对 aws-lambda-functions 改进了 vpc-networking/ (3认同)
  • 您建议在私有子网中运行 lambda 的原因是什么?与在公共平台上运行相比有什么缺点吗? (2认同)
  • @LLL 退后一步,如果您*需要*在 VPC 中运行 Lambda 函数,那么您可以在 VPC 中运行它们,例如因为它们需要访问私有资源,例如 VPC 内的 MySQL 数据库,或者 S3 存储桶通过私有限制对特定 VPC 的访问端点。在 VPC 中运行的缺点是冷启动延迟比不在 VPC 中运行时更高(因为必须附加 ENI)。公共子网和私有子网之间的区别在于路由(0.0.0.0/0 默认路由指向 IGW 或 NAT)。如果您的 Lambda 需要出站访问,那么它将无法在公有子网中工作,因为默认路由是 IGW。 (2认同)
  • 谢谢你!这是一个非常清楚的解释。 (2认同)
  • 从技术上讲,公共/私有子网 + NAT 解决方案非常棒。但 NAT 网关非常昂贵。这就是为什么我想避免它! (2认同)