Skip to content

Instantly share code, notes, and snippets.

@sunds
Created January 8, 2018 17:43
Show Gist options
  • Save sunds/ddf4047bbc4f67281261054c1c306105 to your computer and use it in GitHub Desktop.
Save sunds/ddf4047bbc4f67281261054c1c306105 to your computer and use it in GitHub Desktop.
AWS Fargate ECS cloudformation templete
#
# Sample CloudFormation template for AWS Fargate.
#
# This template builds a new VPC with two public subnets plus an internet gateway and associated security groups.
# It adds an application load balancer with SSL using a certificate of your specification (Use AWS certificate manager to issue)
# It then configures an ECS service running a docker image. This example used the AWS ECS sample application (a small PHP app).
# You would replace that one with yours.
#
# Before you start:
#
# 1) Have ECR (AWS container registry) created and have your image loaded there.
# 2) Optionally have a certificate generated for your site and its ARN ready
# 3) Determine the CIDR and subnets you'd like to use for your new VPC.
#
# Example:
# aws cloudformation deploy --stack-name mystack
# --template-file templates/environment.yaml
# --parameter-overrides Name=dev-vpc VpcCIDR=10.20.0.0/16 Subnet1CIDR=10.20.1.0/24 Subnet2CIDR=10.20.2.0/24 Certificate=arn:aws:acm:us-east-1:AWSACCOUNT:certificate/UUID
# --capabilities CAPABILITY_IAM
#
Description: >
A complete environment using AWS ECS Fargate
A VPC with two public subnets, internet gateway, and application load balancer
Parameters:
Name:
Type: String
VpcCIDR:
Type: String
Subnet1CIDR:
Type: String
Subnet2CIDR:
Type: String
Repository:
Type: String
Default: my-service
InstanceCount:
Type: Number
Default: 1
Certificate:
Type: String
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
Tags:
- Key: Name
Value: !Ref Name
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref Name
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs ]
MapPublicIpOnLaunch: true
CidrBlock: !Ref Subnet1CIDR
Tags:
- Key: Name
Value: !Sub ${Name} (Public)
Subnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs ]
MapPublicIpOnLaunch: true
CidrBlock: !Ref Subnet2CIDR
Tags:
- Key: Name
Value: !Sub ${Name} (Public)
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref Name
DefaultRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
Subnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref Subnet1
Subnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref Subnet2
VPCSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: !Sub ${AWS::StackName}-ingress
SecurityGroupIngress:
- CidrIp: "0.0.0.0/0"
IpProtocol: "TCP"
FromPort: 443
ToPort: 443
- CidrIp: "0.0.0.0/0"
IpProtocol: "TCP"
FromPort: 80
ToPort: 80
VpcId: !Ref VPC
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Ref Name
Subnets:
- !Ref Subnet1
- !Ref Subnet2
SecurityGroups:
- !Ref VPCSecurityGroup
LoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Port: 443
Protocol: HTTPS
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
Certificates:
- CertificateArn: !Ref Certificate
SslPolicy: ELBSecurityPolicy-TLS-1-2-2017-01
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref AWS::StackName
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
TargetType: ip
Port: 80
Protocol: HTTP
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 30
Tags:
- Key: Image
Value: latest
- Key: Name
Value: !Ref Name
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
Conditions:
- Field: path-pattern
Values:
- "*"
ListenerArn: !Ref LoadBalancerListener
Priority: 1
TaskIamRole:
Type: AWS::IAM::Role
Properties:
Path: /
AssumeRolePolicyDocument: |
{
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": [ "ecs-tasks.amazonaws.com" ]},
"Action": [ "sts:AssumeRole" ]
}]
}
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
ECSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub ${AWS::StackName}
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref VPCSecurityGroup
IpProtocol: -1
VpcId: !Ref VPC
Service:
Type: AWS::ECS::Service
DependsOn:
- LoadBalancerListener
Properties:
Cluster: !Ref Cluster
DesiredCount: !Ref InstanceCount
LaunchType: FARGATE
TaskDefinition: !Ref TaskDefinition
DeploymentConfiguration:
MinimumHealthyPercent: 0
LoadBalancers:
- ContainerName: !Ref Repository
ContainerPort: 80
TargetGroupArn: !Ref TargetGroup
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !GetAtt ECSSecurityGroup.GroupId
Subnets:
- !Ref Subnet1
- !Ref Subnet2
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Cpu: 256
Memory: 512
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
ExecutionRoleArn: !GetAtt TaskIamRole.Arn
TaskRoleArn: !GetAtt TaskIamRole.Arn
ContainerDefinitions:
- Name: !Ref Repository
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Repository}:latest
EntryPoint:
- /usr/sbin/apache2
- -D
- FOREGROUND
Essential: true
Memory: 512
PortMappings:
- ContainerPort: 80
Environment:
- Name: Tag
Value: latest
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: us-east-1
awslogs-stream-prefix: !Sub ${AWS::StackName}
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub ${AWS::StackName}
RetentionInDays: 30
Outputs:
Subnet1:
Value: !Ref Subnet1
Subnet2:
Value: !Ref Subnet2
VpcId:
Value: !Ref VPC
ServiceUrl:
Description: URL of the load balancer for the sample service.
Value: !Sub http://${LoadBalancer.DNSName}
SecurityGroup:
Value: !Ref VPCSecurityGroup
LoadBalancerArn:
Value: !Ref LoadBalancer
@sunds
Copy link
Author

sunds commented Jan 8, 2018

Note that AssignPublicIp must be ENABLED in this configuration. Internet gateways only perform 1-to-1 NAT. Any container wanting to reach the internet must have a public IP assigned in order for the return traffic to be routable. Security groups prevent general access to the containers.

An alternative would be to set up public and provide subnets with AWS NAT instances if your deployment needs this complexity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment