我正在尝试在堆栈中设置自定义资源,以在堆栈创建期间实现一些数据库初始化步骤。然而,虽然自定义资源代码似乎运行良好,但 CloudFormation 无法识别自定义资源发回的 SUCCESS 信号,并且它会陷入
CREATE_IN_PROGRESS
状态长达 1 小时的超时。然后,当然,当我尝试手动删除堆栈时,它又卡在了一个小时DELETE_IN_PROGRESS
等待删除信号。
我已经对我的环境进行了最小程度的重现,并表现出相同的行为。这是我的 lambda 代码:
const { put } = require('axios');
const SUCCESS = 'SUCCESS';
const FAILED = 'FAILED';
// CloudFormation Custom Resource Response Handler
let Responder = (event, context) => async (status, data={}) => {
let body = {
Status: status,
Reason: data.Reason ?? data.Error ?? "",
PhysicalResourceId: `${event.LogicalResourceId}-${event.RequestId}`,
StackId: event.StackId,
RequestId: event.RequestId,
LogicalResourceId: event.LogicalResourceId,
Data: (({Reason, Error, ...etc}) => etc)(data)
};
console.log("Custom Resource body:", body);
let request = put(event.ResponseURL, body);
console.log("Response sent");
context.done();
console.log("Context discontinued");
let response = await request;
console.log("Custom Resource response:", response);
}
exports.lambdaHandler = async (event, context) => {
console.info("event:", event);
let responder = Responder(event, context);
try {
if (event.RequestType === "Delete") {
console.log("Custom resource deleting!");
// delete resource
await responder(SUCCESS);
} else {
console.log("Custom resource creating!");
// create resource
await responder(SUCCESS);
}
} catch (err) {
console.error(err);
await responder(FAILED, err);
}
};
这是我的 SAM 模板:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
RDSVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.10.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref RDSVPC
CidrBlock: 10.10.1.0/24
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: 'AWS::Region'
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref RDSVPC
CidrBlock: 10.10.2.0/24
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: 'AWS::Region'
InternetGateway:
Type: AWS::EC2::InternetGateway
InternetGatewayAttachment:
DependsOn: InternetGateway
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref RDSVPC
InternetGatewayId: !Ref InternetGateway
RouteTable:
DependsOn: InternetGatewayAttachment
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref RDSVPC
RouteTableAttachement:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref RouteTable
RouteTableAttachement2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref RouteTable
EIP:
DependsOn: InternetGatewayAttachment
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NAT:
DependsOn: RDSVPC
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIP.AllocationId
SubnetId: !Ref InternetSubnet
ConnectivityType: public
NATRoute:
DependsOn:
- NAT
- RouteTable
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NAT
InternetSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref RDSVPC
CidrBlock: 10.10.3.0/24
AvailabilityZone: !Select
- 2
- !GetAZs
Ref: 'AWS::Region'
InternetRouteTable:
DependsOn: InternetGatewayAttachment
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref RDSVPC
InternetRouteTableAttachement:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref InternetSubnet
RouteTableId: !Ref InternetRouteTable
InternetRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref InternetRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Lambda SG
VpcId: !Ref RDSVPC
SecurityGroupEgress:
- CidrIp: "0.0.0.0/0"
IpProtocol: "-1"
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
Timeout: 3
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs14.x
Architectures:
- x86_64
VpcConfig:
SecurityGroupIds:
- !Ref LambdaSecurityGroup
SubnetIds:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
HelloWorldCustomResource:
DependsOn:
- HelloWorldFunction
- InternetRoute
- NATRoute
Type: AWS::CloudFormation::CustomResource
Properties:
ServiceToken: !GetAtt HelloWorldFunction.Arn
CloudWatch Log 输出示例(匿名):
START RequestId: b7f45954-f5e9-4dd3-8404-c2117c8e8718 Version: $LATEST
2021-12-22T18:22:52.726Z b7f45954-f5e9-4dd3-8404-c2117c8e8718 INFO event: {
RequestType: 'Create',
ServiceToken: 'arn:aws:lambda:us-east-2:<userid>:function:custom-resource-test-2-HelloWorldFunction-DZYI8GLlnI0j',
ResponseURL: 'https://cloudformation-custom-resource-response-useast2.s3.us-east-2.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-2%3A<userid>%3Astack/custom-resource-test-2/1820acc0-6354-11ec-b638-061066120c32%7CHelloWorldCustomResource%7C1311ae33-9ac4-461c-a118-433bc29e1671?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20211222T182252Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7200&X-Amz-Credential=AKIAVRFIPK6PKAFALJ4V%2F20211222%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Signature=0190bb01d874ce33cf7d8559c060df5ffb171053b95279e9318cb556ff0f91e0',
StackId: 'arn:aws:cloudformation:us-east-2:<userid>:stack/custom-resource-test-2/1820acc0-6354-11ec-b638-061066120c32',
RequestId: '1311ae33-9ac4-461c-a118-433bc29e1671',
LogicalResourceId: 'HelloWorldCustomResource',
ResourceType: 'AWS::CloudFormation::CustomResource',
ResourceProperties: {
ServiceToken: 'arn:aws:lambda:us-east-2:<userid>:function:custom-resource-test-2-HelloWorldFunction-DZYI8GLlnI0j'
}
}
2021-12-22T18:22:52.726Z b7f45954-f5e9-4dd3-8404-c2117c8e8718 INFO Custom resource creating!
2021-12-22T18:22:52.726Z b7f45954-f5e9-4dd3-8404-c2117c8e8718 INFO Custom Resource body: {
Status: 'SUCCESS',
Reason: '',
PhysicalResourceId: 'HelloWorldCustomResource-1311ae33-9ac4-461c-a118-433bc29e1671',
StackId: 'arn:aws:cloudformation:us-east-2:<userid>:stack/custom-resource-test-2/1820acc0-6354-11ec-b638-061066120c32',
RequestId: '1311ae33-9ac4-461c-a118-433bc29e1671',
LogicalResourceId: 'HelloWorldCustomResource',
Data: {}
}
2021-12-22T18:22:52.996Z b7f45954-f5e9-4dd3-8404-c2117c8e8718 INFO Response sent
2021-12-22T18:22:53.016Z b7f45954-f5e9-4dd3-8404-c2117c8e8718 INFO Context discontinued
END RequestId: b7f45954-f5e9-4dd3-8404-c2117c8e8718
REPORT RequestId: b7f45954-f5e9-4dd3-8404-c2117c8e8718 Duration: 314.99 ms Billed Duration: 315 ms Memory Size: 128 MB Max Memory Used: 63 MB Init Duration: 195.58 ms
更新:向 lambda 安全组添加完整的入口允许规则...
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Lambda SG
VpcId: !Ref RDSVPC
SecurityGroupEgress:
- CidrIp: "0.0.0.0/0"
IpProtocol: "-1"
SecurityGroupIngress:
- CidrIp: "0.0.0.0/0"
IpProtocol: "-1"
...put请求成功,自定义资源创建成功。然而,这并不是一个真正的解决方案。我不能只是为了解决这个问题而简单地允许我的 lambda 完全进入互联网。我可以设置更具体的入口规则以允许通信正常工作吗?
我认为
event.ResponseURL
是一个对象,它包含一些项目。您可以使用 event.ResponseURL
中提交的 href。或者您可以使用帖子名和路径字段等
当然你可以查看
cfn-response
源代码并在此基础上实现你自己的源代码。