如何在Cloudformation模板中创建可变数量的EC2实例资源? [英] How to create variable number of EC2 instance resources in Cloudformation template?

查看:82
本文介绍了如何在Cloudformation模板中创建可变数量的EC2实例资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何根据模板参数在Cloudformation模板中创建可变数量的EC2实例资源?



EC2 API和管理工具允许启动同一实例的多个实例AMI,但找不到使用Cloudformation的方法。

解决方案

 描述:创建可变数量的EC2实例资源。 
参数:
InstanceCount:
说明:EC2实例数(必须在1到5之间)。
类型:数字
默认值:1
最小值:1
最大值:5
约束说明:必须为1到5之间的数字。
ImageId:
说明:用于启动EC2实例的映像ID。
类型:AWS :: EC2 :: Image :: Id
#amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
默认值:ami-9be6f38c
实例类型:
说明:启动EC2实例的实例类型。
类型:字符串
默认值:m3.medium
AllowedValues:[m3.medium,m3.large,m3.xlarge,m3.2xlarge]
条件:
Launch1 :!Equals [1,1]
Launch2:!Not [!Equals [1,!Ref InstanceCount]]
Launch3:!And
-!Not [!Equals [1,!Ref InstanceCount]]
-!Not [!Equals [2,!Ref InstanceCount]]
Launch4 :!或
-!Equals [4,!Ref InstanceCount]
-!Equals [5,!Ref InstanceCount]
Launch5:!Equals [5,!Ref InstanceCount]
资源:
Instance1:
条件:Launch1
类型:AWS :: EC2 :: Instance
属性:
ImageId:!Ref ImageId
InstanceType:!Ref InstanceType
Instance2:
条件:Launch2
类型:AWS :: EC2 :: Instance
属性:
ImageId:!Ref ImageId
InstanceType:!Ref InstanceType
Instance3:
条件:Launch3
类型:AWS :: EC2 :: Instance
属性:
ImageId:!Ref ImageId
InstanceType:!Ref InstanceType
Instance4:
条件:Launch4
类型:AWS :: EC2 :: Instance
属性:
ImageId:!Ref ImageId
InstanceType:!Ref InstanceType
Instance5:
条件:Launch5
类型:AWS :: EC2 :: Instance
属性:
ImageId:!Ref ImageId
实例类型:!Ref实例类型



1a。具有条件的模板预处理器



作为上述的变体,您可以使用模板预处理器,例如Ruby的

 说明:创建可变数量的EC2实例资源es。 
参数:
InstanceCount:
说明:EC2实例数(必须在1到10之间)。
类型:数字
默认值:1
最小值:1
最大值:10
约束说明:必须为1到10之间的数字。
ImageId:
说明:用于启动EC2实例的映像ID。
类型:AWS :: EC2 :: Image :: Id
#amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
默认值:ami-9be6f38c
实例类型:
说明:启动EC2实例的实例类型。
类型:字符串
默认值:m3.medium
AllowedValues:[m3.medium,m3.large,m3.xlarge,m3.2xlarge]
资源:
EC2Instances :
类型:自定义:: EC2Instances
属性:
ServiceToken:!GetAtt EC2InstancesFunction.Arn
ImageId:!Ref ImageId
InstanceType:!Ref InstanceType
MinCount:!Ref InstanceCount
MaxCount:!Ref InstanceCount
EC2InstancesFunction:
类型:AWS :: Lambda :: Function
属性:
处理程序:index.handler
角色:!GetAtt LambdaExecutionRole.Arn
代码:
ZipFile:!Sub |
var response = require(‘cfn-response’);
var AWS = require('aws-sdk');
exports.handler =函数(事件,上下文){
var physicalId = event.PhysicalResourceId || '没有';
函数success(data){
return response.send(event,context,response.SUCCESS,data,physicalId);
}
函数失败(e){
返回response.send(event,context,response.FAILED,e,physicalId);
}
var ec2 = new AWS.EC2();
个var实例;
if(event.RequestType =='创建'){
var launchParams = event.ResourceProperties;
删除launchParams.ServiceToken;
ec2.runInstances(launchParams).promise()。then((data)=> {
instance = data.Instances.map((data)=> data.InstanceId);
physicalId = instance.join(':');
return ec2.waitFor('instanceRunning',{InstanceIds:instance})。promise();
})。then((data)=> ; success({Instances:instance})
).catch((e)=> failed(e));
} else if(event.RequestType =='Delete'){
if(physicalId =='none'){返回成功({});}
var deleteParams = {InstanceIds: physicalId.split(':')};
ec2.terminateInstances(deleteParams).promise()。then((data)=>
ec2.waitFor('instanceTerminated',deleteParams).promise()
).then(( data)=> success({})
).catch((e)=> failed(e));
} else {
返回失败({错误:不支持就地更新。});
}
};
运行时:nodejs4.3
超时:300
LambdaExecutionRole:
类型:AWS :: IAM :: Role
属性:
AssumeRolePolicyDocument:
版本: 2012-10-17
声明:
-效果:允许
委托人:{服务:[lambda.amazonaws.com]} ​​
操作:['sts :AssumeRole']
路径:/
ManagedPolicyArns:
-arn:aws:iam :: aws:policy / service-role / AWSLambdaBasicExecutionRole
策略:
-PolicyName :EC2Policy
PolicyDocument:
版本:'2012-10-17'
语句:
-效果:允许
操作:
-'ec2:RunInstances '
-'ec2:DescribeInstances'
-'ec2:DescribeInstanceStatus'
-'ec2:TerminateInstances'
资源:['*']
输出:
实例:
值:!Join [',',!GetAtt EC2Instances.Instance s]


