メインコンテンツへスキップ
友田 陽大
ECS on Fargate 本番運用
AWS
ECS
Fargate
トラブルシューティング
可観測性
デバッグ
コンテナ
運用

ECS on Fargate トラブルシューティング完全ガイド:タスクが起動しない・すぐ落ちる原因を停止理由コード別に診断・修復する

ECS Fargate のタスク停止理由(CannotPullContainerError・OutOfMemory・ヘルスチェック失敗など)を describe-tasks の読み方から停止コード別に体系的に診断・修復する実務ガイド。

公開日
読了時間
19分
著者
友田 陽大
シェア

「デプロイしたらタスクが起動しない」「起動してもすぐ落ちる」「ALBのヘルスチェックを永遠に通らない」——ECS on Fargate の運用で必ず一度は踏む問題です。

私は木材流通B2B SaaSで API Gateway → NLB → ALB → ECS on Fargate の構成に221本のエンドポイントを乗せ、決済基盤(本番二重課金0件)のワーカー群も同じ基盤で動かしてきました。タスク停止の問題は「運用の注意深さ」ではなく、診断の型と構造的な予防で潰します。CloudWatch を凝視して「何かおかしい」と感じる前に、stoppedReasonstopCode から論理的に原因を絞るのが最短ルートです。

この記事は、ECS Fargate のタスク停止理由をカテゴリ別に体系化し、「どこを見るか → 何が原因か → どう直すか → どう再発防止するか」を一気通貫で示す実務ガイドです。本番設計の全体像は ECS on Fargate 本番運用ガイド を先に読んでおくと理解が深まります。


まず見るべき場所:診断の起点

「タスクが落ちた」と気づいた瞬間から、確認する場所は4つです。

確認場所何がわかるか
コンソール「Stopped tasks」タブstoppedReason のサマリ、exitCode、最終ステータス
aws ecs describe-tasks全フィールドの構造化データ(最も詳細)
CloudWatch Logs(awslogs)アプリが自分で書いたログ(パニック・起動失敗など)
EventBridge「ECS Task State Change」イベント非同期の停止通知。アラート連携・自動対応の起点

最初の一手はこれ一択です。

aws ecs describe-tasks \
  --cluster prod \
  --tasks <task-id> \
  --query 'tasks[0].{lastStatus:lastStatus,stoppedReason:stoppedReason,stopCode:stopCode,containers:containers[*].{name:name,reason:reason,exitCode:exitCode,lastStatus:lastStatus}}' \
  --output json

describe-tasks の読み方:5フィールドを必ず確認する

{
  "lastStatus": "STOPPED",
  "stoppedReason": "Essential container in task exited",
  "stopCode": "EssentialContainerExited",
  "containers": [
    {
      "name": "app",
      "lastStatus": "STOPPED",
      "exitCode": 1,
      "reason": ""
    }
  ]
}
フィールド意味注目ポイント
lastStatusタスク全体の現在状態STOPPED が確定
stoppedReason人間向けの停止理由テキスト「CannotPullContainerError」「Your Spot Task was interrupted.」などカテゴリが読める
stopCode機械判別用の停止コードEventBridgeフィルタやアラートに使う
containers[].exitCodeコンテナプロセスの終了コード0=正常、1=アプリエラー、137=OOMKill、null=起動すら到達していない
containers[].reasonコンテナ個別の理由pullエラーなどはここに詳細が出る

exitCode が null の場合は、アプリが起動するより前にFargateエージェント側で失敗しています(CannotPullContainer / ResourceInitializationError など)。アプリのログを追う前に、エージェント側の原因を潰してください。


診断フローチャート

タスクが STOPPED になった
        |
        +-- stoppedReason に "CannotPullContainer" ?
        |       YES → § CannotPullContainerError へ
        |
        +-- stoppedReason に "ResourceInitializationError" ?
        |       YES → § ResourceInitializationError へ
        |
        +-- stopCode = "EssentialContainerExited" ?
        |       YES → containers[].exitCode を確認
        |               exitCode=137 → § OutOfMemoryError へ
        |               exitCode≠0, null 以外 → § Essential container exited へ
        |               exitCode=null → § CannotStartContainerError へ
        |
        +-- stoppedReason に "health check" / "ELB" ?
        |       YES → § ELBヘルスチェック失敗 へ
        |
        +-- stopCode = "SpotInterruption" ?
        |       YES → § Spot中断 へ(障害ではない)
        |
        +-- stoppedReason に "timeout" ?
                YES → § ContainerRuntimeTimeoutError へ

CannotPullContainerError:イメージが pull できない

症状

タスクが PROVISIONINGPENDING で止まり、stoppedReason に以下が出る。

CannotPullContainerError: pull image manifest has been retried 1 time(s): failed to resolve ref ...

exitCode は null(アプリ起動に到達していない)。

原因別チェックリスト

① VPCエンドポイント / NAT が不足(最多)

プライベートサブネットで assignPublicIp=false の構成なのに、以下のいずれもない状態。

  • NAT Gateway(アウトバウンド経路)
  • ECR 用 VPC エンドポイント(com.amazonaws.<region>.ecr.api + com.amazonaws.<region>.ecr.dkr
  • S3 ゲートウェイエンドポイント(ECRのレイヤーはS3に格納されているため必須)
# VPCエンドポイント一覧を確認
aws ec2 describe-vpc-endpoints \
  --filters "Name=vpc-id,Values=<vpc-id>" \
  --query 'VpcEndpoints[*].{Service:ServiceName,State:State}'

必要な最小セット(プライベートサブネット構成):

エンドポイント種別用途
ecr.apiInterfaceタスク定義のイメージURL解決
ecr.dkrInterfaceレイヤーのpull(Docker Registry API)
s3GatewayECRレイヤーの実体(S3に格納)
logsInterfaceawslogs ドライバ(CloudWatch Logs)
secretsmanagerInterfacesecrets valueFrom(使う場合)
ssmmessagesInterfaceECS Exec(使う場合)

② 実行ロールに ECR 権限が無い

executionRoleArnAmazonECSTaskExecutionRolePolicy が付いていないか、カスタムポリシーが不足。

{
  "Effect": "Allow",
  "Action": [
    "ecr:GetAuthorizationToken",
    "ecr:BatchCheckLayerAvailability",
    "ecr:GetDownloadUrlForLayer",
    "ecr:BatchGetImage"
  ],
  "Resource": "*"
}

注意: ecr:GetAuthorizationToken はリソースを * にしないと機能しません。

③ タグ・ダイジェスト誤り

指定したタグが ECR に存在しないか、digest が変更されている。

# ECR でタグ一覧を確認
aws ecr describe-images \
  --repository-name web-api \
  --query 'imageDetails[*].{Tags:imageTags,Pushed:imagePushedAt}' \
  --output table

④ Docker Hub レート制限

Docker Hub の公式イメージ(node:20など)を直接使っている場合、匿名プルのレート制限に引っかかることがある。ECR Public または ECR にミラーしてプルする運用に切り替える。

修復フロー

1. プライベートサブネット構成か確認
   YES → VPCエンドポイント(ecr.api / ecr.dkr / s3)を追加
         または NAT Gateway を確認

2. 実行ロールのポリシーを確認
   → AmazonECSTaskExecutionRolePolicy がアタッチされているか

3. イメージURIを確認
   → ECR にそのタグが存在するか describe-images で確認

4. SGを確認
   → VPCエンドポイントのSGがタスクのSGからの443を許可しているか

予防

Terraform で VPC エンドポイントをコード管理し、Plan 段階で経路欠如を検知する。ECR プッシュをCIパイプラインで行い、タグの存在を push 直後に確認してからデプロイをトリガーする。


ResourceInitializationError:リソース初期化失敗

症状

タスク起動の初期フェーズでエラー。stoppedReason に下記のようなメッセージ。

ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: ...

あるいは:

ResourceInitializationError: failed to configure ENI: ...

原因と診断

ResourceInitializationError は CannotPullContainer の親カテゴリに近い位置にあります。Fargateエージェントがネットワーク設定・シークレット取得・ログ初期化を行う「起動前の初期化フェーズ」全体で起きます。

主な原因:

原因チェックポイント
secrets 取得失敗(Secrets Manager / SSM 到達不能)VPCエンドポイント secretsmanager / ssm の有無
実行ロールに GetSecretValue / GetParameter 権限なし実行ロールのポリシーを確認
ログ初期化失敗(CloudWatch Logs 到達不能)VPCエンドポイント logs の有無、ロールに logs:CreateLogStream
ENI 割当失敗(サブネットのIPアドレス枯渇)サブネットの空きIP数を describe-subnets で確認
SG がアウトバウンドを塞いでいるタスクSGのアウトバウンドルールを確認
# サブネットの空きIPを確認
aws ec2 describe-subnets \
  --subnet-ids <subnet-id> \
  --query 'Subnets[*].{CIDR:CidrBlock,Available:AvailableIpAddressCount}'

実行ロールとタスクロールの混同が連鎖エラーを生む

これが最も見落とされるパターンです。ECS on Fargate 本番運用ガイドでも詳述していますが、改めて整理します。

ロール設定キー使用主体典型的な権限
実行ロールexecutionRoleArnECSエージェント(起動時)ECR pull、CloudWatch Logs書込、SecretsManager取得
タスクロールtaskRoleArnアプリコード(実行中)S3・DynamoDB・SQSなどアプリ固有のAWSリソース

シークレット注入(secrets[].valueFrom)はエージェントが起動時に取得するため、権限は実行ロールに付ける。アプリが実行中に aws secretsmanager get-secret-value を呼ぶ場合だけ、タスクロールに付ける。この原則を守らないと ResourceInitializationError として現れます。


OutOfMemoryError:メモリ上限超過

症状

タスクの stoppedReason に:

OutOfMemoryError: Container killed due to memory usage

または containers[].exitCode = 137(Linux の OOMKill は exit code 137)。

原因と診断

Fargateのメモリ制限はコンテナレベルで設定します。コンテナのメモリ使用量がタスク定義の memory(上限)を超えると、Linuxのカーネル OOM Killer がプロセスを強制終了します。

# Container Insights でメモリ使用量を確認(クエリ例)
aws cloudwatch get-metric-statistics \
  --namespace ECS/ContainerInsights \
  --metric-name MemoryUtilized \
  --dimensions Name=ClusterName,Value=prod Name=ServiceName,Value=web-api \
  --start-time $(date -u -v-1H +%Y-%m-%dT%H:%M:%S) \
  --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
  --period 60 \
  --statistics Average Maximum

原因の仕分け:

パターン見分け方対処
タスクサイズの見積もり不足常時OOMKill。最大値がlimitに達しているタスクサイズを上のペアに変更
メモリリーク起動直後は正常だが徐々に増加して落ちるヒープダンプ/プロファイラで調査
スパイク時の瞬間超過特定時間帯や高負荷時のみソフトリミット(memoryReservation)とハードリミット(memory)を分けて設定

タスク定義のメモリ設定には2つのレベルがあります。

{
  "name": "app",
  "memory": 1024,
  "memoryReservation": 512
}
  • memory(ハードリミット): これを超えるとOOMKill
  • memoryReservation(ソフトリミット): スケジューリング時の目安。超えても即Killはしない

スパイク耐性を持たせるには、memoryReservation を通常使用量より少し上に、memory をその1.5〜2倍程度に設定して、余裕のバッファを持たせます。ただし、Fargateのタスクメモリ上限は task.memory と等しく、コンテナの合計が超えると起動できません。


Essential container exited / 非ゼロ exitCode:アプリ起動失敗

症状

Essential container in task exited

stopCode = EssentialContainerExitedcontainers[].exitCode が非ゼロ(0以外)。

診断手順

Step 1: CloudWatch Logs を確認する(最重要)

# ログストリームの最新を取得
aws logs get-log-events \
  --log-group-name /ecs/web-api \
  --log-stream-name app/<task-id> \
  --limit 50 \
  --query 'events[*].message'

Fargate は awslogs ドライバ経由でアプリのSTDOUT/STDERRをCloudWatch Logsに書きます。アプリが「設定ファイルが読めない」「DB接続失敗」「ポートが既に使われている」などで panic/exit した記録が必ずここに残ります。

Step 2: 環境変数・シークレットの不足を確認

secrets[].valueFrom で参照しているシークレットのARNが間違っていたり、該当バージョンが存在しない場合、起動に必要な環境変数が空になってアプリがクラッシュする。

# シークレットの存在確認
aws secretsmanager describe-secret \
  --secret-id arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:prod/db-Ab12Cd

Step 3: CMD / ENTRYPOINT の確認

タスク定義の command が間違っている、または存在しないパスを参照しているケース。

# ローカルでイメージを起動して再現確認
docker run --rm \
  -e DATABASE_URL=<test-url> \
  111122223333.dkr.ecr.ap-northeast-1.amazonaws.com/web-api:latest

よくある exitCode 一覧:

exitCode意味対処の方向
1一般的なアプリエラーCloudWatch Logs でエラー内容を確認
2Bash の誤用 / シェルエラーCMD/ENTRYPOINT の構文確認
127コマンドが見つからないパス / バイナリ名の誤り
137SIGKILL(OOMKillまたは手動kill)メモリ設定またはStopTask操作
143SIGTERM(グレースフルシャットダウン正常受理)正常停止。意図的な停止かを確認

Task failed ELB health checks:ヘルスチェック通過失敗

症状

タスクは起動しているのにサービスが不健全と判定され、タスクが繰り返し入れ替わる。ECSサービスのイベントに以下が出る。

service web-api (port 8080) is unhealthy in target-group arn:... due to (reason Health checks failed)

診断フロー

① target_type = "ip" か確認(Fargate固有の落とし穴)

ALBのターゲットグループが target_type = "instance" のままだと、Fargate タスクを正しく登録できない。

aws elbv2 describe-target-groups \
  --query 'TargetGroups[*].{Name:TargetGroupName,TargetType:TargetType}'

必ず ip であることを確認する。instance になっていたら作り直し(変更不可)。

② ヘルスチェックパスとポートの確認

ALBのターゲットグループに設定したヘルスチェックパス(例 /healthz)がアプリで実装されていて、正しいポートを返すか。

# タスクのENI IPを取得してヘルスチェックを手動実行
TASK_ENI_IP=$(aws ecs describe-tasks \
  --cluster prod --tasks <task-id> \
  --query 'tasks[0].attachments[0].details[?name==`privateIPv4Address`].value' \
  --output text)

# VPC内の踏み台から確認(直接疎通できる場合)
curl -v http://${TASK_ENI_IP}:8080/healthz

③ SG がヘルスチェックをブロックしていないか

タスクのSGインバウンドルールが「ALBのSGのみ許可」になっていても、ALBのSGのヘルスチェック送信元 と一致していなければ通らない。

# タスクSGのインバウンドルールを確認
aws ec2 describe-security-groups \
  --group-ids <task-sg-id> \
  --query 'SecurityGroups[*].IpPermissions'

④ startPeriod と grace period の設定

起動に時間がかかるアプリ(DBマイグレーション実行・大きなモデルロードなど)は、ヘルスチェックが始まる前の猶予を設定しないと、初期化中に「不健全」と判定されてKillされる。

{
  "healthCheck": {
    "startPeriod": 60,
    "interval": 15,
    "timeout": 5,
    "retries": 3
  }
}

加えて、ECSサービス側にも health_check_grace_period_seconds が必要です。

resource "aws_ecs_service" "app" {
  # ...
  health_check_grace_period_seconds = 60
}

healthCheck.startPeriod(タスク定義内コンテナのヘルスチェック猶予)と health_check_grace_period_seconds(ECSサービスが ALB ヘルスチェック失敗を無視する猶予)は別物です。ALBに登録されてからの猶予は後者で設定します。

ヘルスチェック診断チェックリスト:

  • target_type = "ip" になっているか
  • ヘルスチェックパスがアプリで 200 を返すか
  • ヘルスチェックのポート番号がコンテナポートと一致しているか
  • タスクSGがALBのSGからのインバウンドを許可しているか
  • タスク定義の healthCheck.startPeriod が設定されているか
  • ECSサービスの health_check_grace_period_seconds が設定されているか

SpotInterruption:Spot中断は"障害"ではない

症状

stopCode: "SpotInterruption"
stoppedReason: "Your Spot Task was interrupted."

正しい理解

Spot 中断はAWSが容量を回収するための設計された動作であり、ソフトウェアのバグでも運用ミスでもありません。対処すべきは「中断が起きたとき壊れない設計になっているか」です。

Spot 中断の仕組み:

  1. AWSが容量回収を決定(通常の通知より2分前)
  2. EventBridge に ECS Task State Change イベント発行(stopCode=SpotInterruption)
  3. タスクに SIGTERM を送信(stopTimeout の猶予あり、最大120秒)
  4. 猶予後に SIGKILL

設計で吸収する3点セット:

① グレースフルシャットダウン:SIGTERMを受けてin-flightを捌き切る
② 冪等な処理:途中でKillされても、再起動後に二重処理しない
③ 容量プロバイダ戦略:baseをオンデマンドで守り、追加分をSpotに割り当て
# Spot 中断をEventBridgeで検知してアラートへ
resource "aws_cloudwatch_event_rule" "spot_interruption" {
  name        = "ecs-spot-interruption"
  event_pattern = jsonencode({
    source      = ["aws.ecs"]
    detail-type = ["ECS Task State Change"]
    detail = {
      stopCode = ["SpotInterruption"]
    }
  })
}

グレースフルシャットダウンの実装パターンは ECS on Fargate 本番運用ガイド の「SIGTERMを受けて綺麗に終わる」節を参照してください。stopTimeout の既定は30秒、最大は120秒です。本番ではアプリの drain 時間に合わせて明示的に設定します。


CannotStartContainerError / ContainerRuntimeTimeoutError

症状

CannotStartContainerError: ...
ContainerRuntimeTimeoutError: Timeout waiting for container to start

exitCode は null(コンテナプロセス起動に到達していない)。

原因と診断

CannotStartContainerError:

  • command / entryPoint に実行権限のないバイナリを指定
  • volumes のマウント先に書き込めない(readonlyRootFilesystem: true のとき特に)
  • user で指定した UID がコンテナ内に存在しない
  • linuxParameters の依存設定が Fargate でサポート外
# ローカルで同じ設定を再現
docker run --rm \
  --user 10001:10001 \
  --read-only \
  --tmpfs /tmp \
  my-image:tag

ContainerRuntimeTimeoutError:

コンテナの起動シーケンス(ENTRYPOINT/CMD の実行開始)がタイムアウト。依存サービスへの接続待ちが長すぎる場合など。起動時の初期化処理で外部サービスを待っているなら、ヘルスチェックの startPeriod を延ばすか、起動シーケンスから外部依存を切り離すことを検討する。


ECS Exec:動いているコンテナの中で調査する

タスクが動いているとき(または起動直後のデバッグ中)に、コンテナの中に直接入って調査できるのが ECS Exec です。SSHもポート開放も鍵管理も不要です。

前提条件

① ECS サービス / タスクで enableExecuteCommand: true

resource "aws_ecs_service" "app" {
  enable_execute_command = true
  # ...
}

注意: enableExecuteCommand新しく起動するタスクにのみ有効です。既存タスクには後付けできません。設定変更後に force-new-deployment でタスクを差し替えてください。

② タスクロールに ssmmessages の4アクション

{
  "Effect": "Allow",
  "Action": [
    "ssmmessages:CreateControlChannel",
    "ssmmessages:CreateDataChannel",
    "ssmmessages:OpenControlChannel",
    "ssmmessages:OpenDataChannel"
  ],
  "Resource": "*"
}

これはタスクロールtaskRoleArn)に付ける権限です(実行ロールではない)。

③ SSM Session Manager プラグイン(クライアント側)

# macOS
brew install session-manager-plugin

実際のコマンド

# タスクIDを確認
TASK_ID=$(aws ecs list-tasks \
  --cluster prod \
  --service-name web-api \
  --query 'taskArns[0]' \
  --output text | awk -F/ '{print $NF}')

# コンテナに入る
aws ecs execute-command \
  --cluster prod \
  --task ${TASK_ID} \
  --container app \
  --interactive \
  --command "/bin/sh"

シェルに入ったら、環境変数・ファイル存在・ネットワーク疎通などを直接確認できます。

# コンテナ内で環境変数の確認
env | grep DATABASE

# DB への疎通確認
nc -zv db.internal 5432

# プロセスの確認
ps aux

ECS Exec の監査

ECS Exec の全操作は CloudTrail に記録されます(ExecuteCommand API 呼び出しとして)。さらに logging: OVERRIDE で設定すると、セッションの入出力を CloudWatch Logs または S3 に保存できます。本番コンテナへのアクセスには必ずこの監査ログを有効にしておくことを推奨します。

可観測性のより深い実装については OpenTelemetry × ECS の可観測性 を参照してください。


予防:可観測性で再発を止める

問題を一度解決したら、同じ問題で再度時間を使わないよう構造的な予防を入れます。

