Skip to content

Instantly share code, notes, and snippets.

@przygode
Created October 21, 2012 02:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save przygode/3925522 to your computer and use it in GitHub Desktop.
Save przygode/3925522 to your computer and use it in GitHub Desktop.
auto-scaling complete configuration
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "AppServer Stack",
"Parameters": {
"KeyName": {
"Type": "String",
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the web server",
"Default": "AWS_SSH_KEY"
},
"InstanceType": {
"Description": "Application Server EC2 instance type",
"Type": "String",
"Default": "m1.small",
"AllowedValues": ["t1.micro", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "c1.medium", "c1.xlarge", "cc1.4xlarge", "cc2.8xlarge", "cg1.4xlarge"],
"ConstraintDescription": "must be a valid EC2 instance type."
},
"ChefOrganization": {
"Description": "The Organization name used in Hosted Chef.",
"Type": "String",
"Default": "Stratalux"
},
"ChefEnvironment": {
"Description": "The Chef Environment.",
"Type": "String",
"Default": "Production"
},
"ChefRunList": {
"Description": "The Chef runlist.",
"Type": "String",
"Default": "role[app_server_prod]"
},
"DomainName": {
"Description": "Server Domain Name.",
"Type": "String",
"Default": "stratalux.com"
},
"StrataluxBucket": {
"Description": "S3 bucket containing validation private key for Chef Server",
"Type": "String",
"Default": "Stratalux_bucket"
},
"SNSTopic": {
"Description": "Email address for notifications.",
"Type": "String",
"Default": "sns@stratalux.com"
}
},
"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"
},
"c1.medium": {
"Arch": "64"
},
"c1.xlarge": {
"Arch": "64"
}
},
"AWSRegionArch2AMI": {
"us-east-1": {
"32": "ami-abababab",
"64": "ami-abababab"
},
"us-west-1": {
"32": "ami-abababab",
"64": "ami-abababab"
},
"us-west-2": {
"32": "ami-abababab",
"64": "ami-abababab"
},
"eu-west-1": {
"32": "ami-abababab",
"64": "ami-abababab"
},
"sa-east-1": {
"32": "ami-abababab",
"64": "ami-abababab"
},
"ap-southeast-1": {
"32": "ami-abababab",
"64": "ami-abababab"
},
"ap-northeast-1": {
"32": "ami-abababab",
"64": "ami-abababab"
}
}
},
"Resources": {
"ChefClientUser": {
"Type": "AWS::IAM::User",
"Properties": {
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": ["cloudformation:DescribeStackResource", "s3:Get"],
"Resource": "*"
}
]
}
}
]
}
},
"HostKeys": {
"Type": "AWS::IAM::AccessKey",
"DependsOn": "ChefClientUser",
"Properties": {
"UserName": {
"Ref": "ChefClientUser"
}
}
},
"BucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"DependsOn": "HostKeys",
"Properties": {
"PolicyDocument": {
"Version": "2008-10-17",
"Id": "ReadPolicy",
"Statement": [
{
"Sid": "ReadAccess",
"Action": ["s3:GetObject"],
"Effect": "Allow",
"Resource": {
"Fn::Join": ["",
["arn:aws:s3:::", {
"Ref": "StrataluxBucket"
}, "/*"
]
]
},
"Principal": {
"AWS": {
"Fn::GetAtt": ["ChefClientUser", "Arn"]
}
}
}
]
},
"Bucket": {
"Ref": "StrataluxBucket"
}
}
},
"AppServerSNSTopic": {
"Type": "AWS::SNS::Topic",
"Properties": {
"Subscription": [
{
"Endpoint": {
"Ref": "SNSTopic"
},
"Protocol": "email"
}
]
}
},
"AppServerGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones": {
"Fn::GetAZs": ""
},
"LaunchConfigurationName": {
"Ref": "ChefClient"
},
"LoadBalancerNames": [
{
"Ref": "app.stratalux.com"
}
],
"MinSize": "3",
"MaxSize": "6",
"HealthCheckType": "ELB",
"HealthCheckGracePeriod": "720",
"NotificationConfiguration": {
"TopicARN": {
"Ref": "AppServerSNSTopic"
},
"NotificationTypes": ["autoscaling:EC2_INSTANCE_LAUNCH", "autoscaling:EC2_INSTANCE_LAUNCH_ERROR", "autoscaling:EC2_INSTANCE_TERMINATE", "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"]
}
}
},
"ChefClient": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"DependsOn": "BucketPolicy",
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"packages": {
"rubygems": {
"chef": ["10.14.2"],
"ohai": ["0.6.4"]
},
"apt": {
"build-essential": [],
"curl": [],
"irb": [],
"libopenssl-ruby": [],
"libreadline-ruby1.8": [],
"libruby1.8": [],
"libxslt-dev": [],
"libxml2-dev": [],
"libxml2": [],
"rdoc": [],
"ri": [],
"ruby": [],
"ruby-dev": [],
"rubygems": [],
"s3cmd": [],
"ssl-cert": [],
"wget": []
}
},
"files": {
"/etc/chef/first-boot.json": {
"content": {
"run_list": {
"Ref": "ChefRunList"
},
"mode": "000644",
"owner": "root",
"group": "root"
}
},
"/home/ubuntu/.s3cfg": {
"content": {
"Fn::Join": ["",
["[default]\n", "access_key = ", {
"Ref": "HostKeys"
}, "\n", "secret_key = ", {
"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]
}, "\n", "use_https = True\n"
]
]
},
"mode": "000644",
"owner": "ubuntu",
"group": "ubuntu"
},
"/var/lib/gems/1.8/gems/ohai-0.6.4/lib/ohai/plugins/cfn.rb": {
"source": "https://s3.amazonaws.com/cloudformation-examples/cfn.rb",
"mode": "000644",
"owner": "root",
"group": "root"
}
}
}
}
},
"Properties": {
"SecurityGroups": [
{
"Ref": "AppServerAccess"
}
],
"ImageId": {
"Fn::FindInMap": ["AWSRegionArch2AMI", {
"Ref": "AWS::Region"
}, {
"Fn::FindInMap": ["AWSInstanceType2Arch", {
"Ref": "InstanceType"
}, "Arch"
]
}
]
},
"UserData": {
"Fn::Base64": {
"Fn::Join": ["",
["#!/bin/bash -v\n", "function error_exit\n", "{\n", " cfn-signal -e 1 -r \"$1\" '", {
"Ref": "ChefClientWaitHandle"
}, "'\n", " exit 1\n", "}\n", "apt-get update; apt-get upgrade -y; apt-get -y remove apparmor libapparmor1 ; apt-get -y install python-setuptools\n", "easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-1.0-6.tar.gz\n", "cfn-init --region ", {
"Ref": "AWS::Region"
}, " -s ", {
"Ref": "AWS::StackName"
}, " -r ChefClient ", " --access-key ", {
"Ref": "HostKeys"
}, " --secret-key ", {
"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]
}, " --region ", {
"Ref": "AWS::Region"
}, " || error_exit 'Failed to run cfn-init'\n", "# Fixup path and links for the bootstrap script\n", "export PATH=$PATH:/var/lib/gems/1.8/bin\n", "s3cmd -c /home/ubuntu/.s3cfg get s3://", {
"Ref": "StrataluxBucket"
}, "/chef_init.rb /etc/chef/chef_init.rb > /tmp/get_chef_init.log 2>&1 || error_exit 'Failed to get Chef initialization script.'\n", "ruby /etc/chef/chef_init.rb ", {
"Ref": "DomainName"
}, " ", {
"Ref": "ChefEnvironment"
}, " ", {
"Ref": "ChefOrganization"
}, " >> /tmp/get_chef_init.log 2>&1 || error_exit 'Failed to run chef_init script.'\n", "# Fixup the server URL in client.rb\n", "s3cmd -c /home/ubuntu/.s3cfg get s3://", {
"Ref": "StrataluxBucket"
}, "/validation.pem /etc/chef/validation.pem > /tmp/get_validation_key.log 2>&1 || error_exit 'Failed to get Chef Server validation key'\n", "s3cmd -c /home/ubuntu/.s3cfg get s3://", {
"Ref": "StrataluxBucket"
}, "/encrypted_data_bag_secret /etc/chef/encrypted_data_bag_secret > /tmp/encrypted_data_bag_secret.log 2>&1 || error_exit 'Failed to get Chef encrypted data bag secret.'\n", "chmod 600 /etc/chef/encrypted_data_bag_secret \n", "chef-client -j /etc/chef/first-boot.json > /tmp/initialize_client.log 2>&1 || error_exit 'Failed to initialize host via chef client' \n", "# If all went well, signal success\n", "cfn-signal -e $? -r 'Chef Server configuration' '", {
"Ref": "ChefClientWaitHandle"
}, "'\n"
]
]
}
},
"KeyName": {
"Ref": "KeyName"
},
"InstanceType": {
"Ref": "InstanceType"
}
}
},
"AppServerAccess": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "AppServerAccess",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
}, {
"IpProtocol": "tcp",
"FromPort": "443",
"ToPort": "443",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"app.stratalux.com": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"AvailabilityZones": {
"Fn::GetAZs": ""
},
"HealthCheck": {
"HealthyThreshold": "10",
"Interval": "15",
"Target": "HTTP:80/monitor/healthcheck",
"Timeout": "2",
"UnhealthyThreshold": "2"
},
"Listeners": [
{
"InstancePort": "80",
"LoadBalancerPort": "443",
"Protocol": "HTTPS",
"SSLCertificateId": "arn:aws:iam::1234567890:server-certificate/stratalux.com.2012",
"PolicyNames": []
}, {
"InstancePort": "80",
"LoadBalancerPort": "80",
"Protocol": "HTTP",
"PolicyNames": []
}
]
}
},
"AppServerScaleUpPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AdjustmentType": "ChangeInCapacity",
"AutoScalingGroupName": {
"Ref": "AppServerGroup"
},
"Cooldown": "60",
"ScalingAdjustment": "1"
}
},
"AppServerScaleDownPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AdjustmentType": "ChangeInCapacity",
"AutoScalingGroupName": {
"Ref": "AppServerGroup"
},
"Cooldown": "60",
"ScalingAdjustment": "-1"
}
},
"CPUAlarmHigh": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmDescription": "Scale-up if CPU > 75% for 10 minutes",
"MetricName": "CPUUtilization",
"Namespace": "AWS/EC2",
"Statistic": "Average",
"Period": "60",
"EvaluationPeriods": "10",
"Threshold": "75",
"AlarmActions": [
{
"Ref": "AppServerScaleUpPolicy"
}
],
"Dimensions": [
{
"Name": "AutoScalingGroupName",
"Value": {
"Ref": "AppServerGroup"
}
}
],
"ComparisonOperator": "GreaterThanThreshold"
}
},
"CPUAlarmLow": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmDescription": "Scale-down if CPU < 75% for 10 minutes",
"MetricName": "CPUUtilization",
"Namespace": "AWS/EC2",
"Statistic": "Average",
"Period": "60",
"EvaluationPeriods": "10",
"Threshold": "75",
"AlarmActions": [
{
"Ref": "AppServerScaleDownPolicy"
}
],
"Dimensions": [
{
"Name": "AutoScalingGroupName",
"Value": {
"Ref": "AppServerGroup"
}
}
],
"ComparisonOperator": "LessThanThreshold"
}
},
"ChefClientWaitHandle": {
"Type": "AWS::CloudFormation::WaitConditionHandle"
},
"ChefClientWaitCondition": {
"Type": "AWS::CloudFormation::WaitCondition",
"DependsOn": "ChefClient",
"Properties": {
"Handle": {
"Ref": "ChefClientWaitHandle"
},
"Timeout": "1200"
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment