Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples for ECS in dual-stack mode(IPv4 and IPv6) #249

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Core Infrastructure
This folder contains the Terraform code to deploy the core infratructure for an ECS EC2 based workload. The AWS resources created by the script are:
* Networking
* VPC
* VPC in dual-stack mode: your resources can communicate over IPv4, or IPv6, or both. IPv4 and IPv6 communication are independent of each other.
* 3 public subnets, 1 per AZ. If a region has less than 3 AZs it will create same number of public subnets as AZs.
* 3 private subnets, 1 per AZ. If a region has less than 3 AZs it will create same number of private subnets as AZs.
* 1 NAT Gateway
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ resource "aws_service_discovery_private_dns_namespace" "this" {
}

################################################################################
# Supporting Resources
# Supporting Resources - VPC with ipv6-dualstack
################################################################################

module "vpc" {
Expand All @@ -88,12 +88,19 @@ module "vpc" {
cidr = local.vpc_cidr

azs = local.azs
private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)]
public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)]

enable_nat_gateway = true
single_nat_gateway = true

enable_ipv6 = true
public_subnet_assign_ipv6_address_on_creation = true
private_subnet_assign_ipv6_address_on_creation = true

public_subnet_ipv6_prefixes = [0, 1, 2]
private_subnet_ipv6_prefixes = [3, 4, 5]

# Manage so we can name
manage_default_network_acl = true
default_network_acl_tags = { Name = "${local.name}-default" }
Expand All @@ -107,7 +114,7 @@ module "vpc" {

# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html#ecs-optimized-ami-linux
data "aws_ssm_parameter" "ecs_optimized_ami" {
name = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended"
name = "/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended"
}

module "autoscaling" {
Expand All @@ -132,9 +139,9 @@ module "autoscaling" {

vpc_zone_identifier = module.vpc.private_subnets
health_check_type = "EC2"
min_size = 3
max_size = 5
desired_capacity = 3
min_size = 1
max_size = 1
desired_capacity = 1

# https://github.com/hashicorp/terraform-provider-aws/issues/12582
autoscaling_group_tags = {
Expand All @@ -155,8 +162,9 @@ module "autoscaling_sg" {
description = "Autoscaling group security group"
vpc_id = module.vpc.vpc_id

ingress_cidr_blocks = [module.vpc.vpc_cidr_block]
ingress_rules = ["http-80-tcp"]
ingress_cidr_blocks = [module.vpc.vpc_cidr_block]
ingress_ipv6_cidr_blocks = [module.vpc.vpc_ipv6_cidr_block]
ingress_rules = ["http-80-tcp"]

egress_rules = ["all-all"]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# ECS load-balanced service

This solution blueprint creates a web-facing load balanced ECS service. There are two steps to deploying this service:
This solution blueprint creates a web-facing load balanced ECS service.
The Load Balancer is dualstack mode: Clients can connect to the load balancer using both IPv4 addresses (for example, 192.0.2.1) and IPv6 addresses (for example, 2001:db8:85a3::8a2e:0370:7334).
The ECS Task is registered in two different Target groups(ipv4 and ipv6).
Due current limitations, ECS Tasks are not register in ipv6 target type.

There are two steps to deploying this service:

* Deploy the [core-infra](../core-infra/README.md). Note if you have already deployed the `core-infra` then you can reuse it.
* Deploy this blueprint using the below commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ provider "aws" {
}

locals {
name = "ecsdemo-frontend"
name = "ecsdemo-frontend-ipv6"
region = "us-west-2"

container_port = 3000 # Container port is specific to this app example
Expand Down Expand Up @@ -32,7 +32,7 @@ module "ecs_service" {
requires_compatibilities = ["EC2"]
capacity_provider_strategy = {
default = {
capacity_provider = "core-infra" # needs to match name of capacity provider
capacity_provider = "core-infra-ipv6" # needs to match name of capacity provider
weight = 1
base = 1
}
Expand Down Expand Up @@ -81,15 +81,25 @@ module "ecs_service" {
description = "Service port"
source_security_group_id = module.alb.security_group_id
}
egress_all = {
egress_all_ipv4 = {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
egress_all_ipv6 = {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
ipv6_cidr_blocks = ["::/0"]
}
}




tags = local.tags
}

Expand Down Expand Up @@ -121,23 +131,38 @@ module "alb" {
# For example only
enable_deletion_protection = false

vpc_id = data.aws_vpc.vpc.id
subnets = data.aws_subnets.public.ids
vpc_id = data.aws_vpc.vpc.id
subnets = data.aws_subnets.public.ids
ip_address_type = "dualstack"
security_group_ingress_rules = {
all_http = {
all_http_ipv4 = {
from_port = 80
to_port = 80
ip_protocol = "tcp"
description = "HTTP web traffic"
cidr_ipv4 = "0.0.0.0/0"
}
all_http_ipv6 = {
from_port = 8080
to_port = 8080
ip_protocol = "tcp"
description = "HTTP web traffic"
cidr_ipv6 = "::/0"
}
}
security_group_egress_rules = { for subnet in data.aws_subnet.private_cidr :
(subnet.availability_zone) => {
security_group_egress_rules = merge(
{ for subnet in data.aws_subnet.private_cidr : "${subnet.availability_zone}" => {
ip_protocol = "-1"
cidr_ipv4 = subnet.cidr_block
}
},
{ for subnet in data.aws_subnet.private_cidr : "${subnet.availability_zone}-ipv6" => {
ip_protocol = "-1"
cidr_ipv6 = subnet.ipv6_cidr_block
}
}
}
)


listeners = {
http = {
Expand All @@ -148,6 +173,14 @@ module "alb" {
target_group_key = "ecs-task"
}
}
http2 = {
port = "8080"
protocol = "HTTP"

forward = {
target_group_key = "ecs-task-ipv6"
}
}
}

target_groups = {
Expand All @@ -172,6 +205,35 @@ module "alb" {
# ECS will attach the IPs of the tasks to this target group
create_attachment = false
}

#this is just to show that due current limitations, ECS Targets are not registered on the ipv6 target group.
#This is documented on https://docs.aws.amazon.com/AmazonECS/latest/developerguide/alb.html#alb-considerations
#Consider the following when using Application Load Balancers with Amazon ECS:
#Target group must have the IP address type set to IPv4.

ecs-task-ipv6 = {
backend_protocol = "HTTP"
backend_port = local.container_port
target_type = "ip"
ip_address_type = "ipv6"

health_check = {
enabled = true
healthy_threshold = 5
interval = 30
matcher = "200-299"
path = "/"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 2
}

# There's nothing to attach here in this definition. Instead,
# ECS will attach the IPs of the tasks to this target group
create_attachment = false
}

}

tags = local.tags
Expand All @@ -184,21 +246,21 @@ module "alb" {
data "aws_vpc" "vpc" {
filter {
name = "tag:Name"
values = ["core-infra"]
values = ["core-infra-ipv6"]
}
}

data "aws_subnets" "public" {
filter {
name = "tag:Name"
values = ["core-infra-public-*"]
values = ["core-infra-ipv6-public-*"]
}
}

data "aws_subnets" "private" {
filter {
name = "tag:Name"
values = ["core-infra-private-*"]
values = ["core-infra-ipv6-private-*"]
}
}

Expand All @@ -208,7 +270,7 @@ data "aws_subnet" "private_cidr" {
}

data "aws_ecs_cluster" "core_infra" {
cluster_name = "core-infra"
cluster_name = "core-infra-ipv6"
}

data "aws_service_discovery_dns_namespace" "this" {
Expand Down