Last active
May 3, 2018 09:06
-
-
Save chipx86/81b8e77bd62cd626de97 to your computer and use it in GitHub Desktop.
Some samples showing our new CloudFormation compilation tool, with includes, macros, variables, functions, and more.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# This file contains a list of AMIs that we'll reference throughout our | |
# templates. | |
# | |
# We keep track of the baseline AMIs (Amazon Linux) we use to build clean | |
# images for our servers. We also keep track of "delta" images (AMIs last | |
# generated for a particular server image), which we'll bootstrap new | |
# deployments from. | |
# | |
# Note how we're using variable references within the file to avoid repeating | |
# ourselves. This is indicated by the $${....}. | |
# | |
# When we run the bundled create-ami tool for a particular template, the | |
# template will be compiled with some special properties and outputs. A new | |
# stack will then be created, and AMIs automatically generated against | |
# the clean images. | |
# | |
# Once this is done, the create-ami tool will automatically find the old | |
# AMI ID for that server type and replace it with the new one (if passed | |
# the --update-amis-file option). This makes management of your fleet of | |
# AMIs much easier. | |
# | |
--- !vars | |
amis: | |
amazonLinux: | |
us_east_1: | |
hvm: ami-146e2a7c | |
paravirtual: ami-8e682ce6 | |
myServer: | |
us_east_1: | |
clean: $${amis.amazonLinux.us_east_1.hvm} | |
delta: ami-abc1234 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# In this file, we're defining a set of common variables and macros we'll | |
# be using in our other templates. A lot of the bulk in our infrastructure | |
# lives in this file, which is nice, because it means we're not adding that | |
# bulk to all our other templates. | |
# | |
# We're defining some common variables (SNS topics, S3 buckets and paths), | |
# common template parameters and outputs, common bootstrapping tasks, and | |
# more. | |
# | |
--- !vars | |
snsTopics: | |
pagerDuty: 'arn:aws:sns:us-east-1:1234567890:PagerDuty' | |
s3: | |
buckets: | |
deploy: 'arn:aws:s3:::mybucket' | |
paths: | |
deploy: | |
build_tools: "$${s3.buckets.deploy}/build-tools" | |
config: "$${s3.buckets.deploy}/config" | |
--- !macros | |
# | |
# Common input parameters to templates. | |
# | |
# Note how we can define some defaults for these macros. The caller can | |
# specify their own values. | |
# | |
params: | |
AvailabilityZone: | |
defaultParams: | |
default: us-east-1a | |
content: | |
AvailabilityZone: | |
Type: String | |
Default: $$default | |
Description: "The availability zone for the server." | |
Environment: | |
defaultParams: | |
default: production | |
content: | |
Environment: | |
Type: String | |
Default: $$default | |
Description: "The environment of the server instance." | |
ConstraintDescription: "must be a valid environment type." | |
AllowedValues: | |
- production | |
- testing | |
- staging | |
ImageId: | |
content: | |
ImageId: | |
Type: String | |
Default: $$default | |
Description: "The AMI ID to use for the instance. Defaults to | |
the base AMI for this type of server." | |
KeyName: | |
defaultParams: | |
default: mykey | |
content: | |
KeyName: | |
Type: AWS::EC2::KeyPair::KeyName | |
Default: $$default | |
Description: | |
"The EC2 Key Pair to allow SSH access to the gateway." | |
ConstraintDescription: | |
"must be the name of an existing EC2 KeyPair." | |
MinLength: 1 | |
MaxLength: 255 | |
AllowedPattern: '[\x20-\x7E]*' | |
ServerName: | |
content: | |
ServerName: | |
Type: String | |
Default: $$default | |
Description: "The name of the server instance." | |
# | |
# Alarms that will notify us on PagerDuty when bad things happen. | |
# | |
alarms: | |
ec2: | |
# Notifies when the CPU usage is above 80%. | |
HighCPUAlarm: | |
defaultParams: | |
serverName: "@@ServerName" | |
serverRef: "@@WebServer" | |
period: 300 | |
evaluationPeriods: 1 | |
threshold: 80 | |
notifyARNs: | |
- $${snsTopics.pagerDuty} | |
content: | |
HighCPUAlarm: | |
Type: AWS::CloudWatch::Alarm | |
Properties: | |
AlarmDescription: "[$$serverName] Alert if CPU > 80% for 5 minutes" | |
MetricName: CPUUtilization | |
Namespace: AWS/EC2 | |
Statistic: Average | |
Period: $$period | |
EvaluationPeriods: $$evaluationPeriods | |
Threshold: $$threshold | |
ComparisonOperator: GreaterThanOrEqualToThreshold | |
AlarmActions: $$notifyARNs | |
InsufficientDataActions: $$notifyARNs | |
Dimensions: | |
- Name: InstanceId | |
Value: $$serverRef | |
# | |
# Common IAM setup rules. | |
# | |
# A neat trick below: Note how we can use a variable for a key in a macro. | |
# This allows us to pass in custom names for resources. | |
# | |
iam: | |
ec2Setup: | |
defaultParams: | |
roleName: null | |
instanceProfileName: null | |
policyName: null | |
statements: null | |
content: | |
$$roleName: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: | |
- ec2.amazonaws.com | |
Action: | |
- "sts:AssumeRole" | |
Path: / | |
Policies: | |
- PolicyName: $$policyName | |
PolicyDocument: | |
Version: "2012-10-17" | |
Statement: $$statements | |
$$instanceProfileName: | |
Type: AWS::IAM::InstanceProfile | |
Properties: | |
Path: / | |
Roles: | |
- Ref: $$roleName | |
# | |
# Common macro outputs. | |
# | |
# Note below in publicAddress, how we're calling the GetAtt function against | |
# the resource name provided to the template (or "Server", if not provided). | |
# | |
outputs: | |
instanceID: | |
defaultParams: | |
outputName: InstanceID | |
server: "@@Server" | |
content: | |
$$outputName: | |
Description: The ID of the server instance. | |
Value: $$server | |
publicAddress: | |
defaultParams: | |
outputName: PublicAddress | |
serverResourceName: Server | |
content: | |
$$outputName: | |
Description: The public address of the server instance. | |
Value: <% GetAtt($$serverResourceName, "PublicDnsName") %> | |
# | |
# Macros for handling the bootstrapping of an instance. | |
# | |
# We make use of the !cloud-init directive to easily upload a MIME archive | |
# containing both cloud-init configuration and a bootstrapper shell script. | |
# | |
# We're also making use of flexible expressions below to determine if | |
# swap-related rules should be set. These will be compiled into registered | |
# Conditions, and referenced in the appropriate place. | |
# | |
bootstrapper: | |
resources: | |
defaultParams: | |
timeout: 2400 | |
dependsOn: Server | |
content: | |
WaitHandle: | |
Type: AWS::CloudFormation::WaitConditionHandle | |
WaitCondition: | |
Type: AWS::CloudFormation::WaitCondition | |
DependsOn: $$dependsOn | |
Properties: | |
Handle: '@@WaitHandle' | |
Timeout: $$timeout | |
script: | |
defaultParams: | |
hostname: "@@ServerName" | |
useSwap: true | |
content: !cloud-init | |
config: | | |
#cloud-config | |
<% If ($$useSwap == true) { %> | |
mounts: | |
- [ ephemeral0, none, swap, sw, 0, 0 ] | |
bootcmd: | |
- mkswap /dev/xvdb | |
- swapon /dev/xvdb | |
<% } %> | |
script: | | |
#!/bin/bash -v | |
yum update -y | |
# XXX Do some stuff here for bootstrapping the server. | |
/opt/aws/bin/cfn-signal -e 0 -r "Bootstrap complete." \ | |
'@@WaitHandle' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# A template for a server. | |
# | |
# This will start out by importing variables and macros from our amis.yaml | |
# and defs.yaml files. We can then make use of them below. | |
# | |
# Note also that while this mostly follows the format of CloudFormation JSON | |
# files, we do have a special Meta section that contains version information. | |
# Soon, it will also contain destination S3 bucket/path information, to make | |
# it easy to upload compiled templates. Anything can really go in this section. | |
# | |
__imports__: | |
!import amis.yaml | |
defs.yaml | |
Meta: | |
Description: My Server Instance | |
Version: 1.0 | |
Parameters: | |
# Embed some parameters from defs.yaml. The "<" will replace the entire | |
# !call-macro key/value pair with the contents of the macro. | |
<: !call-macro | |
macro: params.KeyName | |
<: !call-macro | |
macro: params.AvailabilityZone | |
<: !call-macro | |
macro: params.ServerName | |
default: myserver.example.com | |
<: !call-macro | |
macro: params.Environment | |
Mappings: | |
RegionMap: | |
us-east-1: | |
<: $${amis.myServer.us_east_1} | |
Resources: | |
<: !call-macro | |
macro: iam.ec2Setup | |
roleName: MyRole | |
instanceProfileName: MyInstanceProfile | |
policyName: my_policy_name | |
statements: | |
- Effect: Allow | |
Action: | |
- 's3:ListBucket' | |
Resource: $${s3.buckets.deploy} | |
- Effect: Allow | |
Action: | |
- 's3:GetObjects' | |
- 's3:ListObjects' | |
Resource: | |
- $${s3.paths.deploy.build_tools}/* | |
- $${s3.paths.deploy.config}/* | |
- Effect: Allow | |
Action: | |
- 's3:ListObjects' | |
Resource: | |
- $${s3.paths.deploy.build_tools}/ | |
- $${s3.paths.deploy.config}/ | |
MyServer: | |
Type: AWS::EC2::Instance | |
Properties: | |
AvailabilityZone: "@@AvailabilityZone" | |
ImageId: <% FindInMap(RegionMap, @@AWS::Region, delta) %> | |
IamInstanceProfile: my_profile_name | |
InstanceType: m3.medium | |
KeyName: "@@KeyName" | |
SecurityGroupIds: | |
- Secret Group | |
- Super Secret Group | |
Tags: !tags | |
Name: "@@ServerName" | |
Environment: "@@Environment" | |
FavoriteColor: blue | |
UserData: !call-macro | |
macro: bootstrapper.script | |
useSwap: false | |
<: !call-macro | |
macro: alarms.ec2.HighCPUAlarm | |
serverRef: "@@MyServer" | |
<: !call-macro | |
macro: bootstrapper.resources | |
timeout: 2400 | |
dependsOn: MyServer | |
Outputs: | |
<: !call-macro | |
macro: outputs.instanceID | |
server: "@@MyServer" | |
<: !call-macro | |
macro: outputs.publicAddress | |
serverResourceName: MyServer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"AWSTemplateFormatVersion": "2010-09-09", | |
"Description": "My Server Instance [v1.0]", | |
"Parameters": { | |
"KeyName": { | |
"Type": "AWS::EC2::KeyPair::KeyName", | |
"Default": "mykey", | |
"Description": "The EC2 Key Pair to allow SSH access to the gateway.", | |
"ConstraintDescription": "must be the name of an existing EC2 KeyPair.", | |
"MinLength": "1", | |
"MaxLength": "255", | |
"AllowedPattern": "[\\x20-\\x7E]*" | |
}, | |
"AvailabilityZone": { | |
"Type": "String", | |
"Default": "us-east-1a", | |
"Description": "The availability zone for the server." | |
}, | |
"ServerName": { | |
"Type": "String", | |
"Default": "myserver.example.com", | |
"Description": "The name of the server instance." | |
}, | |
"Environment": { | |
"Type": "String", | |
"Default": "production", | |
"Description": "The environment of the server instance.", | |
"ConstraintDescription": "must be a valid environment type.", | |
"AllowedValues": [ | |
"production", | |
"testing", | |
"staging" | |
] | |
} | |
}, | |
"Mappings": { | |
"RegionMap": { | |
"us-east-1": { | |
"hvm": "ami-146e2a7c" | |
} | |
} | |
}, | |
"Conditions": { | |
"IfCondition1": { | |
"Fn::Equals": [ | |
"false", | |
"true" | |
] | |
} | |
}, | |
"Resources": { | |
"MyRole": { | |
"Type": "AWS::IAM::Role", | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Effect": "Allow", | |
"Principal": { | |
"Service": [ | |
"ec2.amazonaws.com" | |
] | |
}, | |
"Action": [ | |
"sts:AssumeRole" | |
] | |
} | |
] | |
}, | |
"Path": "/", | |
"Policies": [ | |
{ | |
"PolicyName": "my_policy_name", | |
"PolicyDocument": { | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Effect": "Allow", | |
"Action": [ | |
"s3:ListBucket" | |
], | |
"Resource": "arn:aws:s3:::mybucket" | |
}, | |
{ | |
"Effect": "Allow", | |
"Action": [ | |
"s3:GetObjects", | |
"s3:ListObjects" | |
], | |
"Resource": [ | |
"arn:aws:s3:::mybucket/build-tools/*", | |
"arn:aws:s3:::mybucket/config/*" | |
] | |
}, | |
{ | |
"Effect": "Allow", | |
"Action": [ | |
"s3:ListObjects" | |
], | |
"Resource": [ | |
"arn:aws:s3:::mybucket/build-tools/", | |
"arn:aws:s3:::mybucket/config/" | |
] | |
} | |
] | |
} | |
} | |
] | |
} | |
}, | |
"MyInstanceProfile": { | |
"Type": "AWS::IAM::InstanceProfile", | |
"Properties": { | |
"Path": "/", | |
"Roles": [ | |
{ | |
"Ref": "MyRole" | |
} | |
] | |
} | |
}, | |
"MyServer": { | |
"Type": "AWS::EC2::Instance", | |
"Properties": { | |
"AvailabilityZone": { | |
"Ref": "AvailabilityZone" | |
}, | |
"ImageId": { | |
"Fn::FindInMap": [ | |
"RegionMap", | |
{ | |
"Ref": "AWS::Region" | |
}, | |
"hvm" | |
] | |
}, | |
"IamInstanceProfile": "my_profile_name", | |
"InstanceType": "m3.medium", | |
"KeyName": { | |
"Ref": "KeyName" | |
}, | |
"SecurityGroupIds": [ | |
"Secret Group", | |
"Super Secret Group" | |
], | |
"Tags": [ | |
{ | |
"Key": "Environment", | |
"Value": { | |
"Ref": "Environment" | |
} | |
}, | |
{ | |
"Key": "FavoriteColor", | |
"Value": "blue" | |
}, | |
{ | |
"Key": "Name", | |
"Value": { | |
"Ref": "ServerName" | |
} | |
} | |
], | |
"UserData": { | |
"Fn::Base64": { | |
"Fn::Join": [ | |
"", | |
[ | |
"Content-Type: multipart/mixed; boundary=\"===============2834702784899265975==\"\n", | |
"MIME-Version: 1.0\n", | |
"\n", | |
"--===============2834702784899265975==\n", | |
"Content-Type: text/cloud-config\n", | |
"MIME-Version: 1.0\n", | |
"Content-Disposition: attachment; filename=\"cloud.cfg\"\n", | |
"\n", | |
"#cloud-config\n", | |
"\n", | |
{ | |
"Fn::If": [ | |
"IfCondition1", | |
{ | |
"Fn::Join": [ | |
"", | |
[ | |
"mounts:\n", | |
" - [ ephemeral0, none, swap, sw, 0, 0 ]\n", | |
"\n", | |
"bootcmd:\n", | |
" - mkswap /dev/xvdb\n", | |
" - swapon /dev/xvdb\n" | |
] | |
] | |
}, | |
{ | |
"Ref": "AWS::NoValue" | |
} | |
] | |
}, | |
"--===============2834702784899265975==\n", | |
"Content-Type: text/x-shellscript\n", | |
"MIME-Version: 1.0\n", | |
"Content-Disposition: attachment; filename=\"script.sh\"\n", | |
"\n", | |
"#!/bin/bash -v\n", | |
"yum update -y\n", | |
"\n", | |
"function error_exit {\n", | |
" /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", | |
{ | |
"Ref": "WaitHandle" | |
}, | |
"'\n", | |
" exit 1\n", | |
"}\n", | |
"\n", | |
"# XXX Do some stuff here for bootstrapping the server.\n", | |
"\n", | |
"/opt/aws/bin/cfn-signal -e 0 -r \"Bootstrap complete.\" '", | |
{ | |
"Ref": "WaitHandle" | |
}, | |
"'\n", | |
"--===============2834702784899265975==--\n" | |
] | |
] | |
} | |
} | |
} | |
}, | |
"HighCPUAlarm": { | |
"Type": "AWS::CloudWatch::Alarm", | |
"Properties": { | |
"AlarmDescription": { | |
"Fn::Join": [ | |
"", | |
[ | |
"[", | |
{ | |
"Ref": "ServerName" | |
}, | |
"] Alert if CPU > 80% for 5 minutes" | |
] | |
] | |
}, | |
"MetricName": "CPUUtilization", | |
"Namespace": "AWS/EC2", | |
"Statistic": "Average", | |
"Period": "300", | |
"EvaluationPeriods": "1", | |
"Threshold": "80", | |
"ComparisonOperator": "GreaterThanOrEqualToThreshold", | |
"AlarmActions": [ | |
"arn:aws:sns:us-east-1:1234567890:PagerDuty" | |
], | |
"InsufficientDataActions": [ | |
"arn:aws:sns:us-east-1:1234567890:PagerDuty" | |
], | |
"Dimensions": [ | |
{ | |
"Name": "InstanceId", | |
"Value": { | |
"Ref": "MyServer" | |
} | |
} | |
] | |
} | |
}, | |
"WaitHandle": { | |
"Type": "AWS::CloudFormation::WaitConditionHandle" | |
}, | |
"WaitCondition": { | |
"Type": "AWS::CloudFormation::WaitCondition", | |
"DependsOn": "MyServer", | |
"Properties": { | |
"Handle": { | |
"Ref": "WaitHandle" | |
}, | |
"Timeout": "2400" | |
} | |
} | |
}, | |
"Outputs": { | |
"InstanceID": { | |
"Description": "The ID of the server instance.", | |
"Value": { | |
"Ref": "MyServer" | |
} | |
}, | |
"PublicAddress": { | |
"Description": "The public address of the server instance.", | |
"Value": { | |
"Fn::GetAtt": [ | |
"MyServer", | |
"PublicDnsName" | |
] | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment