Created
March 22, 2019 09:58
-
-
Save dhardy92/f6da8ee062c80d9e9513cabb0b1c122b to your computer and use it in GitHub Desktop.
Amazon AWS AutoscaleGroup of spot instance with ElasticIP
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 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