关于 ecs
面向在 AWS 上部署和运维容器工作负载团队的 Amazon Elastic Container Service(ECS)参考技能。介绍 Fargate 与 EC2 上的集群、任务和服务管理,并提供扩缩容、部署、安全及故障排查的命令行示例。
主要功能
- 01管理集群、任务定义、任务和服务
- 02在 Fargate 或 EC2 上运行工作负载
- 03配置服务扩缩容与部署
- 04在适用工作负载中使用 Fargate Spot
- 05排查任务、容器和部署问题
适用场景
- 01部署带负载均衡器的 Web 服务
- 02运行独立批处理或队列处理任务
- 03根据工作负载指标扩缩 ECS 服务
- 04调查启动失败或部署停滞
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ itsmostafa/ aws-agent-skills --skill ecs安装后在 Claude Code 中输入/ecs确认已加载。
附带文件task-definitions.md
详细介绍
AWS ECS
Amazon Elastic Container Service(ECS)是一项全托管的容器编排服务。可在 AWS Fargate(无服务器)或 EC2 实例上运行容器。
目录
核心概念
集群
任务或服务的逻辑分组。可包含 Fargate 任务、EC2 实例,或两者兼有。
任务定义
应用的蓝图。用于定义容器、资源、网络和 IAM 角色。
任务
任务定义的运行实例。可独立运行,也可作为服务的一部分运行。
服务
维持任务的期望数量,并负责部署、负载均衡和自动扩缩。
启动类型
| 类型 | 说明 | 用例 |
|---|---|---|
| Fargate | 无服务器,按任务付费 | 大多数工作负载 |
| EC2 | 自行管理的实例 | GPU、Windows、特定需求 |
常见模式
创建 Fargate 集群
AWS CLI:
# Create cluster
aws ecs create-cluster --cluster-name my-cluster
# With capacity providers
aws ecs create-cluster \
--cluster-name my-cluster \
--capacity-providers FARGATE FARGATE_SPOT \
--default-capacity-provider-strategy \
capacityProvider=FARGATE,weight=1 \
capacityProvider=FARGATE_SPOT,weight=1
注册任务定义
cat > task-definition.json << 'EOF'
{
"family": "web-app",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "web",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"environment": [
{"name": "NODE_ENV", "value": "production"}
],
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:db-password"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/web-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs",
"mode": "non-blocking",
"max-buffer-size": "25m"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
}
}
]
}
EOF
aws ecs register-task-definition --cli-input-json file://task-definition.json
创建带负载均衡器的服务
aws ecs create-service \
--cluster my-cluster \
--service-name web-service \
--task-definition web-app:1 \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-12345678,subnet-87654321],
securityGroups=[sg-12345678],
assignPublicIp=DISABLED
}" \
--load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/web-tg/1234567890123456,containerName=web,containerPort=8080" \
--health-check-grace-period-seconds 60 \
--deployment-configuration "deploymentCircuitBreaker={enable=true,rollback=true}"
运行独立任务
aws ecs run-task \
--cluster my-cluster \
--task-definition my-batch-job:1 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-12345678],
securityGroups=[sg-12345678],
assignPublicIp=ENABLED
}"
更新服务(部署新映像)
# Register new task definition with updated image
aws ecs register-task-definition --cli-input-json file://task-definition.json
# Update service to use new version
aws ecs update-service \
--cluster my-cluster \
--service web-service \
--task-definition web-app:2 \
--force-new-deployment
使用基于 SQS 的扩缩容配置 Fargate Spot
对批处理/队列工作负载使用 FARGATE_SPOT,可将成本降低约 70%。务必设置回退到常规 FARGATE 的机制。
# Create service with Spot + fallback
aws ecs create-service \
--cluster batch-cluster \
--service-name queue-processor \
--task-definition my-processor:1 \
--desired-count 0 \
--capacity-provider-strategy \
capacityProvider=FARGATE_SPOT,weight=4,base=0 \
capacityProvider=FARGATE,weight=1,base=1 \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-12345678],
securityGroups=[sg-12345678],
assignPublicIp=DISABLED
}"
# Register scalable target (scale to zero when queue empty)
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/batch-cluster/queue-processor \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 0 \
--max-capacity 20
# Scale-out alarm: messages > 100
aws cloudwatch put-metric-alarm \
--alarm-name queue-scale-out \
--metric-name ApproximateNumberOfMessagesVisible \
--namespace AWS/SQS \
--dimensions Name=QueueName,Value=my-queue \
--statistic Average \
--period 60 \
--evaluation-periods 1 \
--threshold 100 \
--comparison-operator GreaterThanThreshold \
--alarm-actions <scale-out-policy-arn>
# Scale-in alarm: queue empty for 3 periods (conservative to avoid flapping)
aws cloudwatch put-metric-alarm \
--alarm-name queue-scale-in \
--metric-name ApproximateNumberOfMessagesVisible \
--namespace AWS/SQS \
--dimensions Name=QueueName,Value=my-queue \
--statistic Average \
--period 60 \
--evaluation-periods 3 \
--threshold 0 \
--comparison-operator LessThanOrEqualToThreshold \
--alarm-actions <scale-in-policy-arn>
**每个任务的积压量(AWS 推荐):**直接使用队列深度会导致过度扩缩容。改用指标数学计算 queue depth / RunningTaskCount 并进行目标跟踪;Application Auto Scaling 会管理告警。集群需要启用 Container Insights(ECS/ContainerInsights 中的 RunningTaskCount)。当运行任务数为 0 时,除数没有数据,因此无法从 0 扩容;如果 min-capacity 为 0,请保留上方的告警模式。
# TargetValue = acceptable latency / avg processing time per message (e.g. 10s / 0.1s = 100)
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/batch-cluster/queue-processor \
--scalable-dimension ecs:service:DesiredCount \
--policy-name sqs-backlog-per-task \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 100,
"CustomizedMetricSpecification": {
"Metrics": [
{"Id": "m1", "ReturnData": false, "MetricStat": {"Stat": "Sum",
"Metric": {"Namespace": "AWS/SQS", "MetricName": "ApproximateNumberOfMessagesVisible",
"Dimensions": [{"Name": "QueueName", "Value": "my-queue"}]}}},
{"Id": "m2", "ReturnData": false, "MetricStat": {"Stat": "Average",
"Metric": {"Namespace": "ECS/ContainerInsights", "MetricName": "RunningTaskCount",
"Dimensions": [{"Name": "ClusterName", "Value": "batch-cluster"},
{"Name": "ServiceName", "Value": "queue-processor"}]}}},
{"Id": "e1", "Expression": "m1 / m2", "ReturnData": true}
]
}
}'
**防止缩容时中断进行中的工作:**工作进程在处理期间将 ProtectionEnabled=true(使用容器 Agent 端点 $ECS_AGENT_URI/task-protection/v1/state,或运行 aws ecs update-task-protection --cluster <c> --tasks <id> --protection-enabled --expires-in-minutes 60),处理完成后将其清除。任务角色需要 ecs:GetTaskProtection 和 ecs:UpdateTaskProtection 权限。仅适用于服务任务。
**Fargate Spot 中断处理:**Spot 任务会在终止前 2 分钟收到 SIGTERM。在应用中捕获该信号,以便优雅关闭。对于 SQS 消费者,调用 ChangeMessageVisibility 处理正在进行的消息,使其返回队列,而不是超时。
自动扩缩容
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/my-cluster/web-service \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 10
# Target tracking policy
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/my-cluster/web-service \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-target-tracking \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 120
}'
**使用 20 秒指标加快扩缩容:**启用高分辨率服务指标,然后将 ECSServiceAverageCPUUtilizationHighResolution 或 ECSServiceAverageMemoryUtilizationHighResolution 用作 PredefinedMetricType。对于现有服务,更改 --monitoring 会触发部署;请在部署完成后再创建高分辨率策略。部署控制器为 CODE_DEPLOY/EXTERNAL 时不支持此功能。将产生额外的 CloudWatch 费用。
aws ecs update-service \
--cluster my-cluster \
--service web-service \
--monitoring "metricConfigurations=[{metricNames=[CPUUtilization,MemoryUtilization],resolutionSeconds=20}]"
CLI 参考
集群管理
| 命令 | 说明 |
|---|---|
aws ecs create-cluster | 创建集群 |
aws ecs describe-clusters | 获取集群详情 |
aws ecs list-clusters | 列出集群 |
aws ecs delete-cluster | 删除集群 |
任务定义
| 命令 | 说明 |
|---|---|
aws ecs register-task-definition | 创建任务定义 |
aws ecs describe-task-definition | 获取任务定义 |
aws ecs list-task-definitions | 列出任务定义 |
aws ecs deregister-task-definition | 注销版本 |
服务
| 命令 | 说明 |
|---|---|
aws ecs create-service | 创建服务 |
aws ecs update-service | 更新服务 |
aws ecs describe-services | 获取服务详情 |
aws ecs delete-service | 删除服务 |
任务
| 命令 | 描述 |
|---|---|
aws ecs run-task | 运行独立任务 |
aws ecs stop-task | 停止正在运行的任务 |
aws ecs describe-tasks | 获取任务详情 |
aws ecs list-tasks | 列出任务 |
最佳实践
安全
- 使用任务角色访问 AWS API(而非访问密钥)
- 使用执行角色访问 ECR/Secrets
- 将机密存储在 Secrets Manager 或 Parameter Store 中
- 使用带 NAT 网关的私有子网
- 启用 CloudTrail 进行 API 审计
- 通过 IAM 限制任务规格——
ecs:task-cpu/ecs:task-memory条件键适用于RunTask和StartTask,也适用于RegisterTaskDefinition、CreateService、UpdateService
性能
- 合理设置 CPU/内存规格——监控并调整
- 对容错工作负载使用 Fargate Spot(节省 70%)
- 启用容器洞察进行监控
- 使用服务发现进行内部通信
可靠性
- 跨多个 AZ 部署
- 正确配置运行状况检查
- 设置适当的注销延迟
- 在部署中使用断路器
aws ecs update-service \
--cluster my-cluster \
--service web-service \
--deployment-configuration '{
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true,
"resetOnHealthyTask": true,
"thresholdConfiguration": {"type": "BOUNDED_PERCENT", "value": 50}
}
}'
- **调整断路器阈值:**默认值
BOUNDED_PERCENT/50 = 期望任务数的 50%,失败次数限制在 3 到 200 次之间。UNBOUNDED_PERCENT取消此限制(适用于大型服务);COUNT将value用作固定失败次数(例如,为快速开发回滚设置较低值)。resetOnHealthyTask: false会累计计算失败次数,而非只计算连续失败次数。 - 提前成功条件(仅适用于滚动部署):当新修订版中达到
healthyPercent比例的期望任务运行状况正常时,即标记部署成功;其余任务通过常规服务扩缩启动。healthyPercent必须介于minimumHealthyPercent和 100 之间;副本服务默认minimumHealthyPercent为 100,因此使用较低的healthyPercent时需显式设置该值。提前完成后,断路器和警报回滚将不再适用。sourceServiceRevisionCleanup:BLOCKING会在成功前排空旧任务;DEFERRED会先声明成功,再异步排空旧任务(适用于长连接、缩容保护)。
aws ecs update-service \
--cluster my-cluster \
--service web-service \
--deployment-configuration '{
"strategy": "ROLLING",
"minimumHealthyPercent": 75,
"earlySuccessCriteria": {"enable": true, "healthyPercent": 90, "sourceServiceRevisionCleanup": "BLOCKING"}
}'
- Service Connect 区域感知路由默认启用(优先选择同一 AZ 的端点,降低跨 AZ 成本);现有服务需要重新部署一次才能启用该功能。
- EC2 启动类型:迁移到 Amazon Linux 2023 ECS 优化型 AMI。AL2 ECS 优化型 AMI 将于 2026 年 6 月 30 日结束生命周期(不再发布新 AMI,Agent 版本将固定)。
- **Fargate:**平台版本
1.3.0已于 2026 年 6 月 15 日弃用。请使用LATEST或1.4.0。
成本优化
- 对批处理工作负载使用 Fargate Spot
- 合理设置任务资源规格
- 不需要时缩容至零
- 对混合使用 Fargate/Spot 的场景使用容量提供程序
故障排除
任务无法启动
检查:
# View stopped tasks
aws ecs describe-tasks \
--cluster my-cluster \
--tasks $(aws ecs list-tasks --cluster my-cluster --desired-status STOPPED --query 'taskArns[0]' --output text)
常见原因:
- 找不到镜像(ECR 权限)
- 访问机密遭拒
- 网络配置(子网、安全组)
- 超出资源限制
容器不断重启
调试:
# Check CloudWatch logs
aws logs get-log-events \
--log-group-name /ecs/web-app \
--log-stream-name "ecs/web/abc123"
# Check task details
aws ecs describe-tasks \
--cluster my-cluster \
--tasks task-arn \
--query 'tasks[0].containers[0].{reason:reason,exitCode:exitCode}'
原因:
- 运行状况检查失败
- 应用程序崩溃
- 内存不足
使用 ECS Exec 实时调试
无需 SSH,即可直接连接到正在运行的容器。需要在服务中设置 enableExecuteCommand: true,并在容器镜像中安装 SSM Agent(大多数基础镜像都包含该 Agent)。
# Enable on existing service
aws ecs update-service \
--cluster my-cluster \
--service web-service \
--enable-execute-command
# Get a shell in a running task
TASK_ARN=$(aws ecs list-tasks --cluster my-cluster --service-name web-service \
--query 'taskArns[0]' --output text)
aws ecs execute-command \
--cluster my-cluster \
--task $TASK_ARN \
--container web \
--interactive \
--command "/bin/sh"
**要求:**任务角色必须具有 ssmmessages:CreateControlChannel、ssmmessages:CreateDataChannel、ssmmessages:OpenControlChannel、ssmmessages:OpenDataChannel 权限。
服务部署卡住
# Check deployment status
aws ecs describe-services \
--cluster my-cluster \
--services web-service \
--query 'services[0].deployments'
# Check events
aws ecs describe-services \
--cluster my-cluster \
--services web-service \
--query 'services[0].events[:5]'
原因:
- 新任务的运行状况检查失败
- 容量不足
- 目标组运行状况检查失败
操作日志(部署期间 ECS 执行了哪些操作)
每个集群可选择启用。记录 ECS 在服务部署期间执行的操作(状态转换、回滚、生命周期钩子)以及托管式守护进程的生命周期,并包含时间戳、logLevel INFO/WARN/ERROR 和状态原因。即使停止的任务保留时间超过 1 小时,这些日志仍会保留失败元数据。按 CloudWatch 托管日志计费。
aws logs put-delivery-source \
--name my-ecs-action-logs \
--resource-arn arn:aws:ecs:us-east-1:123456789012:cluster/my-cluster \
--log-type EcsActionLogs
aws logs put-delivery-destination \
--name my-ecs-logs-destination \
--output-format json \
--delivery-destination-configuration '{"destinationResourceArn": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/vendedlogs/ecs/action-logs/my-cluster"}'
aws logs create-delivery \
--delivery-source-name my-ecs-action-logs \
--delivery-destination-arn arn:aws:logs:us-east-1:123456789012:delivery-destination:my-ecs-logs-destination
需要: logs:PutDeliverySource、logs:PutDeliveryDestination、logs:CreateDelivery、logs:GetDelivery、ecs:AllowVendedLogDeliveryForResource;日志组资源策略必须允许 delivery.logs.amazonaws.com 执行 logs:CreateLogStream/logs:PutLogEvents。每个服务/守护进程 ARN 对应一个日志流。
将 EC2 主机迁移到 AL2023 后发生 OOM 终止
AL2023 使用 cgroup v2:如果只设置任务级别的 memory,容器将无法读取该限制,因此 JVM 和类似运行时会根据主机内存来确定堆大小。将容器级别的 memory 设置为与任务内存相同,或者在 /etc/ecs/ecs.config 中设置 ECS_PROPAGATE_TASK_MEMORY_LIMIT_CGROUPV2=true(agent 1.104.0+)。在 cgroup v2 上,报告的内存用量还包括页面缓存,因此利用率读数会高于 AL2。
无法从 ECR 拉取映像
检查执行角色是否具有:
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": "*"
}
另请检查:
- ECR 的 VPC 端点(如果使用私有子网)
- NAT 网关(如果使用私有子网)
- 安全组是否允许出站 HTTPS