1. 構造化ログ + 相関ID

全ログを JSON で出力し、requestId / traceId を必ず含める。CloudWatch Logs Insights でフィルタできるようになります。

// 構造化ログの最小実装
const log = (level: string, msg: string, ctx: Record<string, unknown> = {}) => {
  process.stdout.write(
    JSON.stringify({ level, msg, timestamp: new Date().toISOString(), ...ctx }) + "\n"
  );
};

// リクエストIDを全ログに通す
log("info", "server:start", { port: 8080, env: process.env.NODE_ENV });

2. Container Insights + アラート

resource "aws_cloudwatch_metric_alarm" "task_stopped" {
  alarm_name          = "ecs-task-stopped-abnormally"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name         = "RunningTaskCount"
  namespace           = "ECS/ContainerInsights"
  period              = 60
  statistic           = "Minimum"
  threshold           = 0
  alarm_description   = "全タスクが停止した(desired > 0 にもかかわらず)"
  dimensions = {
    ClusterName = "prod"
    ServiceName = "web-api"
  }
}

3. デプロイサーキットブレーカー

新タスクが連続してヘルスチェックに失敗したとき、自動で前リビジョンへロールバックします。

resource "aws_ecs_service" "app" {
  deployment_circuit_breaker {
    enable   = true
    rollback = true
  }
}

これだけで「ミスデプロイが本番に刺さり続ける」事故を構造的に防げます。CI/CDパイプラインとの統合は ECS on Fargate CI/CD ガイド で詳述しています。

4. ヘルスチェックの startPeriod を必ず設定

{
  "healthCheck": {
    "startPeriod": 30,
    "interval": 15,
    "timeout": 5,
    "retries": 3
  }
}

startPeriod なしのデフォルトは0秒。起動中の一時的な不健全状態でタスクが落とされます。

5. ネットワーク設計は Terraform でコード化

VPCエンドポイントの欠如が CannotPullContainer / ResourceInitializationError の最多原因です。ECS on Fargate ネットワーキングガイド のパターンを Terraform で管理し、環境間の設定差分をなくします。


早見表:停止理由 → 真っ先に見る場所 → 典型原因 → 修復

停止理由 / stopCode真っ先に見る場所典型原因修復
CannotPullContainerErrorVPCエンドポイント一覧、実行ロールプライベートサブネットでNAT/VPCエンドポイント欠如、実行ロールのECR権限不足ECR用エンドポイント追加 or NAT確認、ポリシー付与
ResourceInitializationError実行ロール、VPCエンドポイント(secretsmanager/logs/ssm)シークレット取得不能、ログ書込不能、ENI割当失敗実行ロールに権限追加、VPCエンドポイント追加、サブネットIP枯渇確認
EssentialContainerExited (exitCode≠0)CloudWatch Logsアプリ起動失敗、env/secrets不足、CMD誤りログでエラー内容確認、環境変数・コマンドを修正
EssentialContainerExited (exitCode=137)Container Insights メモリグラフOOMKill(メモリ上限超過)タスクメモリを上のペアに変更、リークを調査
EssentialContainerExited (exitCode=null)describe-tasks の containers[].reasonCannotStartContainer(起動前失敗)CMD/ENTRYPOINTのパス・権限確認
ELBヘルスチェック失敗ALBターゲットグループ設定、タスクSGtarget_type=instance、SG設定ミス、startPeriod不足target_type=ipに変更、SG許可追加、startPeriod設定
SpotInterruptionEventBridgeイベントSpot容量回収(正常動作)グレースフルシャットダウン実装、冪等設計を確認
ContainerRuntimeTimeoutErrorタスク定義のCMD/ENTRYPOINT起動処理が長すぎる、依存サービスへの接続待ち起動シーケンスの最適化、startPeriod延長
CannotCreateVolumeErrorタスク定義のvolumes、EFS設定EFSマウントターゲット不達、SG設定EFSエンドポイントとSGを確認

まとめ

ECS on Fargate のトラブルシューティングは、「何かがおかしい」という感覚から始めるのではなく、stoppedReasonstopCodeexitCode → CloudWatch Logs という順序で論理的に絞り込む型が最速です。

私が実務で積み重ねてきた経験から言うと、タスクが起動しない問題の大多数は次の3つに集約されます。

  1. ネットワーク到達性(プライベートサブネットでVPCエンドポイントまたはNAT不足)
  2. 実行ロールとタスクロールの混同(権限が間違ったロールに付いている)
  3. ヘルスチェックの猶予不足(startPeriod と grace period が設定されていない)

決済基盤で二重課金0件を実現できたのも、「障害が起きてから直す」ではなく、構造と可観測性で問題を事前に潰す設計を一貫して持っていたからです。Fargateの本番環境を速く・安全に安定させたい場合は、お気軽にご相談ください。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

環境分野のサーバーレス決済プラットフォーム(フルスタック開発・決済信頼性レイヤーを主導)

ケーススタディを見る