mcpField
A
aws-cloudwatch-investigation

aws-cloudwatch-investigation

github.com/githubクラウド・DevOps40.5k40 回インストール今日更新
リポジトリ

aws-cloudwatch-investigation について

本番インシデントに対応するエンジニア向けに、AWS CloudWatch の調査パターンをまとめたスキルです。ログやメトリクスのクエリ、アラームとデプロイの関連付け、影響範囲の特定、タイムラインの再構成を扱います。

主な機能

  1. 01Logs Insights によるエラー・遅延クエリ
  2. 02Lambda のコールドスタート・OOM・タイムアウト検出
  3. 03アラームとデプロイイベントの関連付け
  4. 04アカウントや依存関係をまたぐ影響範囲の特定
  5. 05インシデントタイムラインの再構成

活用シーン

  1. 01本番環境のエラーや遅延の急増を調査
  2. 02アラームと直近のデプロイの関連を評価
  3. 03複数サービスに及ぶ障害の共有依存先を特定
  4. 04ログ・メトリクス・変更を時系列に整理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/github/awesome-copilot --skill aws-cloudwatch-investigation

インストール後、Claude Code で/aws-cloudwatch-investigationを入力して読み込まれたか確認します。

詳細

AWS CloudWatch 調査スキル

CloudWatch Logs、Metrics、Alarms を使用して本番環境のインシデントを調査するための再利用可能なパターンです。これらのパターンは、インシデントのトリアージ中に組み合わせて使用できるように設計されています。


パターン 1:Logs Insights クエリテンプレート

エラー急増の検出

時間範囲内のエラーを種類ごとにグループ化し、上位のものを特定します。

fields @timestamp, @message, @logStream
| filter @message like /(?i)(error|exception|fatal|critical)/
| stats count(*) as errorCount by bin(5m), @logStream
| sort errorCount desc
| limit 20
オペレーション別の P99 レイテンシの内訳

どのオペレーションがレイテンシの急増を引き起こしているかを特定します。

fields @timestamp, @duration, operation
| filter ispresent(@duration)
| stats avg(@duration) as avgMs,
        pct(@duration, 50) as p50Ms,
        pct(@duration, 95) as p95Ms,
        pct(@duration, 99) as p99Ms,
        count(*) as invocations
  by operation
| sort p99Ms desc
| limit 15
Lambda のコールドスタート検出

インシデント中のコールドスタートの影響を定量化します。

fields @timestamp, @duration, @initDuration, @memorySize, @maxMemoryUsed
| filter ispresent(@initDuration)
| stats count(*) as coldStarts,
        avg(@initDuration) as avgInitMs,
        max(@initDuration) as maxInitMs,
        avg(@duration) as avgDurationMs
  by bin(5m)
| sort @timestamp desc
メモリ不足(OOM)の検出

メモリ不足により終了した Lambda 関数またはコンテナを特定します。

fields @timestamp, @message, @logStream, @memorySize, @maxMemoryUsed
| filter @message like /Runtime exited|out of memory|OOMKilled|Cannot allocate memory|MemoryError/
| stats count(*) as oomEvents by @logStream, bin(10m)
| sort oomEvents desc
| limit 10

OOM 発生前のメモリ使用率の推移を確認するには:

fields @timestamp, @maxMemoryUsed, @memorySize
| filter ispresent(@maxMemoryUsed)
| stats max(@maxMemoryUsed / @memorySize * 100) as peakMemPct,
        avg(@maxMemoryUsed / @memorySize * 100) as avgMemPct
  by bin(5m)
| sort @timestamp desc
タイムアウトの検出

設定されたタイムアウトに達した呼び出しを特定します。

fields @timestamp, @duration, @logStream, @requestId
| filter @message like /Task timed out/ or @duration > 28000
| stats count(*) as timeouts by @logStream, bin(5m)
| sort timeouts desc

パターン 2:アラーム履歴とデプロイイベントの相関付け

手順
  1. アラームの状態遷移時刻を取得する — アラームが ALARM 状態に入った正確なタイムスタンプを記録します。
  2. CloudTrail をクエリする — [alarm_time - 30min, alarm_time] の時間範囲で、デプロイ関連イベントを検索します。
# CloudTrail Lake query for deployment events
SELECT eventTime, eventName, userIdentity.arn, requestParameters
FROM <event-data-store-id>
WHERE eventTime > '<alarm_time_minus_30m>'
  AND eventTime < '<alarm_time>'
  AND eventName IN (
    'UpdateFunctionCode', 'UpdateFunctionConfiguration',
    'UpdateService', 'CreateDeployment', 'RegisterTaskDefinition',
    'CreateChangeSet', 'ExecuteChangeSet',
    'StartPipelineExecution', 'PutImage'
  )
ORDER BY eventTime DESC
  1. 相関の判定基準 — 次の条件を満たすデプロイを「相関あり」とします。

    • アラームと同じサービス/リソースを対象としている
    • アラームの状態遷移前 15 分以内に完了している
    • デプロイ実行者の ID が CI/CD ロールと一致する(人間によるホットフィックスの適用ではない)
  2. 相関の確度を高める:

    • 前回のデプロイサイクルで同じアラームが正常だったか確認します
    • 同じ時間範囲に、他の環境変更(スケーリングイベント、設定変更)がなかったことを確認します
    • 同じ時刻に開始したカナリア/合成モニターの失敗を探します
出力形式
Deploy Correlation:
  Event: UpdateFunctionCode
  Time: 2024-03-15T14:23:07Z (12 min before alarm)
  Actor: arn:aws:sts::123456789012:assumed-role/github-actions-deploy/session
  Resource: arn:aws:lambda:us-east-1:123456789012:function:payment-processor
  Correlation: STRONG — same resource, CI/CD actor, alarm was OK prior cycle

パターン 3:影響範囲を絞り込む決定木

この決定木を使って、最も広い範囲から最も具体的な範囲へと、インシデントのスコープを体系的に絞り込みます。

START
  |
  v
[1] ACCOUNT — Which account(s) show the alarm?
  |  - Check: Are alarms firing in multiple accounts?
  |  - If yes → suspect shared service (SSO, networking, shared deployment pipeline)
  |  - If no → proceed to Region
  v
[2] REGION — Which region(s) are affected?
  |  - Check: Same alarm in other regions?
  |  - If multi-region → suspect global service (IAM, Route53, S3 global)
  |  - If single-region → proceed to Service
  v
[3] SERVICE — Which service namespace shows degradation?
  |  - Check CloudWatch namespace: AWS/Lambda, AWS/ECS, AWS/ApiGateway, etc.
  |  - If multiple services → suspect shared dependency (VPC, NAT, DNS, IAM)
  |  - If single service → proceed to Operation
  v
[4] OPERATION — Which API action or function is failing?
  |  - For Lambda: which function name?
  |  - For ECS: which service/task definition?
  |  - For API GW: which stage/resource/method?
  |  - If all operations → suspect service-level issue (throttling, quota)
  |  - If specific operation → proceed to Resource
  v
[5] RESOURCE — Which specific resource instance?
     - Function ARN, Task ID, DB instance identifier
     - This is your investigation target
     - Proceed to log and trace analysis scoped to this resource
共通依存関係の調査

影響範囲が複数のサービスに及ぶ場合は、次の順に調査します。

  1. VPC/ネットワーク — NAT Gateway の ErrorPortAllocation、パケットドロップ、DNS 名前解決の失敗
  2. IAM/STS — AssumeRole の ThrottlingException、トークン発行のレイテンシ
  3. 下流の依存関係 — 共通データベース、キャッシュ、または外部 API
  4. デプロイパイプライン — 同じパイプライン実行から複数のサービスに同時にデプロイされていないか
  5. AWS サービスイベント — 対象リージョンの AWS Health Dashboard と Service Health を確認します

パターン 4:PromQL 形式のメトリクスクエリパターン

これらのパターンでは、CloudWatch のメトリクス演算と GetMetricData を使用して複合シグナルを構築します。ダッシュボードまたはプログラムからの取得に使うメトリクスクエリとして表現します。

