Low cost AWS VPC for an Amazon ECS cluster

Nathan Peck profile picture
Nathan Peck
Senior Developer Advocate at AWS

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:

VPCPublic subnetPublic subnetInternet gatewayOutbound internet trafficOutbound internet traffic

  • 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.

ConfigurationPublic 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:

File: vpc.ymlLanguage: yml
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:

Language: shell
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.