我正在尝试在AWS Lambda函数(NodeJS 6.10运行时)中使用AWS SDK for JavaScript。我的最终目标是使用它来管理我的ECS实例,但是现在我只是尝试使用API的任何部分,并且每次尝试都失败了。我已将功能简化为最简单的功能;看一看:
exports.handler = (event, context, callback) => {
var AWS = require('aws-sdk');
(new AWS.ECS({"apiVersion": '2014-11-13'})).listClusters({}, (err, data) => {
if (err) console.log(err, err.stack);
else console.log(data);
callback(null, "DONE");
})
};
我已将此函数赋予具有此定义的IAM角色:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"aws:*",
"ecs:*"
],
"Resource": [
"*"
]
}
]
}
我已将此功能设置为在我现有的VPC,子网和安全组中运行。我已经增加了超出所有可能需求的超时和内存上限。
此函数的每次执行都会因超时异常而失败。我尝试过使用许多不同的API调用,甚至是不同的服务API,但是每次尝试在我的函数中调用API总会导致超时。
我甚至为这个功能启用了X射线追踪,但是从各方面来看似乎没有任何东西离开Lambda执行环境--X-Ray报告没有活动到AWS的其他部分(例如ECS)。
我错过了什么?为什么我不能在Lambda中使用任何JS SDK?
答案 0 :(得分:3)
你的代码对我来说非常好,但这里有一些我必须先做的事情:
CreateNetworkInterface
的其他权限(请参阅Lambda creating ENI everytime it is invoked: Hitting limit)以上是因为Lambda函数需要Internet访问来调用AWS API端点。附加到VPC的Lambda函数仅具有专用IP地址,因此它们需要NAT网关或NAT实例才能访问Internet。请参阅:Internet Access for Lambda Functions
答案 1 :(得分:0)
对于后人,我采用了John Rotenstein的优秀建议并使用了VPC向导来使事情顺利进行。结果显示关键细节与NAT网关的构建有关。
如果您希望Lambda函数能够访问AWS SDK和您的VPC资源,则至少需要两个子网(一个用于公共子网,一个用于私有资源)。以下是您需要执行的VPC命令,这些命令与VPC向导类似:
export REGION=us-west-2 #or whatever region you want
export VPC_ID=`aws ec2 create-vpc --cidr-block 10.1.0.0/16 \
--query Vpc.VpcId --output text`
export IGW_ID=`aws ec2 create-internet-gateway \
--query InternetGateway.InternetGatewayId --output text`
aws ec2 attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID
export ROUTE_TABLE_ID_PUBLIC=`aws ec2 describe-route-tables \
--filter Name=vpc-id,Values=$VPC_ID --query RouteTables[0].RouteTableId --output text`
export SUBNET_ID_PUBLIC=`aws ec2 create-subnet --vpc-id $VPC_ID \
--cidr-block 10.1.0.0/24 --availability-zone ${REGION}a \
--query Subnet.SubnetId --output text`
aws ec2 associate-route-table --subnet-id $SUBNET_ID_PUBLIC \
--route-table-id $ROUTE_TABLE_ID_PUBLIC
aws ec2 create-route --route-table-id $ROUTE_TABLE_ID_PUBLIC \
--gateway-id $IGW_ID --destination-cidr-block 0.0.0.0/0
export IP_ALLOCATION_ID=`aws ec2 allocate-address --domain vpc \
--query AllocationId --output text`
export ROUTE_TABLE_ID_PRIVATE=`aws ec2 create-route-table --vpc-id $VPC_ID \
--query RouteTable.RouteTableId --output text`
export SUBNET_ID_PRIVATE=`aws ec2 create-subnet --vpc-id $VPC_ID \
--cidr-block 10.1.1.0/24 --availability-zone ${REGION}b \
--query Subnet.SubnetId --output text`
aws ec2 associate-route-table --subnet-id $SUBNET_ID_PRIVATE \
--route-table-id $ROUTE_TABLE_ID_PRIVATE
export NAT_GW_ID=`aws ec2 create-nat-gateway --subnet-id $SUBNET_ID_PUBLIC \
--allocation-id $IP_ALLOCATION_ID --query NatGateway.NatGatewayId --output text`
请稍等片刻 - NAT网关准备好并可用于进一步的命令需要一些时间。
关键细节(我在AWS文档中找不到)在上面的最后一个命令中 - 必须使用 PUBLIC 创建NAT网关 子网,即使它与 PRIVATE 路由表关联:
aws ec2 create-route --route-table-id $ROUTE_TABLE_ID_PRIVATE \
--gateway-id $NAT_GW_ID --destination-cidr-block 0.0.0.0/0
export SECURITY_GROUP_ID=`aws ec2 create-security-group --vpc-id $VPC_ID \
--group-name mygroup --description "My SG" \
--query GroupId --output text`
aws ec2 authorize-security-group-ingress --group-id $SECURITY_GROUP_ID \
--protocol tcp --port 22 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id $SECURITY_GROUP_ID \
--cidr 10.1.0.0/16 --protocol all
此时,您应该能够创建与私有子网关联的Lambda函数,这些函数可以访问VPC中的资源,还可以调用Internet(这是AWS SDK使用所必需的)。这是Lambda函数的一个示例,它正是这样做的:
aws iam create-instance-profile --instance-profile-name testRole
testRole_trust_policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
export TEST_ROLE_ARN=`aws iam create-role --role-name testRole \
--assume-role-policy-document file://testRole_trust_policy.json \
--query Role.Arn --output text`
testRole_policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:*",
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface"
],
"Resource": [
"*"
]
}
]
}
aws iam put-role-policy --role-name testRole \
--policy-name testRole --policy-document file://testRole_policy.json
aws iam add-role-to-instance-profile \
--instance-profile-name testRole \
--role-name testRole
contents of lambda.zip:
- test.js:
exports.handler = (event, context, callback) => {
AWS = require('aws-sdk'),
lambda = new AWS.Lambda({"apiVersion": '2015-03-31'});
lambda.listFunctions(callback);
};
aws lambda create-function --function-name testWithVPC \
--runtime nodejs6.10 --role $TEST_ROLE_ARN \
--handler test.handler --timeout 10 \
--zip-file fileb://lambda.zip \
--vpc-config SubnetIds=$SUBNET_ID_PRIVATE,SecurityGroupIds=$SECURITY_GROUP_ID
aws lambda invoke --function-name testWithVPC with.txt
with.txt:
{"NextMarker":null,"Functions":[{"FunctionName":"testWithVPC","FunctionArn": ....]}
这足以证明功能。我可以在此处获得基于此模式的项目,以获得更强大的样本:https://github.com/jakefeasel/sqlfiddle3