返回 Skill 列表
extension
分类: 开发与工程无需 API Key

ecs-fargate

AWS Fargate 无服务器容器计算服务适用于ECS。涵盖了Fargate与EC2的选择指南、CPU/内存大小调整、平台版本、Fargate Spot成本优化、Graviton/ARM架构、网络配置以及EFS集成等内容。在部署无服务器容器、优化Fargate成本、确定Fargate任务规模或选择Fargate和EC2启动类型时使用。

person作者: jakexiaohubgithub

AWS Fargate for ECS

Complete guide to AWS Fargate serverless container compute, including sizing, optimization, and best practices.

Quick Reference

| Aspect | Fargate | EC2 | |--------|---------|-----| | Management | Serverless | Manual | | Scaling | Automatic | ASG-based | | Pricing | Per vCPU-second | Per instance-hour | | Overhead | None | High | | Control | Limited | Full | | Best For | Variable load | Steady state |

When to Use Fargate

Use Fargate when:

  • Team prioritizes operational simplicity
  • Variable or unpredictable traffic
  • Microservices architecture
  • Rapid scaling needed
  • Development/testing environments
  • No specific instance type requirements

Use EC2 when:

  • Steady-state, predictable workloads
  • Cost optimization is critical (>60% utilization)
  • Need specific instance types (GPU, high memory)
  • Existing Reserved Instance commitments
  • Custom AMI requirements

CPU and Memory Configurations

Valid Combinations

| CPU (vCPU) | Memory Options | |------------|----------------| | 0.25 | 512 MB, 1 GB, 2 GB | | 0.5 | 1 GB - 4 GB (1 GB increments) | | 1 | 2 GB - 8 GB (1 GB increments) | | 2 | 4 GB - 16 GB (1 GB increments) | | 4 | 8 GB - 30 GB (1 GB increments) | | 8 | 16 GB - 60 GB (4 GB increments) | | 16 | 32 GB - 120 GB (8 GB increments) |

Sizing Guidelines

# Sizing decision tree
def recommend_fargate_size(app_type: str, expected_memory_mb: int):
    """Recommend Fargate CPU/Memory based on workload"""

    if app_type == "web_api":
        # Typically CPU-bound
        if expected_memory_mb <= 512:
            return {"cpu": "256", "memory": "512"}
        elif expected_memory_mb <= 1024:
            return {"cpu": "512", "memory": "1024"}
        else:
            return {"cpu": "1024", "memory": str(min(expected_memory_mb, 2048))}

    elif app_type == "worker":
        # Typically memory-bound
        return {"cpu": "256", "memory": str(max(512, expected_memory_mb))}

    elif app_type == "batch":
        # Need burst capacity
        return {"cpu": "1024", "memory": str(max(2048, expected_memory_mb))}

    # Default conservative
    return {"cpu": "512", "memory": "1024"}

Cost-Effective Sizing

# Development: Minimum viable
cpu    = "256"
memory = "512"

# Small API: Balanced
cpu    = "512"
memory = "1024"

# Production API: Standard
cpu    = "1024"
memory = "2048"

# Memory-intensive: Data processing
cpu    = "1024"
memory = "4096"

# Compute-intensive: ML inference
cpu    = "4096"
memory = "8192"

Platform Versions

Current Versions (2025)

| Version | Status | Features | |---------|--------|----------| | 1.4.0 | Recommended | containerd runtime, jumbo frames, UDP support | | 1.3.0 | Deprecated (Mar 2026) | Docker runtime | | LATEST | Auto-updates | Always latest revision |

Configuration

# Always pin explicitly
resource "aws_ecs_service" "app" {
  platform_version = "1.4.0"  # NOT "LATEST"
  # ...
}
# Boto3
ecs.create_service(
    platformVersion='1.4.0',
    # ...
)

Fargate Spot (Cost Optimization)

Overview

  • Up to 70% savings vs on-demand
  • 2-minute termination notice when capacity needed
  • Best for: Batch jobs, CI/CD, fault-tolerant workloads

Configuration

# Mixed strategy: reliable baseline + cost-effective scaling
resource "aws_ecs_service" "app" {
  capacity_provider_strategy {
    capacity_provider = "FARGATE"
    weight            = 1
    base              = 2  # Always keep 2 on-demand
  }

  capacity_provider_strategy {
    capacity_provider = "FARGATE_SPOT"
    weight            = 4  # 4x weight = ~80% on Spot
  }
}
# Boto3
ecs.create_service(
    capacityProviderStrategy=[
        {'capacityProvider': 'FARGATE', 'weight': 1, 'base': 2},
        {'capacityProvider': 'FARGATE_SPOT', 'weight': 4}
    ],
    # ...
)

Handling Spot Interruptions

# Application-level graceful shutdown
import signal
import sys

def shutdown_handler(signum, frame):
    print("Received termination signal, shutting down gracefully...")
    # Drain connections
    # Complete in-flight requests
    # Save state if needed
    sys.exit(0)

signal.signal(signal.SIGTERM, shutdown_handler)

ARM/Graviton (20% Cost Savings)

Benefits

  • ~20% cost reduction vs x86
  • Up to 40% better performance for many workloads
  • Same API - just change task definition

Configuration

resource "aws_ecs_task_definition" "app" {
  family                   = "my-app"
  requires_compatibilities = ["FARGATE"]

  # ARM architecture
  runtime_platform {
    operating_system_family = "LINUX"
    cpu_architecture        = "ARM64"  # or "X86_64"
  }

  # ...
}

Multi-Architecture Images

# Dockerfile supporting both architectures
FROM --platform=$TARGETPLATFORM python:3.11-slim

# Build for multiple platforms
# docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .
# Build and push multi-arch image
docker buildx create --use
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --push \
  -t 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest .

Networking (awsvpc Mode)

Task-Level Networking

Each Fargate task gets its own ENI with:

  • Unique private IP
  • Dedicated security group
  • Full network isolation
resource "aws_ecs_service" "app" {
  network_configuration {
    subnets          = var.private_subnets
    security_groups  = [aws_security_group.ecs_tasks.id]
    assign_public_ip = false  # Use NAT for outbound
  }
}

VPC Endpoints (Recommended)

# Avoid NAT costs for AWS services
resource "aws_vpc_endpoint" "ecr_api" {
  vpc_id            = module.vpc.vpc_id
  service_name      = "com.amazonaws.${var.region}.ecr.api"
  vpc_endpoint_type = "Interface"
  subnet_ids        = module.vpc.private_subnets
}

resource "aws_vpc_endpoint" "ecr_dkr" {
  vpc_id            = module.vpc.vpc_id
  service_name      = "com.amazonaws.${var.region}.ecr.dkr"
  vpc_endpoint_type = "Interface"
  subnet_ids        = module.vpc.private_subnets
}

resource "aws_vpc_endpoint" "s3" {
  vpc_id       = module.vpc.vpc_id
  service_name = "com.amazonaws.${var.region}.s3"
}

resource "aws_vpc_endpoint" "logs" {
  vpc_id            = module.vpc.vpc_id
  service_name      = "com.amazonaws.${var.region}.logs"
  vpc_endpoint_type = "Interface"
  subnet_ids        = module.vpc.private_subnets
}

EFS Integration (Persistent Storage)

Configuration

# EFS File System
resource "aws_efs_file_system" "app" {
  creation_token = "app-storage"
  encrypted      = true

  lifecycle_policy {
    transition_to_ia = "AFTER_30_DAYS"
  }
}

resource "aws_efs_mount_target" "app" {
  count           = length(var.private_subnets)
  file_system_id  = aws_efs_file_system.app.id
  subnet_id       = var.private_subnets[count.index]
  security_groups = [aws_security_group.efs.id]
}

# Task Definition with EFS
resource "aws_ecs_task_definition" "app" {
  family = "my-app"

  volume {
    name = "app-storage"

    efs_volume_configuration {
      file_system_id          = aws_efs_file_system.app.id
      root_directory          = "/app-data"
      transit_encryption      = "ENABLED"
      authorization_config {
        access_point_id = aws_efs_access_point.app.id
        iam             = "ENABLED"
      }
    }
  }

  container_definitions = jsonencode([
    {
      name = "my-app"
      mountPoints = [
        {
          sourceVolume  = "app-storage"
          containerPath = "/data"
          readOnly      = false
        }
      ]
      # ...
    }
  ])
}

Ephemeral Storage

Default and Configurable

# Default: 20 GB, configurable up to 200 GB
resource "aws_ecs_task_definition" "app" {
  ephemeral_storage {
    size_in_gib = 100  # For large temp files
  }
}

Cost Optimization Summary

| Strategy | Savings | Effort | |----------|---------|--------| | Fargate Spot | 70% | Low | | ARM/Graviton | 20% | Medium | | Right-sizing | 10-50% | Medium | | Compute Savings Plans | 50% | Low | | Schedule-based scaling | 30-60% | Medium |

Cost Calculation

def estimate_monthly_cost(cpu_vcpu: float, memory_gb: float,
                          hours_per_month: int = 730,
                          spot_percentage: float = 0.0):
    """Estimate monthly Fargate cost (us-east-1 pricing)"""

    # On-demand pricing (approximate)
    cpu_rate = 0.04048  # per vCPU-hour
    memory_rate = 0.004445  # per GB-hour

    on_demand_hours = hours_per_month * (1 - spot_percentage)
    spot_hours = hours_per_month * spot_percentage

    # Spot is ~70% cheaper
    cpu_cost = (cpu_vcpu * cpu_rate * on_demand_hours) + \
               (cpu_vcpu * cpu_rate * 0.3 * spot_hours)
    memory_cost = (memory_gb * memory_rate * on_demand_hours) + \
                  (memory_gb * memory_rate * 0.3 * spot_hours)

    return cpu_cost + memory_cost

# Example: 1 vCPU, 2 GB, 50% Spot
cost = estimate_monthly_cost(1, 2, spot_percentage=0.5)
print(f"Estimated monthly cost: ${cost:.2f}")  # ~$25

Progressive Disclosure

Quick Start (This File)

  • Fargate vs EC2 decision
  • CPU/Memory sizing
  • Platform versions
  • Cost optimization basics

Detailed References

Related Skills

  • boto3-ecs: SDK patterns for ECS
  • terraform-ecs: Infrastructure as Code
  • ecs-deployment: Deployment strategies
  • ecs-troubleshooting: Debugging guide

Best Practices

  1. Start small, scale up - Begin with 0.25 vCPU/512 MB and increase based on metrics
  2. Use Fargate Spot for non-critical workloads (70% savings)
  3. Consider ARM/Graviton for compatible workloads (20% savings)
  4. Pin platform version explicitly (e.g., "1.4.0")
  5. Use VPC endpoints to reduce NAT costs
  6. Enable Container Insights for visibility
  7. Right-size continuously using CloudWatch metrics
  8. Use capacity provider strategy instead of launch type