How to create variable number of EC2 instance resources in Cloudformation template, according to a template parameter?

The EC2 API and management tools allow launching multiple instances of the same AMI, but I can't find how to do this using Cloudformation.

解决方案

The AWS::EC2::Instance Resource doesn't support the MinCount/MaxCount parameters of the underlying RunInstances API, so it's not possible to create a variable number of EC2 instances by passing Parameters to a single copy of this Resource.

To create a variable number of EC2 instance resources in CloudFormation template according to a template Parameter, and without deploying an Auto Scaling Group instead, there are two options:

1. Conditions

You can use Conditions to create a variable number of AWS::EC2::Instance Resources depending on the Parameter.

It's a little verbose (because you have to use Fn::Equals), but it works.

Here's a working example that allows the user to specify up to a maximum of 5 instances:

Description: Create a variable number of EC2 instance resources.
Parameters:
  InstanceCount:
    Description: Number of EC2 instances (must be between 1 and 5).
    Type: Number
    Default: 1
    MinValue: 1
    MaxValue: 5
    ConstraintDescription: Must be a number between 1 and 5.
  ImageId:
    Description: Image ID to launch EC2 instances.
    Type: AWS::EC2::Image::Id
    # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
    Default: ami-9be6f38c
  InstanceType:
    Description: Instance type to launch EC2 instances.
    Type: String
    Default: m3.medium
    AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ]
Conditions:
  Launch1: !Equals [1, 1]
  Launch2: !Not [!Equals [1, !Ref InstanceCount]]
  Launch3: !And
  - !Not [!Equals [1, !Ref InstanceCount]]
  - !Not [!Equals [2, !Ref InstanceCount]]
  Launch4: !Or
  - !Equals [4, !Ref InstanceCount]
  - !Equals [5, !Ref InstanceCount]
  Launch5: !Equals [5, !Ref InstanceCount]
Resources:
  Instance1:
    Condition: Launch1
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
  Instance2:
    Condition: Launch2
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
  Instance3:
    Condition: Launch3
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
  Instance4:
    Condition: Launch4
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
  Instance5:
    Condition: Launch5
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType

1a. Template preprocessor with Conditions

As a variation on the above, you can use a template preprocessor like Ruby's Erb to generate the above template based on a specified maximum, making your source code more compact and eliminating duplication:

<%max = 10-%>
Description: Create a variable number of EC2 instance resources.
Parameters:
  InstanceCount:
    Description: Number of EC2 instances (must be between 1 and <%=max%>).
    Type: Number
    Default: 1
    MinValue: 1
    MaxValue: <%=max%>
    ConstraintDescription: Must be a number between 1 and <%=max%>.
  ImageId:
    Description: Image ID to launch EC2 instances.
    Type: AWS::EC2::Image::Id
    # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
    Default: ami-9be6f38c
  InstanceType:
    Description: Instance type to launch EC2 instances.
    Type: String
    Default: m3.medium
    AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ]
Conditions:
  Launch1: !Equals [1, 1]
  Launch2: !Not [!Equals [1, !Ref InstanceCount]]
<%(3..max-1).each do |x|
    low = (max-1)/(x-1) <= 1-%>
  Launch<%=x%>: !<%=low ? 'Or' : 'And'%>
<%  (1..max).each do |i|
      if low && i >= x-%>
  - !Equals [<%=i%>, !Ref InstanceCount]
<%    elsif !low && i < x-%>
  - !Not [!Equals [<%=i%>, !Ref InstanceCount]]
<%    end
    end
  end-%>
  Launch<%=max%>: !Equals [<%=max%>, !Ref InstanceCount]
Resources:
<%(1..max).each do |x|-%>
  Instance<%=x%>:
    Condition: Launch<%=x%>
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
<%end-%>

To process the above source into a CloudFormation-compatible template, run:

ruby -rerb -e "puts ERB.new(ARGF.read, nil, '-').result" < template.yml > template-out.yml

For convenience, here is a gist with the generated output YAML for 10 variable EC2 instances.

2. Custom Resource

An alternate approach is to implement a Custom Resource that calls the RunInstances/TerminateInstances APIs directly:

Description: Create a variable number of EC2 instance resources.
Parameters:
  InstanceCount:
    Description: Number of EC2 instances (must be between 1 and 10).
    Type: Number
    Default: 1
    MinValue: 1
    MaxValue: 10
    ConstraintDescription: Must be a number between 1 and 10.
  ImageId:
    Description: Image ID to launch EC2 instances.
    Type: AWS::EC2::Image::Id
    # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
    Default: ami-9be6f38c
  InstanceType:
    Description: Instance type to launch EC2 instances.
    Type: String
    Default: m3.medium
    AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ]
Resources:
  EC2Instances:
    Type: Custom::EC2Instances
    Properties:
      ServiceToken: !GetAtt EC2InstancesFunction.Arn
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      MinCount: !Ref InstanceCount
      MaxCount: !Ref InstanceCount
  EC2InstancesFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          var AWS = require('aws-sdk');
          exports.handler = function(event, context) {
            var physicalId = event.PhysicalResourceId || 'none';
            function success(data) {
              return response.send(event, context, response.SUCCESS, data, physicalId);
            }
            function failed(e) {
              return response.send(event, context, response.FAILED, e, physicalId);
            }
            var ec2 = new AWS.EC2();
            var instances;
            if (event.RequestType == 'Create') {
              var launchParams = event.ResourceProperties;
              delete launchParams.ServiceToken;
              ec2.runInstances(launchParams).promise().then((data)=> {
                instances = data.Instances.map((data)=> data.InstanceId);
                physicalId = instances.join(':');
                return ec2.waitFor('instanceRunning', {InstanceIds: instances}).promise();
              }).then((data)=> success({Instances: instances})
              ).catch((e)=> failed(e));
            } else if (event.RequestType == 'Delete') {
              if (physicalId == 'none') {return success({});}
              var deleteParams = {InstanceIds: physicalId.split(':')};
              ec2.terminateInstances(deleteParams).promise().then((data)=>
                ec2.waitFor('instanceTerminated', deleteParams).promise()
              ).then((data)=>success({})
              ).catch((e)=>failed(e));
            } else {
              return failed({Error: "In-place updates not supported."});
            }
          };
      Runtime: nodejs4.3
      Timeout: 300
  LambdaExecutionRole:
    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
      Policies:
      - PolicyName: EC2Policy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
              - 'ec2:RunInstances'
              - 'ec2:DescribeInstances'
              - 'ec2:DescribeInstanceStatus'
              - 'ec2:TerminateInstances'
              Resource: ['*']
Outputs:
  Instances:
    Value: !Join [',', !GetAtt EC2Instances.Instances]

这篇关于如何在Cloudformation模板中创建可变数量的EC2实例资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