aws-ecs-fargate について
Fargate または EC2 を使い、Amazon ECS でコンテナアプリケーションをデプロイ、運用するためのスキルです。AWS の利用者向けに、クラスター設定、デプロイ、スケーリング、ログ確認、トラブルシューティングを案内します。
主な機能
- 01ECS クラスターとタスクの設定
- 02コンテナイメージの ECR への push
- 03ALB を使うサービスの設定
- 04ローリングデプロイと自動スケーリング
- 05CloudWatch ログの確認
- 06タスクとネットワークの問題解決
活用シーン
- 01サーバー管理なしで Fargate にコンテナをデプロイ
- 02ロードバランサー配下でマイクロサービスを実行
- 03コンテナワークロードのスケーリング設定
- 04タスク失敗やヘルスチェック問題の診断
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill aws-ecs-fargateインストール後、Claude Code で/aws-ecs-fargateを入力して読み込まれたか確認します。
詳細
AWS ECS & Fargate
Fargate のサーバーレスコンピューティングまたは EC2 起動タイプを使用して、Amazon ECS でコンテナ化されたアプリケーションを実行します。
このスキルを使用する場面
- サーバーを管理せずに Docker コンテナを AWS にデプロイする場合(Fargate)
- サービスディスカバリーとロードバランシングを使用してマイクロサービスを実行する場合
- コンテナ化されたアプリ向けにブルー/グリーンデプロイやローリングデプロイを設定する場合
- コンテナワークロードの自動スケーリングを設定する場合
- docker-compose または Kubernetes から ECS に移行する場合
- タスクの失敗、ヘルスチェックの問題、ネットワークの問題をトラブルシューティングする場合
前提条件
- AWS CLI v2 がインストールされ、設定されていること
- イメージをビルドしてプッシュするために Docker がインストールされていること
- IAM 権限:
ecs:*、ecr:*、elasticloadbalancing:*、logs:*、iam:PassRole - コンテナイメージを保存するための ECR リポジトリ
- サブネットと ALB を備えた VPC(aws-vpc を参照)
クラスターのセットアップ
# Create an ECS cluster with Container Insights enabled
aws ecs create-cluster \
--cluster-name production \
--capacity-providers FARGATE FARGATE_SPOT \
--default-capacity-provider-strategy '[
{"capacityProvider": "FARGATE", "weight": 1, "base": 2},
{"capacityProvider": "FARGATE_SPOT", "weight": 3}
]' \
--settings '[{"name": "containerInsights", "value": "enabled"}]'
# List clusters
aws ecs list-clusters
# Describe cluster details
aws ecs describe-clusters --clusters production --include STATISTICS ATTACHMENTS
ECR へのイメージのプッシュ
# Create ECR repository
aws ecr create-repository \
--repository-name myapp \
--image-scanning-configuration scanOnPush=true \
--encryption-configuration encryptionType=KMS
# Authenticate Docker to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
# Build, tag, and push
docker build -t myapp:latest .
docker tag myapp:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
タスク定義
{
"family": "myapp",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "myapp",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest",
"essential": true,
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"environment": [
{"name": "NODE_ENV", "value": "production"},
{"name": "PORT", "value": "8080"}
],
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:myapp/db-password"
},
{
"name": "API_KEY",
"valueFrom": "arn:aws:ssm:us-east-1:123456789012:parameter/myapp/api-key"
}
],
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
},
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/myapp",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs",
"awslogs-create-group": "true"
}
},
"ulimits": [
{"name": "nofile", "softLimit": 65536, "hardLimit": 65536}
]
}
]
}
# Register the task definition
aws ecs register-task-definition --cli-input-json file://task-definition.json
# List task definition revisions
aws ecs list-task-definitions --family-prefix myapp
# Deregister an old revision
aws ecs deregister-task-definition --task-definition myapp:1
ALB を使用したサービスの作成
# Create the CloudWatch log group first
aws logs create-log-group --log-group-name /ecs/myapp
aws logs put-retention-policy --log-group-name /ecs/myapp --retention-in-days 30
# Create ECS service with load balancer
aws ecs create-service \
--cluster production \
--service-name myapp \
--task-definition myapp:2 \
--desired-count 3 \
--launch-type FARGATE \
--platform-version LATEST \
--deployment-configuration '{
"deploymentCircuitBreaker": {"enable": true, "rollback": true},
"maximumPercent": 200,
"minimumHealthyPercent": 100
}' \
--network-configuration '{
"awsvpcConfiguration": {
"subnets": ["subnet-private-a", "subnet-private-b"],
"securityGroups": ["sg-app"],
"assignPublicIp": "DISABLED"
}
}' \
--load-balancers '[{
"targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/myapp-tg/abc123",
"containerName": "myapp",
"containerPort": 8080
}]' \
--service-registries '[{
"registryArn": "arn:aws:servicediscovery:us-east-1:123456789012:service/srv-abc123"
}]' \
--enable-execute-command \
--propagate-tags SERVICE
デプロイ
# Rolling update - update task definition and force new deployment
aws ecs update-service \
--cluster production \
--service myapp \
--task-definition myapp:3 \
--force-new-deployment
# Watch deployment progress
aws ecs describe-services \
--cluster production \
--services myapp \
--query "services[0].deployments[].{Status:status,Running:runningCount,Desired:desiredCount,TaskDef:taskDefinition}" \
--output table
# Wait for service to stabilize
aws ecs wait services-stable --cluster production --services myapp
# Exec into a running container for debugging
aws ecs execute-command \
--cluster production \
--task arn:aws:ecs:us-east-1:123456789012:task/production/abc123 \
--container myapp \
--interactive \
--command "/bin/sh"
自動スケーリング
# Register ECS service as a scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/production/myapp \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 20
# Target tracking policy - scale on CPU utilization
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/production/myapp \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-target-tracking \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"TargetValue": 70.0,
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
# Scale on request count per target (ALB)
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/production/myapp \
--scalable-dimension ecs:service:DesiredCount \
--policy-name request-count-tracking \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ALBRequestCountPerTarget",
"ResourceLabel": "app/my-alb/abc123/targetgroup/myapp-tg/def456"
},
"TargetValue": 1000.0,
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
Terraform による ECS Fargate サービス
resource "aws_ecs_cluster" "main" {
name = "production"
setting {
name = "containerInsights"
value = "enabled"
}
}
resource "aws_ecs_task_definition" "myapp" {
family = "myapp"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 512
memory = 1024
execution_role_arn = aws_iam_role.ecs_execution.arn
task_role_arn = aws_iam_role.ecs_task.arn
container_definitions = jsonencode([{
name = "myapp"
image = "${aws_ecr_repository.myapp.repository_url}:latest"
essential = true
portMappings = [{
containerPort = 8080
protocol = "tcp"
}]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.myapp.name
awslogs-region = "us-east-1"
awslogs-stream-prefix = "ecs"
}
}
healthCheck = {
command = ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]
interval = 30
timeout = 5
retries = 3
startPeriod = 60
}
}])
}
resource "aws_ecs_service" "myapp" {
name = "myapp"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.myapp.arn
desired_count = 3
launch_type = "FARGATE"
deployment_circuit_breaker {
enable = true
rollback = true
}
network_configuration {
subnets = aws_subnet.private[*].id
security_groups = [aws_security_group.app.id]
assign_public_ip = false
}
load_balancer {
target_group_arn = aws_lb_target_group.myapp.arn
container_name = "myapp"
container_port = 8080
}
enable_execute_command = true
propagate_tags = "SERVICE"
}
ログの表示
# Tail logs from CloudWatch
aws logs tail /ecs/myapp --follow --since 1h
# Get logs for a specific task
aws logs get-log-events \
--log-group-name /ecs/myapp \
--log-stream-name "ecs/myapp/abc123def456" \
--start-from-head
# Filter logs for errors
aws logs filter-log-events \
--log-group-name /ecs/myapp \
--filter-pattern "ERROR" \
--start-time $(date -d '1 hour ago' +%s000)
トラブルシューティング
| 問題 | 原因 | 対処方法 |
|---|---|---|
| タスクが PROVISIONING のまま進まない | サブネットに利用可能なキャパシティがない | サブネットの利用可能状況とキャパシティプロバイダーを確認する |
| タスクがすぐに失敗する | 起動時にコンテナがクラッシュする | CloudWatch ログを確認し、まずイメージをローカルで実行する |
| ヘルスチェックが失敗する | startPeriod 内にアプリの準備が完了しない | startPeriod を延長し、ヘルスエンドポイントを確認する |
| ECR イメージをプルできない | 実行ロールに ECR 権限がない | AmazonECSTaskExecutionRolePolicy をアタッチする |
| サービスの実行中タスク数が 0 のまま | セキュリティグループが ALB のヘルスチェックをブロックしている | ALB の SG からコンテナのポートへのアクセスを許可する |
| Exec コマンドが失敗する | SSM エージェントが初期化されていない | enableExecuteCommand が true であることを確認し、タスクロールを確認する |
| Fargate のコストが高い | 許容可能なワークロードで Fargate Spot を使用していない | FARGATE_SPOT キャパシティプロバイダーを追加する |
| コンテナが OOM で強制終了される | メモリ制限が低すぎる | タスク定義の memory を増やし、メモリリークを確認する |
| デプロイが遅い | minimumHealthyPercent が高すぎる | ローリングアップデートを高速化するため、50% に設定する |
関連スキル
- docker-management - コンテナの基本
- container-registries - ECR とイメージ管理
- aws-vpc - ECS タスクのネットワーク
- aws-iam - タスクロールと実行ロール
- terraform-aws - Infrastructure as Code によるデプロイ
コメント
Markdown 対応