DEV Community

JM Rifkhan for AWS Community Builders

Posted on

Mastering AWS ECS with CloudFormation: A Comprehensive Guide

Introduction

In the dynamic landscape of cloud computing, efficient and secure infrastructure deployment is a cornerstone of success. AWS CloudFormation represents a powerful tool in this realm, offering automation and precision. This comprehensive guide dives into a CloudFormation template designed for establishing an Elastic Container Service (ECS) cluster across public and private subnets—a configuration that balances accessibility, security, and optimal performance.

Understanding CloudFormation and ECS

Before we delve into the template, let's understand the key concepts:

AWS CloudFormation

CloudFormation is an AWS service that helps you model and set up your Amazon Web Services resources. It allows you to use a simple text file to automate and manage the deployment of resources, avoiding the time-consuming and error-prone manual process.

AWS Elastic Container Service (ECS)

ECS is a highly scalable, high-performance container orchestration service that supports Docker containers and allows you to easily run applications on a managed cluster of Amazon EC2 instances or AWS Fargate.

The Architecture Overview

The proposed architecture uses AWS CloudFormation to automate the deployment of an ECS cluster. This architecture is designed to provide:

Scalability to handle varying loads.
Enhanced security through isolated network environments.
High availability across multiple availability zones.

Architecture Diagram

Detailed Breakdown of the CloudFormation Template

This section will cover each component of the CloudFormation template in detail.

VPC and Subnet Configuration

VPC Setup
CIDR Block: The VPC is configured with a 10.0.0.0/16 CIDR block, offering a large range of IP addresses.
DNS Support: DNS support and hostnames are enabled for better network management and resolution.

Subnet Planning
Public Subnets: Two public subnets are designed for resources that need to be connected to the internet.
Private Subnets: Two private subnets are used for backend systems that don't require direct internet access.

VPC

Subnets

Internet Gateway and Routing

Internet Gateway
The Internet Gateway serves as a bridge between the VPC and the internet, facilitating communication for resources in the public subnet.

Route Tables
Public Route Table: Routes traffic from the public subnet to the Internet Gateway.
Private Route Table: Manages internal traffic within the VPC.

Internet Gateway

Route Tables

NAT Gateways for Private Subnet Internet Access

The NAT Gateways are crucial for allowing resources in the private subnets to access the internet for updates and patches while keeping them secure from inbound internet traffic.

NAT Gateways

Elastic Load Balancing

Application Load Balancer (ALB)
Placement: Located within the public subnets to balance incoming internet traffic.
Functionality: Distributes traffic to different targets within the ECS cluster based on predefined rules, enhancing performance and fault tolerance.

Load Balancer

ECS Cluster Setup

Fargate Integration
Serverless Approach: Utilizing AWS Fargate removes the need to provision and manage servers for containerized applications.
Cluster Configuration: The template includes the setup for an ECS cluster, ready to host containerized applications.

ECS Cluster

Security Groups and Network Access

Security Group for ALB
Regulates the traffic to and from the load balancer, ensuring that only legitimate requests reach the application services.
Container Security Group
Controls the communication between the load balancer and the ECS services, crucial for maintaining the integrity and security of the applications.

Setting Up an ECS Service and Task Definition

After discussing the theoretical aspects of the architecture and CloudFormation, it's time to show a practical implementation. Once the infrastructure is in place, the next critical steps involve creating the ECS service and task definitions.

ECS Service and Task Definition

An ECS service is a configuration that enables you to run and maintain a specified number of instances of a task definition simultaneously. A task definition is a blueprint for your application that describes one or more containers.

Task Definition

Creating an ECS Service

In our setup, we've created an ECS service that utilizes a task definition to deploy a react-app. Here's a breakdown of the components involved:
ecs-svc

Launch Type: Utilizes Fargate for serverless deployment.
Load Balancer: An Application Load Balancer is configured to distribute traffic to the containers.

Network and Security Configuration

Network Configuration: The service is associated with the VPC and subnets created by our CloudFormation template.
Security Groups: Security groups are assigned to the service to control the traffic according to the predefined rules.

Testing the Load Balancer

With the ECS service deployed, the final step is to verify that the Application Load Balancer correctly distributes incoming traffic to our react-app service.

DNS Record Testing: By accessing the DNS name provided by the load balancer, you can confirm that the service is reachable and that the load balancing is functioning as expected.

testing-alb

CloudFormation Template and Deployment

Here, I provide the entire CloudFormation template code. This template is the blueprint for the entire infrastructure setup described above.



AWSTemplateFormatVersion: '2010-09-09'
Description: AWS core resources to create an ECS cluster spanning public and private subnets. Supports
public facing load balancers.
Mappings:
SubnetConfig:
VPC:
CIDR: '10.0.0.0/16'
PublicOne:
CIDR: '10.0.0.0/24'
PublicTwo:
CIDR: '10.0.1.0/24'
PrivateOne:
CIDR: '10.0.2.0/24'
PrivateTwo:
CIDR: '10.0.3.0/24'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
EnableDnsSupport: true
EnableDnsHostnames: true
CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']

PublicSubnetOne:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
MapPublicIpOnLaunch: true
PublicSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
MapPublicIpOnLaunch: true

PrivateSubnetOne:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR']
PrivateSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR']

InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachement:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref 'VPC'
InternetGatewayId: !Ref 'InternetGateway'
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
PublicRoute:
Type: AWS::EC2::Route
DependsOn: GatewayAttachement
Properties:
RouteTableId: !Ref 'PublicRouteTable'
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref 'InternetGateway'
PublicSubnetOneRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetOne
RouteTableId: !Ref PublicRouteTable
PublicSubnetTwoRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetTwo
RouteTableId: !Ref PublicRouteTable

NatGatewayOneAttachment:
Type: AWS::EC2::EIP
DependsOn: GatewayAttachement
Properties:
Domain: vpc
NatGatewayTwoAttachment:
Type: AWS::EC2::EIP
DependsOn: GatewayAttachement
Properties:
Domain: vpc
NatGatewayOne:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayOneAttachment.AllocationId
SubnetId: !Ref PublicSubnetOne
NatGatewayTwo:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayTwoAttachment.AllocationId
SubnetId: !Ref PublicSubnetTwo
PrivateRouteTableOne:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
PrivateRouteOne:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableOne
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayOne
PrivateRouteTableOneAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTableOne
SubnetId: !Ref PrivateSubnetOne
PrivateRouteTableTwo:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
PrivateRouteTwo:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableTwo
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayTwo
PrivateRouteTableTwoAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTableTwo
SubnetId: !Ref PrivateSubnetTwo

####
# ALB related resources
####
PublicLoadBalancerSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the public facing load balancer
VpcId: !Ref 'VPC'
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
PublicLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
LoadBalancerAttributes:
- Key: idle_timeout.timeout_seconds
Value: '30'
Subnets:
- !Ref 'PublicSubnetOne'
- !Ref 'PublicSubnetTwo'
SecurityGroups: [!Ref 'PublicLoadBalancerSG']
# A dummy target group is used to setup the ALB to just drop traffic
# initially, before any real service target groups have been added.
DummyTargetGroupPublic:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 6
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Port: 80
Protocol: HTTP
UnhealthyThresholdCount: 2
VpcId: !Ref 'VPC'
PublicLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn:
- PublicLoadBalancer
Properties:
DefaultActions:
- TargetGroupArn: !Ref 'DummyTargetGroupPublic'
Type: 'forward'
LoadBalancerArn: !Ref 'PublicLoadBalancer'
Port: 80
Protocol: HTTP
####
# ECS related resources
####
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: 'enhanced-architecture-fargate'
ContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the containers
VpcId: !Ref 'VPC'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'

######################################
Outputs:
VpcId:
Description: The ID of the VPC that this stack is deployed in
Value: !Ref 'VPC'
PublicSubnetOne:
Description: Public subnet one
Value: !Ref 'PublicSubnetOne'
PublicSubnetTwo:
Description: Public subnet two
Value: !Ref 'PublicSubnetTwo'
PrivateSubnetOne:
Description: Private subnet one
Value: !Ref 'PrivateSubnetOne'
PrivateSubnetTwo:
Description: Private subnet two
Value: !Ref 'PrivateSubnetTwo'
ExternalUrl:
Description: The url of the external load balancer
Value: !Sub http://${PublicLoadBalancer.DNSName}

Enter fullscreen mode Exit fullscreen mode




Deploying the Stack with AWS CLI

To deploy this CloudFormation stack, you can use the following AWS CLI command. This command initializes the creation of the resources as defined in the template.



aws cloudformation create-stack --capabilities CAPABILITY_IAM --stack-name enhanced-architecture --template-body file://./path_to_template_file.yaml

Enter fullscreen mode Exit fullscreen mode




Benefits of This Architecture

Scalability

The setup is inherently scalable, easily adapting to increased traffic and workloads without significant manual intervention.

Security

The segregation of public and private subnets ensures a secure environment for backend services, protecting sensitive data and operations.

High Availability

The multi-AZ deployment ensures that the system remains operational and robust, even in the event of an individual zone's failure.

Cost-Efficiency

With AWS Fargate, you only pay for the resources your containers use, leading to optimized costs especially beneficial for varying workloads.

Conclusion

This guide presents a detailed view of deploying a scalable, secure, and highly available ECS cluster using AWS CloudFormation. The provided template is a robust foundation for any organization looking to leverage the power of AWS for their containerized applications. By automating infrastructure deployment, this approach not only saves time but also significantly reduces the potential for error, ensuring a reliable and efficient cloud environment.

References and Further Reading

The journey through AWS ECS and CloudFormation doesn't stop here. For those eager to delve deeper and expand their knowledge, the following resources offer a wealth of information:

  1. AWS CloudFormation User Guide

    A comprehensive guide to AWS CloudFormation, detailing concepts, template references, and best practices.

    AWS CloudFormation User Guide

  2. AWS Elastic Container Service Documentation

    Everything you need to know about ECS, from basics to advanced topics, is covered in the official AWS documentation.

    AWS ECS Documentation

  3. AWS Fargate Documentation

    Learn more about the serverless compute engine for containers and how to use it with ECS.

    AWS Fargate Documentation

  4. Best Practices for Security in Amazon ECS

    Understand how to secure your containerized applications and infrastructure in ECS.

    Security Best Practices in Amazon ECS

Peace!✌️

Top comments (0)