Monday, October 28, 2013

AWS EC2 instance auto scale policy with spot instances and automatic attachment to ELB

Some time ago I was having a look how to deploy this in our infrastructure. I found some interesting examples in this link, and with the official manual I managed to get the right policy for us, launching spot instances on demand and automatically registering them into our ELB. Here's my final take.

My variables are:

Security group: EE-FE-Stack-SG
SNS Topic: EE-FE-Stack
Minimum servers: 1
Scale up: 80% + CPU Used for 5 min Cooldown 300 sec
Scale down: 65% - CPU Used for 5 min Cooldown 600 sec
In bold the lines where you need to specify your load balancer name, AMI images and availability zone where you want to launch the instances.
In italic Userdata contains some instructions to try to fetch the cf-helper debian package and install it.

When launching the template, you will be asked to introduce the operators email, max spot price, min servers, max servers, security keys and some other parameters. Some of these values can be modified later on when re configuring the policy via web interface or cli tools.


{
"AWSTemplateFormatVersion" : "2010-09-09",

"Description" : "EE-FE Stack. Cooldown 300 sec up, 600 down.  [EE-FE-Stack-SG secutirygroup, EE-FE SNS topic]",

"Parameters" : {
"KeyName" : {
    "Description" : "Security key",
    "Type" : "String"
},

"InstanceType" : {
    "Type" : "String",
    "Default" : "m1.small",
    "AllowedValues" : [ "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "c1.xlarge", "cc1.4xlarge" ],
    "Description" : "EC2 instance type (e.g. m1.large, m1.xlarge, m2.xlarge)"
},

"SpotPrice": {
    "Description": "Spot price for application AutoScaling Group",
    "Type": "Number",
    "MinValue" : ".03"
},

"MinInstances" : {
  "Description" : "The minimum number of Workers",
  "Type" : "Number",
  "MinValue" : "0",
  "Default"  : "0",
  "ConstraintDescription" : "Enter a number >=0"
},

"MaxInstances" : {
  "Description" : "The maximum number of Workers",
  "Type" : "Number",
  "MinValue" : "1",
  "Default"  : "4",
  "ConstraintDescription" : "Enter a number >1"
},

"OperatorEmail": {
  "Description": "Email Address",
  "Type": "String"
}
},

"Mappings" : {
"AWSInstanceType2Arch" : {
  "t1.micro"    : { "Arch" : "64" },
  "m1.small"    : { "Arch" : "64" },
  "m1.medium"   : { "Arch" : "64" },
  "m1.large"    : { "Arch" : "64" },
  "m1.xlarge"   : { "Arch" : "64" },
  "m2.xlarge"   : { "Arch" : "64" },
  "m2.2xlarge"  : { "Arch" : "64" },
  "m2.4xlarge"  : { "Arch" : "64" },
  "m3.xlarge"   : { "Arch" : "64" },
  "m3.2xlarge"  : { "Arch" : "64" },
  "c1.medium"   : { "Arch" : "64" },
  "c1.xlarge"   : { "Arch" : "64" },
  "cc1.4xlarge" : { "Arch" : "64HVM" },
  "cc2.8xlarge" : { "Arch" : "64HVM" },
  "cg1.4xlarge" : { "Arch" : "64HVM" }
},

"AWSRegionArch2AMI" : {
  "us-east-1"      : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "us-west-2"      : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "us-west-1"      : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "eu-west-1"      : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "ap-southeast-1" : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "ap-southeast-2" : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "ap-northeast-1" : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" },
  "sa-east-1"      : { "32" : "NOT_YET_SUPPORTED", "64" : "<Your AMI here>", "64HVM" : "NOT_YET_SUPPORTED" }
}
},

"Resources" : {
"NotificationTopic": {
  "Type": "AWS::SNS::Topic",
  "Properties": {
    "DisplayName" : "EE-FE-Stack",
    "Subscription": [ {
        "Endpoint": { "Ref": "OperatorEmail" },
        "Protocol": "email" } ]
  }
},

"WebServerGroup" : {
  "Type" : "AWS::AutoScaling::AutoScalingGroup",
  "Properties" : {
    "AvailabilityZones" : [ "us-west-1a" ],
    "LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
    "MinSize" : { "Ref" : "MinInstances" },
    "MaxSize" : { "Ref" : "MaxInstances" },
    "LoadBalancerNames" : [ "<your load balancer here>"],
    "NotificationConfiguration" : {
      "TopicARN" : { "Ref" : "NotificationTopic" },
      "NotificationTypes" : [ "autoscaling:EC2_INSTANCE_LAUNCH","autoscaling:EC2_INSTANCE_LAUNCH_ERROR","autoscaling:EC2_INSTANCE_TERMINATE", "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"]
    }
    }
},

"CfnUser" : {
    "Type" : "AWS::IAM::User",
    "Properties" : {
        "Path": "/",
        "Policies": [ {
            "PolicyName": "root",
            "PolicyDocument": { "Statement": [ {
                "Effect":"Allow",
                "Action":"cloudformation:DescribeStackResource",
                "Resource":"*"
            } ] }
        } ]
    }
},

"HostKeys" : {
    "Type" : "AWS::IAM::AccessKey",
    "Properties" : {
        "UserName" : { "Ref" : "CfnUser" }
    }
},

"LaunchConfig" : {
  "Type" : "AWS::AutoScaling::LaunchConfiguration",
  "Metadata" : {
    "Comment" : "Create a single webserver",
    "AWS::CloudFormation::Init" : {
      "config" : {
        "packages" : {
            "yum" : {

            }
        },
        "files" : {

        }
      }
    }
  },
  "Properties" : {
    "KeyName" : { "Ref" : "KeyName" },
    "SpotPrice" : { "Ref" : "SpotPrice" },
    "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
                                      { "Fn::FindInMap" : [ "AWSInstanceType2Arch", {     "Ref" : "InstanceType" },
                                      "Arch" ] } ] },
    "SecurityGroups" : [ "WEB" ],
    "InstanceType" : { "Ref" : "InstanceType" },
    "UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
      "#!/bin/bash\n",
      "wget -O /opt/aws-cfn-bootstrap.deb http://pkg.camptocamp.net/staging/pool/sysadmin/a/aws-cfn-bootstrap/aws-cfn-bootstrap_1.3-1_all.deb\n",
      "dpkg -i /opt/aws-cfn-bootstrap.deb\n",
      "# Install the Worker application\n",
      "/opt/aws/bin/cfn-init ",
      "         --stack ", { "Ref" : "AWS::StackId" },
      "         --resource LaunchConfig ",
      "         --configset ALL",
      "         --region ", { "Ref" : "AWS::Region" }, "\n"
    ]]}}      
  }
},


"WebServerScaleUpPolicy" : {
  "Type" : "AWS::AutoScaling::ScalingPolicy",
  "Properties" : {
    "AdjustmentType" : "ChangeInCapacity",
    "AutoScalingGroupName" : { "Ref" : "WebServerGroup" },
    "Cooldown" : "300",
    "ScalingAdjustment" : "1"
  }
},
"WebServerScaleDownPolicy" : {
  "Type" : "AWS::AutoScaling::ScalingPolicy",
  "Properties" : {
    "AdjustmentType" : "ChangeInCapacity",
    "AutoScalingGroupName" : { "Ref" : "WebServerGroup" },
    "Cooldown" : "600",
    "ScalingAdjustment" : "-1"
  }
},

  "WorkerThreadHigh": {
   "Type": "AWS::CloudWatch::Alarm",
   "Properties": {
      "AlarmDescription": "Scale-up if Worker Thread Vs. Idle Percent > 80% for 5min",
      "MetricName": "CPUUtilization",
      "Namespace": "AWS/EC2",
      "Statistic": "Average",
      "Period": "300",
      "EvaluationPeriods": "2",
      "Threshold": "80",
      "AlarmActions": [ { "Ref": "WebServerScaleUpPolicy" } ],
      "Dimensions": [
        {
          "Name": "AutoScalingGroupName",
          "Value": { "Ref": "WebServerGroup" }
        }
      ],
      "ComparisonOperator": "GreaterThanThreshold"
    }
  },
  "WorkerThreadLow": {
   "Type": "AWS::CloudWatch::Alarm",
   "Properties": {
      "AlarmDescription": "Scale-down if CPU < 65% for 5 minutes",
      "MetricName": "CPUUtilization",
      "Namespace": "AWS/EC2",
      "Statistic": "Average",
      "Period": "300",
      "EvaluationPeriods": "2",
      "Threshold": "65",
      "AlarmActions": [ { "Ref": "WebServerScaleDownPolicy" } ],
      "Dimensions": [
        {
          "Name": "AutoScalingGroupName",
          "Value": { "Ref": "WebServerGroup" }
        }
      ],
      "ComparisonOperator": "LessThanThreshold"
    }
  }
}

}

No comments:

Post a Comment