我正在使用cloudformation创建AWS堆栈。我正在创建EBS卷作为Cloud Formation的一部分,并将它们附加到引导程序中的EC2。
创作部分工作正常。但是,在删除堆栈时,Cloudformation首先尝试删除EBS卷。由于卷已经附加,因此无法删除和删除剩余资源。
因此,除非手动删除或再次使用删除堆栈,否则EBS卷将保留在那里。
有没有办法可以在删除(仅限)cloudformation模板中的资源时指定订单。?
答案 0 :(得分:1)
控制CloudFormation操作顺序的唯一机制是使用DependsOn
。但这并不能解决这个特殊问题。
您在此处描述的问题是因为CloudFormation 不知道该卷已附加:您通过单独的机制附加它(正如您所描述的,使用EC2引导程序,我认为这是某种东西例如,就像EC2实例用户数据脚本上的aws
命令一样。
相反,你可以做的是 CloudFormation为你附加音量。这样,CloudFormation 知道已经附加了卷,并且它知道它也必须分离卷。
为此,您需要使用AWS::EC2::VolumeAttachment
类型的资源。一个YAML片段就像是:
Resources:
MyInstance:
Type: AWS::EC2::Instance
Properties:
...
MyVolume:
Type: AWS::EC2::Volume
Properties:
...
MyVolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/sdf
InstanceId: !Ref MyInstance
VolumeId: !Ref MyVolume
CFN上有相当多的*Attachment
资源类型,出于这个目的:您让CFN将资源附加到您,您为参与附件的资源指定Ref
,所以CFN知道“订单”(即,首先创建2个资源,然后附加它们,或者在删除时,它首先分离,然后删除两个资源),然后CFN可以为您处理整个过程。
答案 1 :(得分:0)
我通过使用自定义lambda函数终止实例解决了此问题。该函数取决于VolumeAttachment资源,并在CloudFormation尝试分离卷之前被调用。它在创建堆栈时不执行任何操作,但是在删除堆栈时终止实例:
Resources:
...
TerminateInstance:
Type: Custom::InstanceTermination
DependsOn: VolumeAttachment1
Properties:
ServiceToken: !GetAtt TerminateInstanceFunction.Arn
InstanceId: !Ref EC2Instance
TerminateInstanceFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt TerminateInstanceLambdaExecutionRole.Arn
Runtime: nodejs4.3
Timeout: 30
Code:
ZipFile: !Sub |
var aws = require("aws-sdk");
var response = require('cfn-response');
exports.handler = function(event, context) {
console.log("request received:\n" + JSON.stringify(event));
var physicalId = event.PhysicalResourceId;
function success(data) {
data = data || {}
console.log('SUCCESS:\n', data);
return response.send(event, context, response.SUCCESS, data, physicalId);
}
function failed(err) {
console.log('FAILED:\n', err);
return response.send(event, context, response.FAILED, err, physicalId);
}
// ignore non-delete requests
if (event.RequestType !== 'Delete') {
console.log('Non-delete request is ignored');
return success();
}
var instanceId = event.ResourceProperties.InstanceId;
if (!instanceId) {
return failed('InstanceId required');
}
var ec2 = new aws.EC2({region: event.ResourceProperties.Region});
ec2.terminateInstances({InstanceIds: [instanceId]})
.promise()
.then((data) => {
console.log('"terminateInstances" Response:\n', JSON.stringify(data));
success();
})
.catch((err) => failed(err));
};
TerminateInstanceLambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/service-role/AWSLambdaRole
Policies:
- PolicyName: EC2Policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'ec2:TerminateInstances'
Resource: ['*']