【发布时间】:2019-07-05 12:48:47
【问题描述】:
我使用serverless 部署应用程序,我使用Custom Resource 迁移RDS 数据库。
在我部署时一切正常,但是当我删除堆栈时,自定义资源在一小时后超时,并显示消息“自定义资源未能在预期时间内稳定。”。对预签名 AWS S3 URL 的请求返回 403,错误代码为 AccessDenied。
我第一次成功发送了对预签名 URL 的响应正文(在创建时):
{
"Status": "SUCCESS",
"RequestId": "bd487606-8017-49f2-99af-b29b2bbad40b",
"LogicalResourceId": "SheltersDBMigrationTrigger",
"StackId": "arn:aws:cloudformation:us-east-1:848139458219:stack/update-shelters-dev/c08a80e0-2e4e-11e9-87a6-124d1eab42ba",
"PhysicalResourceId": "DB_MIGRATION"
}
我第二次向预签名 URL 发送了失败的响应正文(删除时):
{
"Status": "SUCCESS",
"RequestId": "2d166d36-7c0c-4848-9eb5-aedaf5e9172c",
"LogicalResourceId": "SheltersDBMigrationTrigger",
"StackId": "arn:aws:cloudformation:us-east-1:848139458219:stack/update-shelters-dev/c08a80e0-2e4e-11e9-87a6-124d1eab42ba",
"PhysicalResourceId": "DB_MIGRATION"
}
lambda.go:
func handler(ctx context.Context, event cfn.Event) (rid string, data map[string]interface{}, err error) {
rid = "DB_MIGRATION"
if event.RequestType != cfn.RequestCreate {
return
}
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@(%s)/", os.Getenv("DB_MASTER_USER"), os.Getenv("DB_MASTER_PASSWORD"), os.Getenv("DB_ADDRESS")))
if err != nil {
panic(err)
}
defer db.Close()
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("handler: Failed to migrate DB: %v", r)
}
}()
MigrateDb(db)
return
}
func main() {
lambda.Start(cfn.LambdaWrap(handler))
}
Lambda CFN 的无服务器配置:
functions:
dbMigration:
handler: lambda-bin/migrate-db
environment:
DB_MASTER_USER: ${env:DB_MASTER_USER}
DB_MASTER_PASSWORD: ${env:DB_MASTER_PASSWORD}
DB_ADDRESS:
"Fn::GetAtt": [ SheltersDB, Endpoint.Address ]
vpc:
securityGroupIds:
- Ref: SheltersVPCSecurityGroup
subnetIds:
- Ref: SheltersSubnet1
- Ref: SheltersSubnet2
...
Resources:
SheltersDBMigrationTrigger:
Type: Custom::DBMigration
DependsOn:
- SheltersDB
Properties:
ServiceToken: !GetAtt
- DbMigrationLambdaFunction
- Arn
SheltersSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select [ 0, {Fn::GetAZs: ""} ]
CidrBlock: 10.0.1.0/24
VpcId: !Ref SheltersVPC
SheltersSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select [ 1, {Fn::GetAZs: ""} ]
CidrBlock: 10.0.2.0/24
VpcId: !Ref SheltersVPC
SheltersVPCSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Security group for DB connections"
VpcId: !Ref SheltersVPC
SheltersVPCSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref SheltersVPCSecurityGroup
IpProtocol: tcp
FromPort: "3306"
ToPort: "3306"
SourceSecurityGroupId: !Ref SheltersVPCSecurityGroup
SheltersVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
SheltersRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SheltersVPC
SheltersSubnet1Association:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SheltersSubnet1
RouteTableId: !Ref SheltersRouteTable
SheltersSubnet2Association:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SheltersSubnet2
RouteTableId: !Ref SheltersRouteTable
SheltersVPCS3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref SheltersVPC
PolicyDocument: "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"*\",\"Resource\":\"*\"}]}"
RouteTableIds:
- !Ref SheltersRouteTable
ServiceName: !Join ['', ['com.amazonaws.', !Ref 'AWS::Region', '.s3']]
Here's a gist with my full source files and log.
发现问题的更新
似乎我到 S3 的 VPCEndpoint SheltersVPCS3Endpoint 在 dBMigration 之前被删除,这就是我收到 403 的原因。
对于纯 Cloudformation,我想这可以通过将 DependsOn 放在 dbMigration 上轻松解决,但对于无服务器,这似乎是不可能的。
【问题讨论】:
-
从您的源代码中我可以理解,当您收到“DELETE”请求类型时,您没有返回成功消息。遇到这种情况时需要显式发送成功消息,否则您的 CF 堆栈会卡住。
-
谢谢,但我正在使用 github.com/aws/aws-lambda-go/tree/master/cfn 包装函数并处理响应。在日志中,您可以看到已发送响应以及我返回的正文。
-
啊,我的错。尽管自定义资源因无法稳定而被卡住一个小时是指该问题。在这种情况下,请检查与自定义资源触发的 lambda 函数关联的 IAM 角色。由于我从未使用过无服务器框架并且使用过 SAM,因此它很难导航。希望有帮助!
-
哦。 IAM 角色可能值得进一步研究。您知道执行此操作需要哪些角色吗?
标签: amazon-web-services amazon-s3 aws-lambda amazon-cloudformation serverless-framework