エラー率のパーセンテージ
MetricDataQueries:
  - Id: errors
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Errors
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 60
      Stat: Sum
  - Id: invocations
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Invocations
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 60
      Stat: Sum
  - Id: error_rate
    Expression: "errors / invocations * 100"
    Label: "Error Rate %"
レイテンシ異常の検出(ベースラインとの比較)
MetricDataQueries:
  - Id: current_p99
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Duration
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 300
      Stat: p99
  - Id: baseline_p99
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Duration
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 300
      Stat: p99
    # Use StartTime/EndTime set to same window last week
  - Id: anomaly_ratio
    Expression: "current_p99 / baseline_p99"
    Label: "Latency vs Baseline (ratio > 2 = anomaly)"
スロットリング圧力スコア

複数のスロットリングシグナルを、単一の圧力メトリクスにまとめます。

MetricDataQueries:
  - Id: lambda_throttles
    MetricStat:
      Metric: {Namespace: AWS/Lambda, MetricName: Throttles}
      Period: 60
      Stat: Sum
  - Id: api_gw_429s
    MetricStat:
      Metric: {Namespace: AWS/ApiGateway, MetricName: 4XXError, Dimensions: [{Name: ApiName, Value: TARGET}]}
      Period: 60
      Stat: Sum
  - Id: dynamo_throttles
    MetricStat:
      Metric: {Namespace: AWS/DynamoDB, MetricName: ThrottledRequests, Dimensions: [{Name: TableName, Value: TARGET}]}
      Period: 60
      Stat: Sum
  - Id: throttle_pressure
    Expression: "lambda_throttles + api_gw_429s + dynamo_throttles"
    Label: "Combined Throttle Pressure"
同時実行数の余裕
MetricDataQueries:
  - Id: concurrent
    MetricStat:
      Metric: {Namespace: AWS/Lambda, MetricName: ConcurrentExecutions}
      Period: 60
      Stat: Maximum
  - Id: headroom
    Expression: "1000 - concurrent"
    Label: "Remaining Concurrency (account limit 1000)"

パターン 5:インシデントタイムラインの再構築

手順

複数のソースからデータを統合して、正確なタイムラインを再構築します。

  1. タイムスタンプを収集する:
ソースクエリ得られる情報
CloudWatch AlarmsAlarm history API状態遷移時刻
CloudWatch Metrics1 分間隔の GetMetricData最初の異常発生時点
CloudWatch Logsearliest(@timestamp) を使った Logs Insights最初のエラー発生
CloudTrail時刻でフィルタリングした LookupEventsデプロイ/変更イベント
AWS HealthDescribeEventsAWS 側のインシデント
  1. タイムラインを作成する:
fields @timestamp, @message
| filter @message like /ERROR|WARN|timeout|refused|denied/
| stats earliest(@timestamp) as firstSeen, latest(@timestamp) as lastSeen, count(*) as occurrences
  by @message
| sort firstSeen asc
| limit 20
  1. 発生順序を特定する:
Timeline:
  T-15m: CloudTrail — UpdateFunctionCode by CI/CD role
  T-12m: Logs — first error "Connection refused to payments-api.internal"
  T-10m: Metrics — Error count crosses 5/min threshold
  T-8m:  Alarm — PaymentProcessorErrors enters ALARM
  T-5m:  Metrics — p99 latency spikes to 28s (timeout)
  T-0:   Current — error rate at 45%, alarm still firing
  1. 根本原因となったイベントを特定する — すべての症状に先行した最も早い変更を特定します。最初の症状からさかのぼり、直近の変更(デプロイ、設定変更、スケーリングイベント、外部依存関係の変化)を確認します。
注意事項
  • CloudWatch メトリクスのタイムスタンプは期間の終了時刻です。14:05 の1分間のデータポイントは、14:04~14:05 の期間を対象としています。
  • CloudTrail イベントの配信には、最大15分の遅延が発生する場合があります。取り込み時刻ではなく、eventTime を使用してください。
  • ロググループのタイムスタンプは、エージェント/SDK のフラッシュ間隔によって異なります。30~60秒のクロックずれを考慮してください。
  • アラーム状態の変化には、評価期間(期間 × 評価期間)に基づく組み込みの遅延があります。実際の異常は、それより前に始まっています。

コメント