Skip to content

Instantly share code, notes, and snippets.

@dhardy92
Created March 22, 2019 09:58
Show Gist options
  • Save dhardy92/f6da8ee062c80d9e9513cabb0b1c122b to your computer and use it in GitHub Desktop.
Save dhardy92/f6da8ee062c80d9e9513cabb0b1c122b to your computer and use it in GitHub Desktop.
Amazon AWS AutoscaleGroup of spot instance with ElasticIP
# A domain zone not hosted on AWS::Route53 and we want domain root record to exists (require a A record).
# ELB/Cloudfront is not static and change IP all the time.
# We cannot associare ElasticIP with ELB.
# We want some failover on this tiny stack
# AutoscaleGroup cannot associate ELasticIP to an instance.
# In internet gateway enabled subnet, instance without ElasticIP cannot use AWS API (no public network)
# Here is my solution :
# * AutoscaleGroup for resilience of spot instance
# * Lambda runing python for ElasticIP association on ASG launch instance event.
# LIMITATION:
# As first instance should be created before event rule exists,
# you should terminate this very first instance on your own
# so that lambda can associate ElasticIP to the second one (emiting an event)
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ImageId:
Description: ImageId to use
Type: String
VpcId:
Description: Id of the VPC where to deploy this app
Type: AWS::EC2::VPC::Id
EC2SubnetsIds:
Description: Subnet IDs where to put the instance.
Type: List<AWS::EC2::Subnet::Id>
RoleTag:
Description: The role of the instance
Type: String
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
Type: AWS::EC2::KeyPair::KeyName
Resources:
EventRule:
Type: AWS::Events::Rule
Properties:
Description: Events rule for Autoscaling
EventPattern:
detail-type: [ 'EC2 Instance Launch Successful' ]
source: [ 'aws.autoscaling' ]
detail:
AutoScalingGroupName:
- !Ref AutoScalingGroup
State: ENABLED
Targets:
- Arn: !Sub '${LambdaFunction.Arn}'
Id: !Ref LambdaFunction
LambdaFunction:
Type: AWS::Lambda::Function
DependsOn:
- LambdaFunctionRole
- ElasticIP
Properties:
Environment:
Variables:
AllocationId: !Sub "${ElasticIP.AllocationId}"
Description: |
Associate public ElasticIP to AutoscaleGroup new instance.
Code:
ZipFile: |
import boto3
import os
def handler(event, context):
print(event)
instance_id = event["detail"]["EC2InstanceId"]
client = boto3.client('ec2')
response = client.associate_address(
AllocationId=os.getenv('AllocationId', None),
InstanceId=instance_id,
AllowReassociation=True,
)
print(response)
return
Handler: index.handler
Role: !Sub '${LambdaFunctionRole.Arn}'
Runtime: python3.7
LambdaFunctionPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Sub '${LambdaFunction.Arn}'
Principal: events.amazonaws.com
SourceArn: !Sub '${EventRule.Arn}'
LambdaFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Path: /
Policies:
- PolicyName: ec2AssociateAddress
PolicyDocument:
Statement:
- Action: ec2:AssociateAddress
Effect: Allow
Resource: '*'
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
DependsOn:
- LambdaFunction
Properties:
LaunchConfigurationName: !Ref LaunchConfiguration
MinSize: 1
MaxSize: 1
VPCZoneIdentifier: !Ref EC2SubnetsIds
Tags:
- Key: Name
Value: !Ref RoleTag
PropagateAtLaunch: "true"
- Key: role
Value: !Ref RoleTag
PropagateAtLaunch: "true"
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
KeyName: !Ref KeyName
ImageId: !Ref ImageId
InstanceType: t3.small
SecurityGroups:
- !Ref InstanceSecurityGroup
IamInstanceProfile: !Ref ServerInstanceProfile
SpotPrice: 0.03 # change according to InstanceType and current auction
ServerInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref Role
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: DefaultInstancesRoles
PolicyDocument:
Statement:
- Action:
- ec2:AssociateAddress
Effect: Allow
Resource: "*"
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable SSH access and HTTP access on the configured port
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
CidrIp: 0.0.0.0/0
- IpProtocol: icmp
FromPort: '-1'
ToPort: '-1'
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub "ec2-${RoleTag}-sg"
- Key: role
Value: !Ref RoleTag
ElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment