正在加载,请稍候…

AWS ECS Fargate: Deploy Containerized Apps Without Managing Servers

Deploy containers on AWS ECS Fargate — task definitions, service auto-scaling, ALB integration, service discovery, secrets from SSM, and CI/CD with GitHub Actions.

ECS Fargate: Serverless Containers

Fargate runs containers without EC2 instances to manage. You define CPU/memory, AWS handles the rest.

Task Definition

{
  "family": "api",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789:role/ecsTaskRole",
  "containerDefinitions": [
    {
      "name": "api",
      "image": "123456789.dkr.ecr.us-east-1.amazonaws.com/api:latest",
      "portMappings": [
        { "containerPort": 3000, "protocol": "tcp" }
      ],
      "environment": [
        { "name": "NODE_ENV", "value": "production" },
        { "name": "PORT", "value": "3000" }
      ],
      "secrets": [
        { "name": "DATABASE_URL", "valueFrom": "arn:aws:ssm:us-east-1:123:parameter/myapp/prod/database-url" },
        { "name": "JWT_SECRET", "valueFrom": "arn:aws:secretsmanager:us-east-1:123:secret:myapp/jwt-secret" }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/api",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 10,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}

Service Definition with Auto-Scaling

# Create service
aws ecs create-service   --cluster production   --service-name api   --task-definition api:5   --desired-count 3   --launch-type FARGATE   --network-configuration "awsvpcConfiguration={
    subnets=[subnet-xxx,subnet-yyy],
    securityGroups=[sg-xxx],
    assignPublicIp=DISABLED
  }"   --load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:...,containerName=api,containerPort=3000"   --deployment-configuration "maximumPercent=200,minimumHealthyPercent=100,deploymentCircuitBreaker={enable=true,rollback=true}"
// Auto-scaling policy
{
  "scalableDimension": "ecs:service:DesiredCount",
  "serviceNamespace": "ecs",
  "resourceId": "service/production/api",
  "minCapacity": 2,
  "maxCapacity": 20,
  "targetTrackingScalingPolicies": [
    {
      "targetValue": 70,
      "predefinedMetricSpecification": {
        "predefinedMetricType": "ECSServiceAverageCPUUtilization"
      },
      "scaleInCooldown": 300,
      "scaleOutCooldown": 60
    },
    {
      "targetValue": 1000,
      "predefinedMetricSpecification": {
        "predefinedMetricType": "ALBRequestCountPerTarget",
        "resourceLabel": "app/prod-alb/xxx/targetgroup/api/xxx"
      }
    }
  ]
}

ECR Push Script

#!/bin/bash
set -e

AWS_REGION=us-east-1
AWS_ACCOUNT=123456789
ECR_REPO="${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com/api"
IMAGE_TAG="${GITHUB_SHA:-latest}"

# Login to ECR
aws ecr get-login-password --region $AWS_REGION |   docker login --username AWS --password-stdin $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com

# Build and push
docker build -t $ECR_REPO:$IMAGE_TAG .
docker push $ECR_REPO:$IMAGE_TAG

# Tag as latest
docker tag $ECR_REPO:$IMAGE_TAG $ECR_REPO:latest
docker push $ECR_REPO:latest

# Update ECS service
aws ecs update-service   --cluster production   --service api   --force-new-deployment   --task-definition api

Secrets Management

# Store secrets in SSM Parameter Store
aws ssm put-parameter   --name /myapp/prod/database-url   --value "postgresql://user:pass@rds-endpoint/myapp"   --type SecureString   --key-id alias/myapp-key

# IAM policy for ECS task to read secrets
{
  "Effect": "Allow",
  "Action": ["ssm:GetParameter", "ssm:GetParameters"],
  "Resource": "arn:aws:ssm:us-east-1:123:parameter/myapp/prod/*"
}

CloudWatch Logs Insights

# Find errors in last hour
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 100

# P99 response time from structured logs
fields @timestamp, duration
| filter statusCode >= 200
| stats pct(duration, 99) as p99 by bin(5m)