Оптимізація вартості AWS мережі: Кастомний EC2 NAT vs Managed NAT Gateway

Оптимізація вартості AWS мережі: Кастомний EC2 NAT vs Managed NAT Gateway

Виклик вартості AWS NAT

AWS NAT Gateway надає managed network address translation для ресурсів приватних підмереж—баз даних, ECS tasks, Lambda functions—що потребують доступу до інтернету. Сервіс коштує $32.40 на місяць за Availability Zone плюс $0.045 за GB processed. Стандартна three-AZ production архітектура генерує $97.20 щомісячних базових витрат ($1,166 щорічно) до data transfer charges.

Організації, що керують кількома середовищами (development, staging, production), стикаються з витратами, що масштабуються лінійно з deployment footprint. Доступ приватних підмереж до інтернету залишається необхідним для security patches, package dependencies та API integrations. Питання стає: скільки операційної складності прийнятно для зменшення витрат?

Ключові результати:

  • 81% зниження вартості використовуючи per-AZ EC2 NAT ($18/місяць vs $97/місяць для 3-AZ)
  • 94% зниження вартості використовуючи single EC2 NAT ($6/місяць vs $97/місяць)
  • Terraform-автоматизоване розгортання, що усуває manual configuration
  • Висока доступність через Auto Scaling Groups

Архітектура: Основи VPC мережі

AWS VPC мережева сегментація відокремлює internet-facing ресурси від внутрішніх систем через класифікацію підмереж та асоціації route table.

Public Subnets:

  • Internet-facing ресурси (load balancers, bastion hosts, NAT instances)
  • Route table default route (0.0.0.0/0) спрямовується на Internet Gateway
  • Ресурси отримують публічні IP адреси

Private Subnets:

  • Внутрішні ресурси (RDS, ECS tasks, Lambda functions)
  • Весь egress traffic маршрутизується через NAT
  • Лише приватні IP адреси—без вхідних internet з'єднань

Логіка Route Table:

Public subnet:

Destination         Target
10.0.0.0/16        local
0.0.0.0/0          igw-xxxxx

Private subnet:

Destination         Target
10.0.0.0/16        local
0.0.0.0/0          nat-xxxxx OR eni-xxxxx

Відмінність маршрутизації визначає класифікацію підмережі. Обидва NAT patterns використовують ідентичну структуру route table—різниця лише у NAT target.

NAT Gateway vs EC2 NAT Instance

NAT Gateway (Managed Service):

  • AWS-managed high-availability NAT сервіс
  • Розгортається в public subnet, один на AZ
  • Автоматичне масштабування—без capacity planning
  • $0.045/година ($32.40/місяць) плюс data processing ($0.045/GB)
  • Нульові операційні витрати

EC2 NAT Instance (Custom Implementation):

  • Стандартний EC2 instance з IP forwarding та iptables
  • source_dest_check = false дозволяє packet forwarding
  • iptables MASQUERADE rule переписує outbound packet source IPs
  • Route table спрямовується на EC2 network interface (eni-xxxxx)
  • Операційні витрати: OS patching, monitoring, failover automation

Обидва забезпечують ідентичну функціональність—приватні ресурси надсилають traffic до NAT, NAT переписує source IP, форвардить до інтернету, переписує response назад до приватного ресурсу.

Реалізація: Terraform EC2 NAT конфігурація

Terraform конфігурація реалізує EC2-based NAT через dual-purpose instances, що служать як ECS cluster members так і network routers.

VPC та Route Table конфігурація

# terraform/shared/vpc.tf
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.14.0"

  name = "${var.app_name}-vpc"
  cidr = var.vpc_cidr

  azs             = var.availability_zones
  public_subnets  = var.public_subnet_cidrs
  private_subnets = var.private_subnet_cidrs

  enable_nat_gateway = false  # Використовуємо custom EC2 NAT
  enable_dns_hostnames = true
}

# Custom NAT routing
locals {
  private_rt_by_az = {
    for idx, az in var.availability_zones :
    az => module.vpc.private_route_table_ids[idx]
  }

  single_nat = var.nat_instance_count == 1
  single_nat_eni_id = local.single_nat ? aws_instance.ecs_instance[var.availability_zones[0]].primary_network_interface_id : null
}

resource "aws_route" "private_default_to_nat" {
  for_each               = local.private_rt_by_az
  route_table_id         = each.value
  destination_cidr_block = "0.0.0.0/0"
  network_interface_id   = local.single_nat ? local.single_nat_eni_id : aws_instance.ecs_instance[each.key].primary_network_interface_id
}

Змінна nat_instance_count визначає маршрутизацію:

  • = 1: Всі приватні підмережі маршрутизуються до single instance (максимальна економія)
  • = 3: Кожна приватна підмережа маршрутизується до instance в тій же AZ (висока доступність)

EC2 NAT Instance конфігурація

# terraform/shared/ec2.tf
resource "aws_instance" "ecs_instance" {
  for_each               = local.nat_public_by_az
  ami                    = var.ecs_optimized_ami
  instance_type          = "t4g.micro"
  subnet_id              = each.value
  vpc_security_group_ids = [aws_security_group.ecs_instance.id]
  iam_instance_profile   = aws_iam_instance_profile.ecs_instance.name

  source_dest_check = false  # Необхідно для NAT

  user_data = base64encode(templatefile("${path.module}/user-data.sh", {
    cluster_name = "${var.app_name}-ecs-cluster"
    vpc_cidr     = var.vpc_cidr
  }))
}

resource "aws_eip" "nat" {
  for_each = aws_instance.ecs_instance
  instance = each.value.id
  domain   = "vpc"
}

User Data Script:

#!/bin/bash
# ECS membership
echo ECS_CLUSTER=${cluster_name} >> /etc/ecs/ecs.config

# Enable IP forwarding
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -w net.ipv4.ip_forward=1

# NAT masquerading
IFACE=$(ip route | grep default | awk '{print $5}')
iptables -t nat -A POSTROUTING -s ${vpc_cidr} ! -d ${vpc_cidr} -o "$IFACE" -j MASQUERADE
service iptables save

Ключова конфігурація:

  1. source_dest_check = false: Дозволяє packet forwarding (non-default EC2 behavior)
  2. IP Forwarding: Linux kernel параметр, що дозволяє маршрутизацію між інтерфейсами
  3. iptables MASQUERADE: Переписує outbound packet source IPs на NAT instance public IP
  4. Dual Purpose: Instance обробляє як ECS workloads так і NAT routing

Висока доступність з Auto Scaling Groups

resource "aws_autoscaling_group" "ecs_nat" {
  for_each                = local.nat_public_by_az
  name                    = "${var.app_name}-ecs-nat-asg-${each.key}"
  vpc_zone_identifier     = [each.value]
  desired_capacity        = 1
  min_size                = 1
  max_size                = 1
  health_check_type       = "EC2"
  health_check_grace_period = 300

  launch_template {
    id      = aws_launch_template.ecs_nat[each.key].id
    version = "$Latest"
  }
}

Auto Scaling Group моніторить instance health та тригерить автоматичну заміну при failure (2-5 хвилин recovery).

Аналіз вартості та trade-offs

Three-AZ Production середовище

NAT Gateway:

Per AZ: $32.40/місяць
Total (3 AZs): $97.20/місяць
Щорічно: $1,166.40

EC2 NAT (Per-AZ):

t4g.micro: $6.13/місяць × 3 = $18.39/місяць
Щорічно: $220.68
Економія: $945.72/рік (81% зниження)

EC2 NAT (Single Instance):

t4g.micro: $6.13/місяць
Щорічно: $73.56
Економія: $1,092.84/рік (94% зниження)
Trade-off: Single point of failure

Операційні міркування

Моніторинг:

  • CloudWatch metrics: Network throughput, CPU, status checks
  • Auto Scaling Group health checks тригерять replacement
  • Алерти при instance failure → автоматичне відновлення

Продуктивність:

  • t4g.micro baseline: 85 Mbps, burst: 5 Gbps
  • Адекватно для типових dev/staging/production workloads
  • Оновіть instance type якщо sustained throughput перевищує baseline

Безпека:

  • Ідентична ізоляція до NAT Gateway
  • Security groups контролюють traffic flow
  • VPC Flow Logs для аудиту

Коли використовувати кожен pattern

Використовуйте NAT Gateway:

  • Потрібні нульові операційні витрати
  • Бюджет дозволяє managed services premium
  • Обмежена networking експертиза
  • Вимоги високої пропускної здатності (>5 Gbps)

Використовуйте EC2 NAT:

  • Пріоритет оптимізації вартості
  • Доступна networking експертиза
  • Terraform/IaC вже використовується
  • Development/staging середовища

Матриця рішень:

Фактор NAT Gateway EC2 NAT (Per-AZ) EC2 NAT (Single)
Вартість (3 AZs) $97/міс $18/міс $6/міс
Економія Базова 81% 94%
Recovery Time <1 хв 2-5 хв 2-5 хв
Overhead Нуль Низький Низький
Найкраще для Enterprise Production Dev/staging

Результати та уроки

Економія вартості:

  • Production (3 AZs): $945/рік заощаджено (81%)
  • Development (1 AZ): $1,092/рік заощаджено (94%)
  • Multi-environment deployment: $2,206/рік загальної економії

Що спрацювало:

✅ Dual-purpose EC2 instances зменшують загальну кількість інфраструктури

✅ Terraform автоматизація усуває manual iptables конфігурацію

✅ Auto Scaling Groups забезпечують адекватну високу доступність

✅ t4g.micro достатньо для типових workload egress потреб

✅ Single NAT прийнятний для non-production середовищ

✅ Фіксована EC2 вартість vs змінні NAT Gateway data processing charges

Підводні камені, яких слід уникати:

❌ Забувати source_dest_check = false (маршрутизація не працюватиме)

❌ Пропущене iptables MASQUERADE правило (немає outbound connectivity)

❌ Відсутність моніторингу/alerting на NAT instance health

❌ Занадто малий instance type для traffic volume

❌ Відсутність Auto Scaling Group (потрібне manual recovery)

❌ Несумісні security group rules між NAT instances

Висновок

EC2-based NAT instances зменшують AWS networking витрати на 81-94% порівняно з NAT Gateway, зберігаючи production-grade доступність через Auto Scaling Groups та Terraform автоматизацію.

Шлях реалізації:

  1. Оцініть поточні NAT Gateway витрати та порахуйте економію
  2. Реалізуйте EC2 NAT в development середовищі спочатку
  3. Налаштуйте Auto Scaling Groups з health checks
  4. Валідуйте failover сценарії
  5. Розгорніть в production з per-AZ NAT instances
  6. Моніторте throughput та коригуйте instance types при потребі

Коли цей підхід має сенс:

  • Cost-sensitive AWS deployments
  • Команди з networking експертизою
  • Terraform-managed інфраструктура
  • Development/staging середовища (single NAT прийнятний)

Організації, що пріоритизують cost efficiency, досягають суттєвої економії без компромісу network reliability. Terraform автоматизація усуває manual configuration складність, роблячи EC2 NAT практичним для команд, що керують Infrastructure as Code deployments.

Ресурси: