我已经使用 Terraform 设置了一个 AWS 基础设施,其中有一个 ECS 集群在 VPC (main-vpc) 中运行 Fargate 任务。 Fargate任务需要从DockerHub拉取镜像。对于出口,我设置了另一个带有公有子网、NAT 网关和互联网网关的 VPC (egress-vpc),以促进出站流量。这两个 VPC 使用 AWS Transit Gateway 连接。
但是,当我启动 Fargate 任务时,它们仍处于 PENDING 状态并且无法启动。当我直接在 main-vpc 中创建测试 NAT 网关(绕过 Transit Gateway 出口设置)时,任务可以正常工作。这让我相信我配置 Transit Gateway 或相关路由的方式存在问题。
这是我的设置的相关 Terraform 代码:
tgw.tf
resource "aws_ec2_transit_gateway" "main_tgw" {
default_route_table_association = "enable"
default_route_table_propagation = "enable"
auto_accept_shared_attachments = "enable"
multicast_support = "enable"
vpn_ecmp_support = "disable"
dns_support = "enable"
tags = {
Name = "main-tgw"
}
}
resource "aws_ram_resource_share" "main_tgw_share" {
name = "main-tgw-share"
allow_external_principals = false
}
resource "aws_ram_resource_association" "main_tgw_share_association" {
resource_arn = aws_ec2_transit_gateway.main_tgw.arn
resource_share_arn = aws_ram_resource_share.main_tgw_share.id
}
resource "aws_ram_principal_association" "main_tgw_org_share_association" {
principal = data.aws_organizations_organization.default.arn
resource_share_arn = aws_ram_resource_share.main_tgw_share.arn
}
主-vpc.tf
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
tags = {
Name = "main-vpc"
}
}
resource "aws_subnet" "private_subnet_1a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.32.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "private-subnet-1"
}
}
resource "aws_subnet" "private_subnet_1b" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.48.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "private-subnet-2"
}
}
resource "aws_subnet" "public_subnet_1a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.0.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "public-subnet-1"
}
}
resource "aws_subnet" "public_subnet_1b" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.16.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "public-subnet-2"
}
}
resource "aws_internet_gateway" "main_vpc_igw" {
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "main-vpc-igw"
}
}
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main_vpc_igw.id
}
tags = {
Name = "public-rt"
}
}
resource "aws_route_table_association" "public_rta_1a" {
subnet_id = aws_subnet.public_subnet_1a.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table_association" "public_rta_1b" {
subnet_id = aws_subnet.public_subnet_1b.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table" "private_subnets_rt" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
transit_gateway_id = aws_ec2_transit_gateway.main_tgw.id
}
tags = {
Name = "private-subnet-rt"
}
}
resource "aws_route_table_association" "private_subnet_1_rta" {
subnet_id = aws_subnet.private_subnet_1a.id
route_table_id = aws_route_table.private_subnets_rt.id
}
resource "aws_route_table_association" "private_subnet_2_rta" {
subnet_id = aws_subnet.private_subnet_1b.id
route_table_id = aws_route_table.private_subnets_rt.id
}
resource "aws_ec2_transit_gateway_vpc_attachment" "main_vpc_attachment" {
subnet_ids = [aws_subnet.private_subnet_1a.id, aws_subnet.private_subnet_1b.id]
transit_gateway_id = aws_ec2_transit_gateway.main_tgw.id
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "main-vpc-tgw-attachment"
}
}
出口-vpc.tf
resource "aws_vpc" "egress_vpc" {
cidr_block = "10.1.0.0/16"
instance_tenancy = "default"
tags = {
Name = "egress-vpc"
}
}
resource "aws_subnet" "egress_vpc_private_subnet_1a" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.32.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "egress-vpc-private-subnet-1"
}
}
resource "aws_subnet" "egress_vpc_private_subnet_1b" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.48.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "egress-vpc-private-subnet-2"
}
}
resource "aws_subnet" "egress_public_subnet" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.0.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "egress-vpc-public-subnet"
}
}
resource "aws_subnet" "egress_public_subnet_2" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.16.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "egress-vpc-public-subnet-2"
}
}
resource "aws_internet_gateway" "egress_vpc_internet_gateway" {
vpc_id = aws_vpc.egress_vpc.id
tags = {
Name = "egress-vpc-internet-gateway"
}
}
resource "aws_eip" "egress_vpc_eip" {
domain = "vpc"
tags = {
Name = "egress-vpc-eip"
}
}
resource "aws_nat_gateway" "egress_vpc_nat_gateway" {
allocation_id = aws_eip.egress_vpc_eip.id
subnet_id = aws_subnet.egress_public_subnet.id
tags = {
Name = "egress-vpc-natgw"
}
}
resource "aws_route_table" "egress_vpc_public_rt" {
vpc_id = aws_vpc.egress_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.egress_vpc_internet_gateway.id
}
tags = {
Name = "egress-vpc-public-rt"
}
}
resource "aws_route_table_association" "egress_vpc_public_rta" {
subnet_id = aws_subnet.egress_public_subnet.id
route_table_id = aws_route_table.egress_vpc_public_rt.id
}
resource "aws_route_table_association" "egress_vpc_public_rta_2" {
subnet_id = aws_subnet.egress_public_subnet_2.id
route_table_id = aws_route_table.egress_vpc_public_rt.id
}
resource "aws_route_table" "egress_vpc_subnets_rt" {
vpc_id = aws_vpc.egress_vpc.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.egress_vpc_nat_gateway.id
}
tags = {
Name = "egress-vpc-private-subnet-rt"
}
}
resource "aws_main_route_table_association" "egress_vpc_main_route_table" {
vpc_id = aws_vpc.egress_vpc.id
route_table_id = aws_route_table.egress_vpc_subnets_rt.id
}
resource "aws_route_table_association" "egress_vpc_private_subnet_1_rta" {
subnet_id = aws_subnet.egress_vpc_private_subnet_1a.id
route_table_id = aws_route_table.egress_vpc_subnets_rt.id
}
resource "aws_route_table_association" "egress_vpc_private_subnet_2_rta" {
subnet_id = aws_subnet.egress_vpc_private_subnet_1b.id
route_table_id = aws_route_table.egress_vpc_subnets_rt.id
}
resource "aws_ec2_transit_gateway_vpc_attachment" "egress_vpc_attachment" {
subnet_ids = [aws_subnet.egress_vpc_private_subnet_1a.id, aws_subnet.egress_vpc_private_subnet_1b.id]
transit_gateway_id = aws_ec2_transit_gateway.main_tgw.id
vpc_id = aws_vpc.egress_vpc.id
tags = {
Name = "egress-vpc-tgw-attachment"
}
}
出口VPC的公共路由表必须有一条返回TGW的路由,以确保来自互联网的响应数据包(经过NAT网关后)可以通过TGW找到返回原始VPC的路径。
在出口 VPC 的公共路由表中添加一条指向 TGW 的路由(针对原始 VPC 的 CIDR 范围)解决了该问题。