Low cost AWS VPC for an Amazon ECS cluster
About
Amazon Virtual Private Cloud (Amazon VPC) gives you full control over your virtual networking environment, including resource placement, connectivity, and security.
The ideal way to configure a VPC is to use both public and private subnets. The public subnets are used for hosting internet facing resources like load balancers, while the private subnets are used to host application containers and other private resources.
However, private subnets need a NAT gateway for internet access, and NAT gateways comes with both an hourly fee, as well as an additional charge per GB of data that goes through the NAT gateway.
For this reason you may prefer to use a VPC that has exclusively public subnets. You can always upgrade to add NAT gateways and private subnets later on.
Architecture
The following diagram shows the architecture of what will be created:
- The VPC that is created spans two availability zones. This gives you increased availability.
- Each AZ has a single public subnet. Internet traffic originating from these subnets goes directly to the internet gateway.
INFO
This low cost architecture is designed for very small deployments, as each resource launched into the public subnet must have a public IPv4 address assigned to it in order to actually use the internet gateway.
As of February 1, 2024 all public IPv4 addresses on your AWS account are billed. Large deployments that would require many public IPv4 addresses should migrate to a more complex but cost efficient architecture that utilizes private subnets and private IP addresses. See the following two options:
Subnet Compatibility
For this example VPC the following table shows subnet support for internet access and networking across each capacity and networking mode.
Configuration | Public Subnets |
---|---|
EC2 Bridge mode | ✅ |
EC2 Host mode | ✅ |
EC2 AWS VPC | ❌ (not supported, EC2 tasks don't have public IP's) |
Fargate AWS VPC | ❗ (requires assign public IP) |
DANGER
AWS VPC on EC2 will not work in this VPC because task ENI's on EC2 can not be assigned public IP addresses, and therefore the task can not utilize the internet gateway.
WARNING
AWS Fargate tasks must be launched with "assign public IP" turned on. This allows them to use the internet gateway directly. But if you don't turn on public IP assignment then internet access will not work.
VPC Configuration
Deploy the following CloudFormation template to create the VPC:
AWSTemplateFormatVersion: '2010-09-09'
Description: This stack deploys a large AWS VPC with internet access
Mappings:
# Hard values for the subnet masks. These masks define
# the range of internal IP addresses that can be assigned.
# The VPC can have all IP's from 10.0.0.0 to 10.0.255.255
# There are two subnets which cover the ranges:
#
# 10.0.0.0 - 10.0.63.255 (16384 IP addresses)
# 10.0.64.0 - 10.0.127.255 (16384 IP addresses)
#
SubnetConfig:
VPC:
CIDR: '10.0.0.0/16'
PublicOne:
CIDR: '10.0.0.0/18'
PublicTwo:
CIDR: '10.0.64.0/18'
Resources:
# VPC in which containers will be networked.
# It has two public subnets.
# We distribute the subnets across the first two available subnets
# for the region, for high availability.
VPC:
Type: AWS::EC2::VPC
Properties:
EnableDnsSupport: true
EnableDnsHostnames: true
CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
# Two public subnets, where containers can have public IP addresses
PublicSubnetOne:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: {Ref: 'AWS::Region'}
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
MapPublicIpOnLaunch: true
PublicSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: {Ref: 'AWS::Region'}
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
MapPublicIpOnLaunch: true
# Setup networking resources for the public subnets. Containers
# in the public subnets have public IP addresses and the routing table
# sends network traffic via the internet gateway.
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
Outputs:
VpcId:
Description: The ID of the VPC that this stack is deployed in
Value: !Ref 'VPC'
PublicSubnetIds:
Description: Comma seperated list of public facing subnets that have
a direct internet connection as long as you assign a public IP
Value: !Sub '${PublicSubnetOne},${PublicSubnetTwo}'
Some things to note:
This pattern VPC has two public subnets, each with 16,384
addresses. These subnets should be used to hosting public facing load balancers, or other similar resources that are intended to accept direct inbound traffic from the internet.
Usage
Deploy the template via the AWS CloudFormation console, or with a CLI command like this:
aws cloudformation deploy \
--stack-name big-vpc \
--template-file vpc.yml
The deployed template has Outputs
that you can pass into other stacks:
VpcId
- Many other AWS resources will need to know the ID of the VPC that they are placed in.PublicSubnetIds
- A comma separated list of the subnet ID's that have direct internet access.
Next Steps
- This template only provisions two subnets. For even greater availability consider adding a third public subnet.
- If you wish to utilize AWS VPC networking mode on EC2 or just want to run your application containers in a private subnet then considering upgrading to the large VPC for Amazon ECS cluster.