CloudFormation: failover application deployment

cfWe’ve set up CloudFormation templates for EC2 and RDS, so far we’re ready to add necessary stuff for failover application deployment.

By necessary stuff I mean scaling, load balancing, monitoring, security and notifications.

Sounds great, so let’s take a look at template:

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "nopCommerce single level app tier",

  "Parameters" : {

    "KeyName" : {
      "Description" : "Name of an existing EC2 KeyPair",
      "Type" : "AWS::EC2::KeyPair::KeyName",
      "ConstraintDescription" : "must be the name of an existing EC2 KeyPair."
    },

    "RDPCidr" : {
      "Description" : "IP Cidr that is allowed to RDP to EC2",
      "Type" : "String",
      "MinLength" : "9",
      "MaxLength" : "18",
      "AllowedPattern" : "^([0-9]+\\.){3}[0-9]+\\/[0-9]+$"
    },

    "SNSEndpoint" : {
      "Description" : "Email for notifications",
      "Type" : "String"
    }

  },

  "Resources" : {

    "NotificationTopic" : {
      "Type" : "AWS::SNS::Topic",
      "Properties" : {
        "DisplayName" : "nopCommerce-demo",
        "Subscription" : [ { "Endpoint": { "Ref" : "SNSEndpoint" }, "Protocol": "email" } ],
        "TopicName" : "nopCommerce-demo"
      }
    },

    "WebServerSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Enable http access from anywhere and RDP from office",
        "SecurityGroupIngress": [
          {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"},
          {"IpProtocol" : "tcp", "FromPort" : "3389", "ToPort" : "3389", "CidrIp" : { "Ref" : "RDPCidr" } }
        ]
      }
    },

    "WebServerGroup" : {
      "Type" : "AWS::AutoScaling::AutoScalingGroup",
      "Properties" : {
        "AvailabilityZones" : { "Fn::GetAZs" : ""},
        "Cooldown" : "60",
        "HealthCheckGracePeriod" : "120",
        "HealthCheckType" : "EC2",
        "LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
        "MinSize" : "2",
        "MaxSize" : "4",
        "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ],
        "MetricsCollection" : [ {
          "Granularity" : "1Minute"
        } ],
        "NotificationConfiguration" : {
          "TopicARN" : { "Ref" : "NotificationTopic" },
          "NotificationTypes" : [
            "autoscaling:EC2_INSTANCE_LAUNCH",
            "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
            "autoscaling:EC2_INSTANCE_TERMINATE",
            "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
          ]
        }
      },

      "UpdatePolicy" : {
        "AutoScalingRollingUpdate" : {
          "MaxBatchSize" : "1",
          "MinInstancesInService" : "0",
          "MinSuccessfulInstancesPercent" : "100",
          "WaitOnResourceSignals" : "true"
        }
      }
    },

    "LaunchConfig" : {
      "Type" : "AWS::AutoScaling::LaunchConfiguration",
      "Properties" : {
        "BlockDeviceMappings" : [ {
          "DeviceName" : "/dev/sda1",
          "Ebs" : { "VolumeSize" : "50" , "VolumeType" : "io1" , "Iops" : "1500" }
        } ],
        "IamInstanceProfile" : "arn:aws:iam::481443282809:instance-profile/aws-elasticbeanstalk-ec2-role",
        "ImageId" : "ami-5f726935",
        "InstanceMonitoring" : "true",
        "InstanceType" : "m4.large",
        "KeyName" : { "Ref" : "KeyName" },
        "SecurityGroups" : [ { "Ref" : "WebServerSecurityGroup" } ]
      }
    },

    "ElasticLoadBalancer" : {
      "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
      "Properties" : {
        "AvailabilityZones" : {
          "Fn::GetAZs" : ""
        },
        "CrossZone" : "true",
        "Listeners" : [ {
          "LoadBalancerPort" : "80",
          "InstancePort" : "80",
          "Protocol" : "HTTP"
        } ],
        "HealthCheck" : {
          "Interval" : "15",
          "HealthyThreshold" : "3",
          "Target" : "HTTP:80/",
          "Timeout" : "3",
          "UnhealthyThreshold" : "2"
        }
      }
    },

    "WebServerScaleUpPolicy" : {
      "Type" : "AWS::AutoScaling::ScalingPolicy",
      "Properties" : {
        "AdjustmentType" : "ChangeInCapacity",
        "AutoScalingGroupName" : { "Ref" : "WebServerGroup" },
        "Cooldown" : "60",
        "PolicyType" : "SimpleScaling",
        "ScalingAdjustment" : "1"
      }
    },

    "WebServerScaleDownPolicy" : {
      "Type" : "AWS::AutoScaling::ScalingPolicy",
      "Properties" : {
        "AdjustmentType" : "ChangeInCapacity",
        "AutoScalingGroupName" : { "Ref" : "WebServerGroup" },
        "Cooldown" : "60",
        "PolicyType" : "SimpleScaling",
        "ScalingAdjustment" : "-1"
      }
    },

    "CPUAlarmHigh" : {
     "Type" : "AWS::CloudWatch::Alarm",
     "Properties" : {
       "ActionsEnabled" : "true",
       "AlarmActions" : [ {
         "Ref" : "WebServerScaleUpPolicy"
        },
        {
          "Ref": "NotificationTopic"
        } ],
       "AlarmDescription" : "Scale-up if CPU > 75% for 10 minutes",
       "AlarmName" : "CPUAlarmHigh",
       "ComparisonOperator" : "GreaterThanThreshold",
       "Dimensions" : [ {
            "Name" : "AutoScalingGroupName",
            "Value" : { "Ref": "WebServerGroup" }
          } ],
       "EvaluationPeriods" : "2",
       "MetricName" : "CPUUtilization",
       "Namespace" : "AWS/EC2",
       "Statistic" : "Average",
       "Period" : "300",
       "Threshold" : "75"
      }
    },

    "CPUAlarmLow": {
     "Type": "AWS::CloudWatch::Alarm",
     "Properties": {
       "ActionsEnabled" : "true",
       "AlarmActions" : [ {
         "Ref" : "WebServerScaleDownPolicy"
       } ],
       "AlarmDescription" : "Scale-down if CPU < 50% for 10 minutes",
       "AlarmName" : "CPUAlarmLow",
       "ComparisonOperator" : "LessThanThreshold",
       "Dimensions" : [ {
         "Name" : "AutoScalingGroupName",
         "Value" : { "Ref": "WebServerGroup" }
       } ],
       "EvaluationPeriods" : "2",
       "MetricName" : "CPUUtilization",
       "Namespace" : "AWS/EC2",
       "Statistic" : "Average",
       "Period" : "300",
       "Threshold" : "50"
      }
    },

    "ELBLatency" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB Latency",
        "ComparisonOperator": "GreaterThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "Latency",
        "Namespace": "AWS/ELB",
        "Statistic": "Average",
        "Period": "300",
        "Threshold": "1"
      }
    },

    "ELBSpilloverCount" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB SpilloverCount",
        "ComparisonOperator": "GreaterThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "SpilloverCount",
        "Namespace": "AWS/ELB",
        "Statistic": "Maximum",
        "Period": "300",
        "Threshold": "10"
      }
    },

    "ELBSurgeQueueLength" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB SurgeQueueLength",
        "ComparisonOperator": "GreaterThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "SurgeQueueLength",
        "Namespace": "AWS/ELB",
        "Statistic": "Maximum",
        "Period": "300",
        "Threshold": "512"
      }
    },

    "ELBRequestCount" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB RequestCount",
        "ComparisonOperator": "GreaterThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "RequestCount",
        "Namespace": "AWS/ELB",
        "Statistic": "Sum",
        "Period": "300",
        "Threshold": "10000"
      }
    },

    "ELBHealthyHostCount" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB Healthy Host Count",
        "ComparisonOperator": "LessThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "HealthyHostCount",
        "Namespace": "AWS/ELB",
        "Statistic": "Average",
        "Period": "300",
        "Threshold": "1"
      }
    },

    "ELBHTTPCode4XX" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB HTTPCode_ELB_4XX",
        "ComparisonOperator": "LessThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "HTTPCode_ELB_4XX",
        "Namespace": "AWS/ELB",
        "Statistic": "Sum",
        "Period": "300",
        "Threshold": "100"
      }
    },

    "ELBHTTPCode5XX" : {
      "Type" : "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "AlarmActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "AlarmDescription": "ELB HTTPCode_ELB_5XX",
        "ComparisonOperator": "LessThanThreshold",
        "Dimensions": [
          {
            "Name": "LoadBalancerName",
            "Value": { "Ref" : "ElasticLoadBalancer" }
          }
        ],
        "EvaluationPeriods": "1",
        "InsufficientDataActions": [
          {
            "Ref": "NotificationTopic"
          }
        ],
        "MetricName": "HTTPCode_ELB_5XX",
        "Namespace": "AWS/ELB",
        "Statistic": "Sum",
        "Period": "300",
        "Threshold": "100"
      }
    },

    "CostAlarm": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled" : "true",
        "AlarmActions": [{
          "Ref" : "NotificationTopic"
        }],
        "AlarmDescription": "Cost tracking",
        "AlarmName" : "CostAlarm",
        "ComparisonOperator": "GreaterThanThreshold",
        "Dimensions": [{
          "Name": "Currency",
          "Value" : "USD"
        }],
        "EvaluationPeriods" : "1",
        "InsufficientDataActions": [{
          "Ref" : "NotificationTopic"
        }],
        "MetricName": "EstimatedCharges",
        "Namespace": "AWS/Billing",
        "Statistic": "Maximum",
        "Period": "21600",
        "Threshold": "100"
      }
    }



  }
}

I hope this info will be useful for you, and if you need any help feel free to use contact from on the main page.