
ECS Fargate:无服务器容器
Fargate 无需管理 EC2 实例即可运行容器。您只需定义 CPU/内存,AWS 负责其余部分。

任务定义
{
"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
}
}
]
}

服务定义与自动扩缩
# 创建服务
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}"
// 自动扩缩策略
{
"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 推送脚本
#!/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}"
# 登录 ECR
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com
# 构建并推送
docker build -t $ECR_REPO:$IMAGE_TAG .
docker push $ECR_REPO:$IMAGE_TAG
# 标记为 latest
docker tag $ECR_REPO:$IMAGE_TAG $ECR_REPO:latest
docker push $ECR_REPO:latest
# 更新 ECS 服务
aws ecs update-service --cluster production --service api --force-new-deployment --task-definition api
密钥管理
# 在 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
# ECS 任务读取密钥的 IAM 策略
{
"Effect": "Allow",
"Action": ["ssm:GetParameter", "ssm:GetParameters"],
"Resource": "arn:aws:ssm:us-east-1:123:parameter/myapp/prod/*"
}
CloudWatch Logs Insights
# 查找过去一小时的错误
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 100
# 从结构化日志中获取 P99 响应时间
fields @timestamp, duration
| filter statusCode >= 200
| stats pct(duration, 99) as p99 by bin(5m)