从 Lambda 连接到 Neptune 时出现问题
Problems connecting to Neptune from Lambda
我创建了一个简单的 AWS Neptune 集群,它有一个写入器,没有读取副本。我使用选项为它创建了一个新的 VPC,同时也为它自动创建了两个安全组。
我还有一个调用 Nepture 集群端点的 Lambda。我已经使用 Neptune 集群的 VPC 配置了 Lambda,指定了它的所有子网和上面提到的两个安全组。在我从 AWS 控制台执行 VPC 配置时自动分配入站和出站规则后,我没有手动修改它们(只是完成这些步骤)。
Lambda 是用 Python 编写的,并使用 requests
库通过 AWS Singature V4 进行 HTTPS 调用。 Lambda 的执行角色具有 NeptuneFullAccess
和一个允许为 Lambda 配置 VPC 的内联策略(已经完成,因此策略有效)。
Lambda 在端口 8182 上调用 Neptune 集群的端点,集群的名称和 ID 已编辑:
https://NAME.cluster-ID.us-east-1.neptune.amazonaws.com:8182
我收到以下错误:
{
"errorMessage": "2020-05-20T21:26:35.066Z c8ee70ac-6390-48fd-a32e-36f80d58a24e Task timed out after 3.00 seconds"
}
我做错了什么?
更新:所以,看起来 Neptune 集群的第二个安全组是由我在创建集群时选择一个选项创建的。因此,我再次尝试为安全组使用 Choose existing
选项,而不是 Create new
。 (我想我之前很困惑,因为我正在创建一个全新的VPC,所以安全组怎么可能已经存在?但是向导只是假定到那时将创建default
个安全组。)
现在,我不再遇到同样的错误。然而,我看到的是:
{
"errorType": "Runtime.ExitError",
"errorMessage": "RequestId: 48e3b4fb-1b88-48d3-8834-247dbb1a4f3f Error: Runtime exited without providing a reason"
}
日志显示如下:
{
"requestId": "b8b91c18-34cd-c5f6-9103-ed3357b9241e",
"code": "BadRequestException",
"detailedMessage": "Bad request."
}
查询是(给定 https://docs.amazonaws.cn/en_us/neptune/latest/userguide/iam-auth-connecting-python.html 中描述的 Lambda 代码):
{
"host": "NAME.cluster-ID.us-east-1.neptune.amazonaws.com:8182",
"method": "GET",
"query_type": "status",
"query": ""
}
有什么建议吗?
更新:尝试针对另一个 Neptune 集群,[Errno 111] Connection refused'
错误又回来了。然而,我注意到一件奇怪的事情:我有一些孤立的网络接口,从 Lambda 与现在已删除的 Neptune 集群的 VPC 相关联开始。但是,网络接口标记为 in use
,我无法分离和删除它们,即使使用 Force detachment
选项也是如此。收到 You are not allowed to manage 'ela-attach' attachments
错误。
更新:从一个全新的 Lambda(不再重做其 VPC 配置,因此不再有孤立的网络接口)和一个启用并配置了 IAM Auth 的全新 Neptune 集群开始(甚至 Lambda 的执行角色被授予完全管理员访问权限)出于调试目的,以消除任何缺失的权限),仍然出现此错误:
{
"errorMessage": "HTTPSConnectionPool(host='NAME.cluster-ID.us-east-1.neptune.amazonaws.com', port=8182): Max retries exceeded with url: /status/ (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f1f9f98c310>: Failed to establish a new connection: [Errno 111] Connection refused'))",
"errorType": "ConnectionError",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 71, in lambda_handler\n return make_signed_request(host, method, query_type, query)\n",
" File \"/var/task/lambda_function.py\", line 264, in make_signed_request\n r = requests.get(request_url, headers=headers, verify=False, params=request_parameters)\n",
" File \"/var/task/requests/api.py\", line 76, in get\n return request('get', url, params=params, **kwargs)\n",
" File \"/var/task/requests/api.py\", line 61, in request\n return session.request(method=method, url=url, **kwargs)\n",
" File \"/var/task/requests/sessions.py\", line 530, in request\n resp = self.send(prep, **send_kwargs)\n",
" File \"/var/task/requests/sessions.py\", line 643, in send\n r = adapter.send(request, **kwargs)\n",
" File \"/var/task/requests/adapters.py\", line 516, in send\n raise ConnectionError(e, request=request)\n"
]
}
根据您的错误信息:
Task timed out after 3.00 seconds
你必须增加你的 lambda 执行timeout,因为你当前设置的 3 秒不足以让它成功竞争:
The amount of time that Lambda allows a function to run before stopping it. The default is 3 seconds. The maximum allowed value is 900 seconds.
如果您的函数 运行s 超过设置的超时时间,lambda 服务将终止 它,因为 运行ning 超过了给定的超时时间阈值。
旁注:
由于您在 vpc 中使用 lambda,因此您必须记住 lambda 函数没有 public IP 也没有 internet 访问权限.即使增加函数超时,您也可能无法连接到数据库。如果您 运行 在 私有子网 中使用 lambda 函数并正确设置 NAT 网关或 NAT 实例 ,则可以克服此问题。
需要检查的几件事:
附加到 Neptune 实例的安全组是否允许来自为 Lambda 函数配置的子网的流量?附加到 Neptune 的安全组的默认入站规则是仅允许来自配置它的 IP 地址的流量。
NeptuneFullAccess 内置 IAM 策略用于控制平面操作,而不用于数据平面操作。您需要使用此处定义的策略文档创建一个 IAM 策略 [1],并将该策略附加到您正在使用的 Lambda 执行角色。然后,您需要使用该角色来签署向 Neptune 发出的请求。 Python request
库不进行 SigV4 签名,因此您需要遵循类似于此处列出的过程 [2].
如果您真的想简化这一切,我们发布了一个 Python 库,可帮助管理连接、IAM 身份验证以及向 Neptune 发送查询。你可以在这里找到它 [3].
[1] https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth.html
[2] https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth-connecting-python.html
[3] https://github.com/awslabs/amazon-neptune-tools/tree/master/neptune-python-utils
感谢 Neptune 团队的帮助(一个惊人的回应!他们打电话给我讨论这个问题),我能够解决这个问题。
首先,当我使用新的 Neptune 集群和安全组的 Use existing
选项以及添加到 Neptune 集群的全新 Lambda 重新设置后,Connection refused
错误消失了专有网络。显然,在 Lambda 上重做 VPC 配置有时会留下难以删除的孤立网络接口。所以,在 Lambda 上只做一次 VPC 配置!
其次,此后开始出现的运行时错误是由于 AWS 在此处提供的 Python 代码中的错误:https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth-connecting-python.html
也就是说,该脚本中的 make_signed_request
函数没有 return 值。它应该 return r.text
或者更好的是 json.loads(r.text)
。然后,一切正常。
我创建了一个简单的 AWS Neptune 集群,它有一个写入器,没有读取副本。我使用选项为它创建了一个新的 VPC,同时也为它自动创建了两个安全组。
我还有一个调用 Nepture 集群端点的 Lambda。我已经使用 Neptune 集群的 VPC 配置了 Lambda,指定了它的所有子网和上面提到的两个安全组。在我从 AWS 控制台执行 VPC 配置时自动分配入站和出站规则后,我没有手动修改它们(只是完成这些步骤)。
Lambda 是用 Python 编写的,并使用 requests
库通过 AWS Singature V4 进行 HTTPS 调用。 Lambda 的执行角色具有 NeptuneFullAccess
和一个允许为 Lambda 配置 VPC 的内联策略(已经完成,因此策略有效)。
Lambda 在端口 8182 上调用 Neptune 集群的端点,集群的名称和 ID 已编辑:
https://NAME.cluster-ID.us-east-1.neptune.amazonaws.com:8182
我收到以下错误:
{
"errorMessage": "2020-05-20T21:26:35.066Z c8ee70ac-6390-48fd-a32e-36f80d58a24e Task timed out after 3.00 seconds"
}
我做错了什么?
更新:所以,看起来 Neptune 集群的第二个安全组是由我在创建集群时选择一个选项创建的。因此,我再次尝试为安全组使用 Choose existing
选项,而不是 Create new
。 (我想我之前很困惑,因为我正在创建一个全新的VPC,所以安全组怎么可能已经存在?但是向导只是假定到那时将创建default
个安全组。)
现在,我不再遇到同样的错误。然而,我看到的是:
{
"errorType": "Runtime.ExitError",
"errorMessage": "RequestId: 48e3b4fb-1b88-48d3-8834-247dbb1a4f3f Error: Runtime exited without providing a reason"
}
日志显示如下:
{
"requestId": "b8b91c18-34cd-c5f6-9103-ed3357b9241e",
"code": "BadRequestException",
"detailedMessage": "Bad request."
}
查询是(给定 https://docs.amazonaws.cn/en_us/neptune/latest/userguide/iam-auth-connecting-python.html 中描述的 Lambda 代码):
{
"host": "NAME.cluster-ID.us-east-1.neptune.amazonaws.com:8182",
"method": "GET",
"query_type": "status",
"query": ""
}
有什么建议吗?
更新:尝试针对另一个 Neptune 集群,[Errno 111] Connection refused'
错误又回来了。然而,我注意到一件奇怪的事情:我有一些孤立的网络接口,从 Lambda 与现在已删除的 Neptune 集群的 VPC 相关联开始。但是,网络接口标记为 in use
,我无法分离和删除它们,即使使用 Force detachment
选项也是如此。收到 You are not allowed to manage 'ela-attach' attachments
错误。
更新:从一个全新的 Lambda(不再重做其 VPC 配置,因此不再有孤立的网络接口)和一个启用并配置了 IAM Auth 的全新 Neptune 集群开始(甚至 Lambda 的执行角色被授予完全管理员访问权限)出于调试目的,以消除任何缺失的权限),仍然出现此错误:
{
"errorMessage": "HTTPSConnectionPool(host='NAME.cluster-ID.us-east-1.neptune.amazonaws.com', port=8182): Max retries exceeded with url: /status/ (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f1f9f98c310>: Failed to establish a new connection: [Errno 111] Connection refused'))",
"errorType": "ConnectionError",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 71, in lambda_handler\n return make_signed_request(host, method, query_type, query)\n",
" File \"/var/task/lambda_function.py\", line 264, in make_signed_request\n r = requests.get(request_url, headers=headers, verify=False, params=request_parameters)\n",
" File \"/var/task/requests/api.py\", line 76, in get\n return request('get', url, params=params, **kwargs)\n",
" File \"/var/task/requests/api.py\", line 61, in request\n return session.request(method=method, url=url, **kwargs)\n",
" File \"/var/task/requests/sessions.py\", line 530, in request\n resp = self.send(prep, **send_kwargs)\n",
" File \"/var/task/requests/sessions.py\", line 643, in send\n r = adapter.send(request, **kwargs)\n",
" File \"/var/task/requests/adapters.py\", line 516, in send\n raise ConnectionError(e, request=request)\n"
]
}
根据您的错误信息:
Task timed out after 3.00 seconds
你必须增加你的 lambda 执行timeout,因为你当前设置的 3 秒不足以让它成功竞争:
The amount of time that Lambda allows a function to run before stopping it. The default is 3 seconds. The maximum allowed value is 900 seconds.
如果您的函数 运行s 超过设置的超时时间,lambda 服务将终止 它,因为 运行ning 超过了给定的超时时间阈值。
旁注:
由于您在 vpc 中使用 lambda,因此您必须记住 lambda 函数没有 public IP 也没有 internet 访问权限.即使增加函数超时,您也可能无法连接到数据库。如果您 运行 在 私有子网 中使用 lambda 函数并正确设置 NAT 网关或 NAT 实例 ,则可以克服此问题。
需要检查的几件事:
附加到 Neptune 实例的安全组是否允许来自为 Lambda 函数配置的子网的流量?附加到 Neptune 的安全组的默认入站规则是仅允许来自配置它的 IP 地址的流量。
NeptuneFullAccess 内置 IAM 策略用于控制平面操作,而不用于数据平面操作。您需要使用此处定义的策略文档创建一个 IAM 策略 [1],并将该策略附加到您正在使用的 Lambda 执行角色。然后,您需要使用该角色来签署向 Neptune 发出的请求。 Python
request
库不进行 SigV4 签名,因此您需要遵循类似于此处列出的过程 [2].如果您真的想简化这一切,我们发布了一个 Python 库,可帮助管理连接、IAM 身份验证以及向 Neptune 发送查询。你可以在这里找到它 [3].
[1] https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth.html
[2] https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth-connecting-python.html
[3] https://github.com/awslabs/amazon-neptune-tools/tree/master/neptune-python-utils
感谢 Neptune 团队的帮助(一个惊人的回应!他们打电话给我讨论这个问题),我能够解决这个问题。
首先,当我使用新的 Neptune 集群和安全组的 Use existing
选项以及添加到 Neptune 集群的全新 Lambda 重新设置后,Connection refused
错误消失了专有网络。显然,在 Lambda 上重做 VPC 配置有时会留下难以删除的孤立网络接口。所以,在 Lambda 上只做一次 VPC 配置!
其次,此后开始出现的运行时错误是由于 AWS 在此处提供的 Python 代码中的错误:https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth-connecting-python.html
也就是说,该脚本中的 make_signed_request
函数没有 return 值。它应该 return r.text
或者更好的是 json.loads(r.text)
。然后,一切正常。