Skip to content

Instantly share code, notes, and snippets.

@kuleszaj
Created April 18, 2017 01:38
Show Gist options
  • Save kuleszaj/6144c2153fd04cb104429cc81e58cf82 to your computer and use it in GitHub Desktop.
Save kuleszaj/6144c2153fd04cb104429cc81e58cf82 to your computer and use it in GitHub Desktop.
AWS CloudFormation template including EFS mount script.
AWSTemplateFormatVersion: '2010-09-09'
Description: >
AWS CloudFormation template to create a new VPC
or use an existing VPC for ECS deployment
in Create Cluster Wizard
Parameters:
EcsClusterName:
Type: String
Description: >
Specifies the ECS Cluster Name with which the resources would be
associated
Default: default
EcsAmiId:
Type: String
Description: Specifies the AMI ID for your container instances.
EcsInstanceType:
Type: String
Description: >
Specifies the EC2 instance type for your container instances.
Defaults to m4.large
Default: m4.large
ConstraintDescription: must be a valid EC2 instance type.
KeyName:
Type: String
Description: >
Optional - Specifies the name of an existing Amazon EC2 key pair
to enable SSH access to the EC2 instances in your cluster.
Default: ''
VpcId:
Type: String
Description: >
Optional - Specifies the ID of an existing VPC in which to launch
your container instances. If you specify a VPC ID, you must specify a list of
existing subnets in that VPC. If you do not specify a VPC ID, a new VPC is created
with atleast 1 subnet.
Default: ''
AllowedPattern: "^(?:vpc-[0-9a-f]{8}|)$"
ConstraintDescription: >
VPC Id must begin with 'vpc-' or leave blank to have a
new VPC created
SubnetIds:
Type: CommaDelimitedList
Description: >
Optional - Specifies the Comma separated list of existing VPC Subnet
Ids where ECS instances will run
Default: ''
SecurityGroupId:
Type: String
Description: >
Optional - Specifies the Security Group Id of an existing Security
Group. Leave blank to have a new Security Group created
Default: ''
VpcCidr:
Type: String
Description: Optional - Specifies the CIDR Block of VPC
Default: ''
SubnetCidr1:
Type: String
Description: Specifies the CIDR Block of Subnet 1
Default: ''
SubnetCidr2:
Type: String
Description: Specifies the CIDR Block of Subnet 2
Default: ''
SubnetCidr3:
Type: String
Description: Specifies the CIDR Block of Subnet 3
Default: ''
AsgMaxSize:
Type: Number
Description: >
Specifies the number of instances to launch and register to the cluster.
Defaults to 1.
Default: '1'
IamRoleInstanceProfile:
Type: String
Description: >
Specifies the Name or the Amazon Resource Name (ARN) of the instance
profile associated with the IAM role for the instance
SecurityIngressFromPort:
Type: Number
Description: >
Optional - Specifies the Start of Security Group port to open on
ECS instances - defaults to port 0
Default: '0'
SecurityIngressToPort:
Type: Number
Description: >
Optional - Specifies the End of Security Group port to open on ECS
instances - defaults to port 65535
Default: '65535'
SecurityIngressCidrIp:
Type: String
Description: >
Optional - Specifies the CIDR/IP range for Security Ports - defaults
to 0.0.0.0/0
Default: 0.0.0.0/0
EcsEndpoint:
Type: String
Description: >
Optional - Specifies the ECS Endpoint for the ECS Agent to connect to
Default: ''
VpcAvailabilityZones:
Type: CommaDelimitedList
Description: >
Specifies a comma-separated list of 3 VPC Availability Zones for
the creation of new subnets. These zones must have the available status.
Default: ''
EbsVolumeSize:
Type: Number
Description: >
Optional - Specifies the Size in GBs, of the newly created Amazon
Elastic Block Store (Amazon EBS) volume
Default: '0'
EbsVolumeType:
Type: String
Description: Optional - Specifies the Type of (Amazon EBS) volume
Default: ''
AllowedValues:
- ''
- standard
- io1
- gp2
- sc1
- st1
ConstraintDescription: Must be a valid EC2 volume type.
DeviceName:
Type: String
Description: Optional - Specifies the device mapping for the Volume
Default: ''
Conditions:
CreateEC2LCWithKeyPair:
!Not [!Equals [!Ref KeyName, '']]
SetEndpointToECSAgent:
!Not [!Equals [!Ref EcsEndpoint, '']]
CreateNewSecurityGroup:
!Equals [!Ref SecurityGroupId, '']
CreateNewVpc:
!Equals [!Ref VpcId, '']
CreateSubnet1: !And
- !Not [!Equals [!Ref SubnetCidr1, '']]
- !Condition CreateNewVpc
CreateSubnet2: !And
- !Not [!Equals [!Ref SubnetCidr2, '']]
- !Condition CreateSubnet1
CreateSubnet3: !And
- !Not [!Equals [!Ref SubnetCidr3, '']]
- !Condition CreateSubnet2
CreateEbsVolume: !And
- !Not [!Equals [!Ref EbsVolumeSize, '0']]
- !Not [!Equals [!Ref EbsVolumeType, '']]
- !Not [!Equals [!Ref DeviceName, '']]
Resources:
Vpc:
Condition: CreateSubnet1
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
PubSubnetAz1:
Condition: CreateSubnet1
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref SubnetCidr1
AvailabilityZone: !Select [ 0, !Ref VpcAvailabilityZones ]
PubSubnetAz2:
Condition: CreateSubnet2
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref SubnetCidr2
AvailabilityZone: !Select [ 1, !Ref VpcAvailabilityZones ]
PubSubnetAz3:
Condition: CreateSubnet3
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref SubnetCidr3
AvailabilityZone: !Select [ 2, !Ref VpcAvailabilityZones ]
InternetGateway:
Condition: CreateSubnet1
Type: AWS::EC2::InternetGateway
AttachGateway:
Condition: CreateSubnet1
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref Vpc
InternetGatewayId: !Ref InternetGateway
RouteViaIgw:
Condition: CreateSubnet1
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
PublicRouteViaIgw:
Condition: CreateSubnet1
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref RouteViaIgw
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PubSubnet1RouteTableAssociation:
Condition: CreateSubnet1
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PubSubnetAz1
RouteTableId: !Ref RouteViaIgw
PubSubnet2RouteTableAssociation:
Condition: CreateSubnet2
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PubSubnetAz2
RouteTableId: !Ref RouteViaIgw
PubSubnet3RouteTableAssociation:
Condition: CreateSubnet3
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PubSubnetAz3
RouteTableId: !Ref RouteViaIgw
EcsSecurityGroup:
Condition: CreateNewSecurityGroup
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ECS Allowed Ports
VpcId: !If [ CreateSubnet1, !Ref Vpc, !Ref VpcId ]
SecurityGroupIngress:
IpProtocol: tcp
FromPort: !Ref SecurityIngressFromPort
ToPort: !Ref SecurityIngressToPort
CidrIp: !Ref SecurityIngressCidrIp
EcsInstanceLc:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !Ref EcsAmiId
InstanceType: !Ref EcsInstanceType
AssociatePublicIpAddress: false
IamInstanceProfile: !Ref IamRoleInstanceProfile
KeyName: !If [ CreateEC2LCWithKeyPair, !Ref KeyName, !Ref "AWS::NoValue" ]
SecurityGroups: [ !If [ CreateNewSecurityGroup, !Ref EcsSecurityGroup, !Ref SecurityGroupId ] ]
BlockDeviceMappings: !If
- CreateEbsVolume
-
- DeviceName: !Ref DeviceName
Ebs:
VolumeSize: !Ref EbsVolumeSize
VolumeType: !Ref EbsVolumeType
- !Ref "AWS::NoValue"
UserData:
Fn::Base64: !Join
-
""
-
- !If
- SetEndpointToECSAgent
- !Sub |
#!/bin/bash
echo ECS_CLUSTER=${EcsClusterName} >> /etc/ecs/ecs.config
echo ECS_BACKEND_HOST=${EcsEndpoint} >> /etc/ecs/ecs.config
- !Sub |
#!/bin/bash
echo ECS_CLUSTER=${EcsClusterName} >> /etc/ecs/ecs.config
- |
yum update -y
yum install -y jq nfs-utils python27 python27-pip awscli
pip install --upgrade awscli
EFS_FILE_SYSTEM_NAME="my-efs-filesystem"
EC2_AVAIL_ZONE="$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)"
EC2_REGION="$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')"
DIR_TGT="/mnt/efs"
mkdir "${DIR_TGT}"
EFS_FILE_SYSTEM_ID="$(/usr/local/bin/aws efs describe-file-systems --region "${EC2_REGION}" | jq '.FileSystems[]' | jq "select(.Name==\"${EFS_FILE_SYSTEM_NAME}\")" | jq -r '.FileSystemId')"
if [ -z "${EFS_FILE_SYSTEM_ID}" ]; then
echo "ERROR: variable not set" 1> /etc/efssetup.log
exit
fi
DIR_SRC="${EC2_AVAIL_ZONE}.${EFS_FILE_SYSTEM_ID}.efs.${EC2_REGION}.amazonaws.com"
mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,soft,timeo=600,retrans=2 "${DIR_SRC}:/" "${DIR_TGT}"
cp -p "/etc/fstab" "/etc/fstab.back-$(date +%F)"
echo -e "${DIR_SRC}:/ \t\t ${DIR_TGT} \t\t nfs \t\t nfsvers=4.1,rsize=1048576,wsize=1048576,soft,timeo=600,retrans=2 \t\t 0 \t\t 0" | tee -a /etc/fstab
docker stop ecs-agent
/etc/init.d/docker restart
docker start ecs-agent
EcsInstanceAsg:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier: !If
- CreateSubnet1
- !If
- CreateSubnet2
- !If
- CreateSubnet3
- [ !Sub "${PubSubnetAz1}, ${PubSubnetAz2}, ${PubSubnetAz3}" ]
- [ !Sub "${PubSubnetAz1}, ${PubSubnetAz2}" ]
- [ !Sub "${PubSubnetAz1}" ]
- !Ref SubnetIds
LaunchConfigurationName: !Ref EcsInstanceLc
MinSize: '0'
MaxSize: !Ref AsgMaxSize
DesiredCapacity: !Ref AsgMaxSize
Tags:
-
Key: Name
Value: !Sub "ECS Instance - ${AWS::StackName}"
PropagateAtLaunch: 'true'
-
Key: Description
Value: "This instance is the part of the Auto Scaling group which was created through ECS Console"
PropagateAtLaunch: 'true'
Outputs:
EcsInstanceAsgName:
Description: Auto Scaling Group Name for ECS Instances
Value: !Ref EcsInstanceAsg
UsedByECSCreateCluster:
Description: Flag used by EC2 Container Service Create Cluster Wizard
Value: 'true'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment