NO IMAGE

CloudWatch Application Signals SLO Burn Rate Terraform 本番ガイド

NO IMAGE
目次

1. この記事について — 観測性本番運用シリーズ Vol3 完結巻

fig01: 観測性 3 層 (Logs/Traces/SLO) 統合アーキテクチャ図

1-1. 観測性 3 部作 + 9 巻シリーズの完結

本記事は「AWS 本番運用シリーズ」9 巻の完結巻です。Lambda 3 部作・EKS 3 部作を経て、観測性 3 部作の最終章として CloudWatch Application Signals + SLO を本番実装します。

観測性 3 部作の構成

テーマWP IDステータス
Vol1CloudWatch Logs Insights — ログ解析基盤2252公開済
Vol2X-Ray + ADOT — 分散トレーシング基盤2304公開済
Vol3Application Signals + SLO (本記事)2315完結巻

9 巻シリーズ全体図

Lambda 3 部作がサービス層のデプロイ・パフォーマンス・コスト最適化を担い、EKS 3 部作がコンテナ基盤のスケーリング・IAM・GitOps を担い、観測性 3 部作がシステム全体の可視化と品質保証を担います。

  • Lambda 本番運用 Vol1: コンテナイメージ + Blue/Green デプロイ
  • Lambda 本番運用 Vol2: SnapStart + Provisioned Concurrency
  • Lambda 本番運用 Vol3: Powertools + Lambda Layers + コスト最適化
  • EKS 本番運用 Vol1: Karpenter + クラスターオートスケーリング
  • EKS 本番運用 Vol2: IRSA + IAM 最小権限設計
  • EKS 本番運用 Vol3: ALB + ArgoCD GitOps
  • 観測性 Vol1: CloudWatch Logs Insights (ログ層)
  • 観測性 Vol2: X-Ray + ADOT (トレース層)
  • 観測性 Vol3: Application Signals + SLO (SLO 層) ← 本記事 (完結巻)

3 層完成の設計思想

Vol1 でログ層、Vol2 でトレース層を整備しました。本記事 Vol3 で SLO 層を追加することで、可観測性の 3 本柱「ログ・トレース・SLO」が完成します。SLO はシステムの信頼性を定量化し、「どこまで劣化を許容するか」という運用判断に根拠を与えます。Application Signals はこの SLO 管理を Lambda・ECS・EKS 横断で一元的に実現するマネージドサービスです。Vol2 で整備した ADOT Collector を再利用し、追加コストを最小化しながら SLO を本番導入します。

3 層が揃うことで「障害発生 → SLO/Burn Rate 検知 → アラート → ログ + トレースで根本原因分析」という一気通貫の観測性ループが完成します。

なぜ今 Application Signals なのか

従来の SLO 管理では独自実装のメトリクス収集・ダッシュボード・アラーム設定が必要で、設計コストの高さや属人化しやすい運用課題が長年残っていました。AWS が 2024 年に GA した Application Signals はこれらを一元化し、ADOT Collector と CloudWatch の既存インフラをそのまま活用して SLO・Error Budget・Burn Rate を自動計算します。

  • ADOT 再利用: Vol2 で構築した Collector 設定に awsapplicationsignals exporter を追加するだけで移行完了
  • Lambda/ECS/EKS 横断: 3 形態を同一の SLO コンソールで統合管理し、サービスマップで依存関係も可視化
  • Terraform ネイティブ: aws_applicationsignals_service_level_objective リソースが AWS Provider 5.x で追加され、IaC で完全管理可能
  • Error Budget 自動算出: SLO 定義後、残 Error Budget と Burn Rate を CloudWatch が自動計算。手動集計は不要

このタイミングで導入することで、Vol1 ログ・Vol2 トレースと連携した「障害発生 → SLO 違反検知 → Burn Rate アラート → PagerDuty 通知 → ログ・トレースで根本原因分析」の全自動観測性パイプラインが完成します。

1-2. 本記事のゴール

本記事を完了すると、以下の成果物が手元に揃います。

  • SLO 3 種の Terraform 定義と稼働確認: Availability SLO (99.9%) / Latency SLO (p99 < 500ms) / Error Rate SLO (< 0.1%) を aws_applicationsignals_service_level_objective で定義
  • Burn Rate 2-window アラート: Fast window (1 時間) + Slow window (6 時間) の二段階検知で誤報を抑制しながら早期検知を実現
  • Synthetic Canary 外形監視: 5 分間隔の外形テストで SLO 計測の盲点 (内部メトリクスが正常でも外部から到達不可の状態) を補完
  • Real User Monitoring (RUM): エンドユーザー体験を SLI として取り込み、SLO の完全性を向上
  • PagerDuty / OpsGenie 自動エスカレーション: Burn Rate 超過を SNS → Lambda → Webhook で自動連携し、夜間の手動確認を不要化

これらはすべて Terraform IaC で管理されており、git 管理・CI/CD パイプラインへの統合が可能です。また Vol1 のログ・Vol2 のトレースと組み合わせることで、SLO 違反発生時に CloudWatch Logs Insights でエラーログを検索し、X-Ray トレースで障害箇所を特定する完全な調査フローが整います。

Vol1 / Vol2 との連携ポイント

本記事の成果物は観測性 3 部作の前 2 巻と直接連携します。

本記事の実装Vol1 (Logs) との連携Vol2 (Traces) との連携
SLO 違反検知Logs Insights でエラーログを検索し根本原因を特定X-Ray トレースで障害サービスと遅延箇所を特定
Burn Rate アラームLambda escalator のログを Logs Insights で監視Canary の active_tracing で X-Ray に記録
RUM エラーJavaScript エラーを CloudWatch Logs に転送RUM enableXRay で API 呼び出しトレースと連携

3 部作を通じて「ログ → トレース → SLO」の完全な可観測性スタックが完成します。Vol1・Vol2 未読の場合は §1-5 のシリーズナビからご参照ください。

1-3. 読者像

パターン 1: Lambda SRE

Lambda で外部 API・DynamoDB を呼ぶサービスの可用性を SLO で管理したい。CloudWatch Alarms は設定済みだが、Error Budget の概念を本番運用に取り込めていない。SLO 違反が発生したとき、どこまでバジェットが残っているかを定量的に把握し、リリースペースの調整判断に使いたい。

本記事では Lambda に ADOT Layer を追加して Application Signals を有効化し、Availability SLO と Error Rate SLO を Terraform で定義する手順を解説します。Burn Rate 2-window アラートと PagerDuty 連携まで一気通貫で実装できます。

パターン 2: ECS マイクロサービス運用者

ECS 上の 5〜6 サービスで応答遅延が増加しているが、SLO がないため「どこまで劣化を許容するか」の基準がない。Burn Rate でアラート閾値を設計し、PagerDuty 連携を整備して夜間の呼び出し件数を最適化したい。

本記事では ECS サイドカー ADOT Collector の設定変更から Application Signals 有効化、Latency SLO 定義、Burn Rate アラームまでを Terraform で管理する方法を解説します。複数サービスを SLO コンソールで一元管理する方法も紹介します。

パターン 3: EKS Platform Engineer

Vol1 (Logs) + Vol2 (Traces) は整備済み。最後の層として SLO Dashboard と Error Budget Tracking を実装したい。既存の ADOT Collector を再利用し、追加インフラを最小化した Application Signals 統合を実現したい。

本記事では amazon-cloudwatch-observability EKS Add-on による ADOT + Application Signals の自動設定から Terraform IRSA 設定まで解説します。Namespace への自動計装注入により、アプリコードを変更せずに SLO 計測が開始されます。

1-4. 本記事の構成早見表

テーマポイント
§3Application Signals vs CloudWatch Metrics 採用判断 + SLO 概念整理brc-red: 採用判断基準を明示
§4ADOT + Application Signals Terraform 統合 (Lambda/ECS/EKS)brc-red: 横断実装パターン
§5SLO 3 種 + Error Budget + Burn Rate 2-windowError Budget 自動計算ロジック
§6Synthetic Canary + RUM + SLO 統合監視外形監視 × 実ユーザー体験
§7Burn Rate → PagerDuty/OpsGenie 自動エスカレーション + コスト最適化夜間アラート最適化
§8まとめ + 観測性 3 部作完結 + 9 巻シリーズ完結告知全体総括

§3・§4 は「何を選ぶか・なぜ選ぶか」の意思決定層で、既存システムに Application Signals を導入すべきか判断する読者に特に有用です。§5〜§7 は「どう実装するか」の実践層で、Terraform コードをそのまま活用できます。§8 は 9 巻シリーズ全体の総括として、次のステップを示します。

1-5. シリーズナビ

Vol2 未読の場合は、ADOT Collector の基礎設定と X-Ray トレーシングの概念を先に把握しておくと本記事の §4 をスムーズに読み進められます。

前提を読む: 観測性Vol2 X-Ray + ADOT 分散トレーシング基盤


2. 前提・環境・準備

fig02: SLI / SLO / Error Budget / Burn Rate 概念フロー

2-0. SLI / SLO / Error Budget / Burn Rate の概念整理

本記事を読む前に、4 つの基本概念を押さえておきましょう。

用語定義
SLI (Service Level Indicator)サービス品質を測定する指標 (計測値)成功リクエスト率 99.95%
SLO (Service Level Objective)SLI の目標値成功率 >= 99.9% (30日間)
Error BudgetSLO を下回ることが許容される量 (= 100% – SLO目標)0.1% = 月間 43.2 分のダウンタイム
Burn RateError Budget が消費される速さ (1× = SLO期間ちょうどで使い切る速度)14× = 1h で Error Budget の 2% を消費

Burn Rate が重要なのは「今の障害が続くとあと何時間で Error Budget を使い切るか」を定量化できるためです。Burn Rate 1× 未満なら問題なし。Burn Rate 14× 以上は「今すぐ対処しないと SLO 違反」のシグナルです。

2-1. 前提環境

本記事では以下の環境が整備済みであることを前提とします。

  • 観測性 Vol1 完了: CloudWatch Logs Insights によるログ解析基盤が稼働中
  • 観測性 Vol2 完了: X-Ray + ADOT 分散トレーシング基盤が稼働中 (ADOT Collector 稼働中)
  • AWS CLI v2.x: aws --version で v2.x 以上であることを確認
  • Terraform >= 1.7: terraform version で 1.7 以上であることを確認
  • 対応リージョン: Application Signals 対応リージョン (us-east-1 / ap-northeast-1 / eu-west-1 等)
  • IAM 権限: application-signals:* / cloudwatch:PutMetricAlarm / synthetics:* / rum:*
  • 稼働中ワークロード: Lambda / ECS / EKS のいずれか (Vol2 で ADOT 計装済み)

Application Signals は ADOT Collector が収集したメトリクスを入力として動作します。Vol2 で整備した Collector 設定をそのまま再利用するため、追加の計装コードは不要です。

前提環境の確認コマンド:

# AWS CLI バージョン確認
aws --version

# Terraform バージョン確認
terraform version

# Application Signals 対応リージョン確認 (ap-northeast-1 で例示)
aws application-signals list-services \
  --start-time $(date -d '1 hour ago' +%s 2>/dev/null || date -v-1H +%s) \
  --end-time $(date +%s) \
  --region ap-northeast-1 2>&1 | head -5

# ADOT Collector 稼働確認 (ECS の場合)
aws ecs list-tasks --cluster my-cluster --region ap-northeast-1

2-2. 使用技術スタック

サービス / ツールバージョン用途
CloudWatch Application SignalsGA (2024-)SLO 定義 + Error Budget + Burn Rate 算出
ADOT Collector (Vol2 成果)v0.39+Application Signals メトリクス送出
aws_applicationsignals_service_level_objectiveAWS Provider >= 5.xSLO Terraform リソース
aws_synthetics_canaryAWS Provider >= 3.xSynthetic Canary (外形監視)
aws_rum_app_monitorAWS Provider >= 4.xReal User Monitoring
aws_cloudwatch_metric_alarmAWS Provider >= 3.xBurn Rate Fast/Slow アラーム
aws_sns_topic / aws_lambda_functionAWS Provider >= 3.xPagerDuty / OpsGenie 連携
Terraform>= 1.7IaC 管理

2-3. Terraform 主要リソース一覧

本記事で定義する Terraform リソースの全体像です。

Terraform リソース役割
aws_applicationsignals_service_level_objectiveSLO 3 種 (Availability / Latency / Error Rate) 定義
aws_cloudwatch_metric_alarmBurn Rate Fast window (1h) + Slow window (6h) アラーム
aws_synthetics_canary5 分間隔外形監視 Canary
aws_rum_app_monitorReal User Monitoring AppMonitor
aws_sns_topicBurn Rate アラーム通知先 SNS
aws_lambda_functionPagerDuty / OpsGenie Webhook 中継 Lambda
aws_iam_roleCanary / RUM / Lambda 実行ロール

2-4. 今回のゴール状態定義

本記事の完了時点で、以下の状態が AWS マネジメントコンソールおよび terraform state で確認できることをゴールとします。

  • SLO 3 種: Availability / Latency / Error Rate の SLO が Application Signals コンソールに表示され、Error Budget が緑 (残あり) であること
  • Burn Rate アラーム: CloudWatch Alarms で Fast window / Slow window の 2 アラームが OK 状態で稼働していること
  • Synthetic Canary: Synthetics コンソールで 5 分間隔の Canary が Passed を返していること
  • RUM AppMonitor: CloudWatch RUM コンソールで AppMonitor が稼働し、ページビューデータが収集されていること

確認コマンドチートシート:

# SLO 稼働確認
aws application-signals list-service-level-objectives --region ap-northeast-1

# Error Budget レポート
aws application-signals batch-get-service-level-objective-budget-report \
  --timestamp $(date +%s) \
  --slo-ids '["my-service-availability-slo"]' \
  --region ap-northeast-1

# Canary ステータス確認
aws synthetics get-canary --name my-service-api-health --region ap-northeast-1

# RUM AppMonitor 確認
aws rum get-app-monitor --name my-app-rum --region ap-northeast-1

3. Application Signals vs CloudWatch Metrics 採用判断 + SLO 概念整理

3-1. CloudWatch Application Signals とは

CloudWatch Application Signals は 2024 年に GA となった AWS ネイティブの APM (Application Performance Monitoring) 機能だ。従来の CloudWatch でサービス品質を監視するには、カスタムメトリクスを手動定義し、X-Ray でトレースを収集し、SLO は自前スクリプトで計算するという分散した作業が必要だった。Application Signals はこれらを「サービス」単位で自動集約し、SLO / Error Budget / Burn Rate を AWS マネジメントコンソールと API で一元管理できる環境を提供する。

Application Signals の核心は OpenTelemetry (ADOT) との統合にある。ADOT Collector が送出するメトリクス・トレース・ログを受け取り、サービスマップとして可視化する。ユーザーは ADOT の設定に awsapplicationsignals エクスポーターを追加するだけで、追加のコード変更なしに Application Signals のすべての機能を利用できる。

対応プラットフォームと計装方式:

プラットフォーム計装方式備考
AWS LambdaADOT Lambda Layer 追加のみLambda Insights は不要になる場合あり
Amazon ECSADOT サイドカーコンテナタスク定義に ADOT コンテナを追加
Amazon EKSADOT Operator + Auto-instrumentationK8s アノテーションで自動計装
Amazon EC2CloudWatch Agent + ADOT Collectorエージェントを EC2 にインストール

Auto-instrumentation が特に強力なのは EKS だ。Pod に instrumentation.opentelemetry.io/inject-java: "true" などのアノテーションを付けるだけで、JVM エージェントが自動挿入される。コードの変更なしにトレース・メトリクスの収集が始まり、Java・Python・Node.js・.NET がサポートされている。

Vol2 で構築した ADOT Collector は Application Signals のデータソースとして そのまま流用できる。Vol2 の Collector 設定に awsapplicationsignals エクスポーターを追加し、パイプラインにバインドするだけで統合が完了する。具体的な Terraform コードと ADOT 設定は §4 で示す。

Application Signals が提供するダッシュボードでは、サービス間の依存関係を自動生成されたサービスマップで可視化できる。上流・下流のサービスにまたがる SLO 達成状況と Error Budget 消費量を一覧で確認でき、インシデント発生時の影響範囲特定が大幅に効率化される。Burn Rate アラームは CloudWatch Alarms と連携しており、PagerDuty・Slack・SNS への通知も標準的に設定可能だ。

Application Signals のサービス検出はリアルタイムで行われる。ADOT Collector が正しく設定されていれば、アプリケーションへのリクエストが発生した時点で AWS コンソールの「Application Signals → サービスマップ」に新しいノードが追加される。初期設定から動作確認まで、コンソールでの視覚的確認は 5 分以内に完了できる。

Application Signals では、サービス名は ADOT の OTEL_SERVICE_NAME 環境変数で制御される。Lambda では AWS_LAMBDA_FUNCTION_NAME が自動的に使われる。ECS / EKS では OTEL_SERVICE_NAME=my-service を明示的に設定することを推奨する。サービス名が統一されていると、サービスマップでの依存関係グラフと SLO ダッシュボードが自動的に関連付けられる。

OTEL_SERVICE_NAME の命名規則はチーム内で統一しておくことが重要だ。例えば {チーム名}-{機能名} (例: auth-login-api) のような形式にすると、サービスマップのノード数が増えた場合でも構造が把握しやすい。名前を後から変更すると SLO の履歴データとの連続性が失われるため、初期設定時に慎重に決定することを強く推奨する。


3-2. Application Signals vs CloudWatch Metrics 採用判断マトリクス

Application Signals と CloudWatch Metrics の両者は「メトリクスを収集・可視化する」機能を持つが、提供する価値・適用場面が明確に異なる。以下の 5 軸で比較し、どちらを採用すべきかの判断基準を整理する。CloudWatch Metrics は「プッシュ型の汎用メトリクス基盤」であり、Application Signals は「OTel ネイティブの SLO 管理層」として位置づけると理解しやすい。

比較軸CloudWatch MetricsApplication Signals
自動計装手動メトリクス定義必須ADOT + 自動計装で即時利用可
SLO ネイティブ自前で Error Budget 計算要SLO / Error Budget / Burn Rate をコンソールで管理
OTel 互換独自 PutMetricData APIOpenTelemetry Protocol (OTLP) 準拠
Lambda 対応カスタムメトリクス + Lambda InsightsADOT Lambda Layer 追加のみで直結
コストメトリクス数 × $0.30/万件Application Signals メトリクス料金 + 既存 CloudWatch 料金に上乗せ

使い分けの原則:

  • SLO 管理が必要なシステム → Application Signals 一択。Error Budget と Burn Rate の計算を自前実装する必要がなくなり、SLO 設定から数分でアラームまで構成できる。
  • OTel (ADOT) 計装済みの環境 → Application Signals への移行コストはほぼゼロ。既存の ADOT Collector 設定にエクスポーターを追加するだけで全機能が利用可能になる。
  • Lambda 単独の簡易監視 → CloudWatch Metrics + Lambda Insights でも十分。SLO 管理が不要で単一 Lambda の基本的な監視に留まる場合は、Application Signals の追加コストを投じるメリットが薄い。
  • マルチサービス依存関係の可視化が必要 → Application Signals が圧倒的に優位。サービスマップで自動生成された依存グラフを確認でき、連鎖障害の根本原因特定が高速化される。
【Application Signals vs CloudWatch Metrics 採用判断マトリクス】

  • SLO管理が必要 → Application Signals 一択(Error Budget / Burn Rate をコンソールで即管理)
  • OTel (ADOT) 計装済み → Application Signals に即切替可能(エクスポーター追加のみ)
  • Lambda 単独の簡易監視 → CloudWatch Metrics でも可(導入コスト vs 機能のトレードオフ)
  • マルチサービス SLO 統合 → Application Signals(サービスマップ + SLO ダッシュボード)
  • コスト: Application Signals は CloudWatch Metrics 料金 + SLO 評価料金(詳細は §7)

コスト面では、Application Signals は通常の CloudWatch メトリクス料金に加え、SLO 評価ごとの追加料金が発生する。月次コストの具体的な試算と最適化手法は §7 のコスト最適化セクションで詳しく解説する。


3-3. SLI / SLO / Error Budget / Burn Rate 用語整理

SRE (Site Reliability Engineering) の文脈で頻出するこれらの概念を、Application Signals の機能と対応づけながら整理する。各用語の数学的定義と実務での使い方を押さえることで、§5 の SLO 設定作業がスムーズになる。

SLI (Service Level Indicator)

サービスの品質を定量化した指標。Application Signals では以下の 3 種類の SLI を標準で計測する。

  • 可用性 (Availability SLI): 計測期間内の成功リクエスト率。計算式: (成功リクエスト数 ÷ 総リクエスト数) × 100。HTTP 2xx/3xx を成功、5xx をエラーとしてカウントする。
  • レイテンシ (Latency SLI): リクエストの応答時間パーセンタイル。P50 / P90 / P99 / P99.9 を選択可能。P99 は「100 リクエスト中 99 件がこの時間以内に完了している」ことを意味する。
  • エラー率 (Error Rate SLI): HTTP 5xx またはアプリケーション定義のエラーコードの割合。可用性 SLI の補集合として利用できる。

Application Signals では SLI の計測粒度は 1 分 (60 秒) ごとだ。1 分ウィンドウでのメトリクス集計が SLO 達成率の計算に使われるため、一瞬のスパイクよりも継続的なエラーが SLO に大きく影響する。カスタム SLI (アプリケーション定義のメトリクス) を使いたい場合は metric_source_configMonitoredRequestCount ではなく Metric Math 式を指定できる (詳細は §5)。

SLO (Service Level Objective)

SLI に対して組織が設定する目標値。Application Signals の SLO 設定画面では、SLI の種類・集計ウィンドウ (7 日 / 30 日 / カレンダー月) ・目標値 (%) を指定する。

典型的な SLO 設定例:

SLO 種類目標値実務での解釈
Availability99.9%月間 43.2 分のダウンタイムが許容範囲
Availability99.99%月間 4.32 分のダウンタイムが許容範囲
Latency P9999% が 200ms 以内100 リクエスト中 99 件が 200ms 以内
Latency P99.999.9% が 1000ms 以内1000 リクエスト中 999 件が 1 秒以内

SLO の目標値は高いほど良いわけではない。99.999% を目標にすると Error Budget が月間 26 秒しかなく、わずかなインフラ作業でも Error Budget を使い果たす。サービスの重要度とチームの運用コストを勘案して現実的な目標値を設定することが SRE の実践では重要だ。

集計ウィンドウには ローリング (Rolling)カレンダー (Calendar) の 2 種類がある。Rolling 30 日は常に「直近 30 日」で計算するためリアルタイム性が高い。Calendar Month は「月初〜月末」でリセットされるため、月末で Error Budget が回復するという心理的効果がある。Application Signals のデフォルト設定は Rolling 30 日であり、SRE のベストプラクティスに合致する。

カレンダー月を選ぶ場合、月末でリセットされる直前へリリース作業を集中させるインセンティブを生まないよう注意したい。

Error Budget

SLO 達成のために許容できる「失敗の予算」。SLO を 99.9% に設定した場合、Error Budget は 100% - 99.9% = 0.1% となる。

具体的な計算例 (30 日 / 月次集計の場合):

SLOError Budget (%)月次許容ダウンタイム月次許容エラー数 (100万req/月)
99.9%0.1%43.2 分1,000 件
99.5%0.5%216 分5,000 件
99.99%0.01%4.32 分100 件

Application Signals の「Error Budget」パネルでは、残余予算をパーセンテージとしてリアルタイム表示する。予算が 0% に近づくと Burn Rate アラームがトリガーされ、デプロイ凍結や緊急対応を促す仕組みだ。

Burn Rate

Error Budget の消費速度を表す指標。Burn Rate = 1.0 は「ちょうど SLO 集計期間中に Error Budget を使い切るペース」を意味する。

Burn Rate消費ペース区分推奨アクション
< 1.0予算内消費正常問題なし・定期確認継続
1.0 ~ 2.0わずかに超過要監視傾向監視・次スプリントで対処
> 6x (6h 計測)Slow Burn 検知Slow BurnP2 アラート・予防的調査
> 14x (1h 計測)Fast Burn 検知Fast BurnP1 緊急インシデント・即時対応

Fast Burn Rate (14x / 1 時間) は「このペースが 1 時間続くと Error Budget が枯渇する」状況を検知する。Slow Burn Rate (6x / 6 時間) は「緩やかに消費が進んでいるが、週次でみると予算超過ペース」という状況を早期に捉える。Application Signals では両方のアラームを CloudWatch Alarms 経由で PagerDuty・SNS に通知できる (詳細は §7)。

Burn Rate の具体的な計算例: SLO = 99.9% (30 日間)、月間リクエスト数 = 1,000 万件のシステムを想定する。

  • Error Budget = 1,000 万 × 0.1% = 10,000 件 のエラーが月間許容予算
  • Fast Burn (14x / 1h): 1 時間で 10,000 × 2% = 200 件消費ペース → 緊急インシデント
  • Slow Burn (6x / 6h): 6 時間で 10,000 × 5% = 500 件消費ペース → 予防的対応
  • 通常ペース (1x): 月間 10,000 件 ÷ 720 時間 = 約 14 件/時間が正常消費レート

Google SRE の書籍が提唱する 2-window Burn Rate アラーム設計は、Application Signals の Burn Rate アラームに直接適用できる。Fast Burn (1h × 14×) と Slow Burn (6h × 6×) の 2 ウィンドウを組み合わせることで、急激な障害 (分単位) と緩やかな品質劣化 (時間単位) の両方を早期検知できる。2 ウィンドウを採用することで単一ウィンドウと比較してアラートの偽陽性が大幅に減少する。具体的な CloudWatch Alarm Terraform 実装は §5-6 で詳述する。


fig02: SLI / SLO / Error Budget / Burn Rate 概念フロー

sequenceDiagram
 participant C as クライアント
 participant S as アプリサービス
 participant AS as Application Signals
 participant SLO as SLO Engine
 participant CW as CloudWatch Alarms
 participant PD as PagerDuty

 C->>S: リクエスト
 S->>AS: ADOT Collector 経由でメトリクス送出
 AS->>AS: SLI 計測 (SuccessRate / Latency / ErrorRatio)
 AS->>SLO: SLI 値報告
 SLO->>SLO: SLO 達成率算出 (99.9% 目標)
 SLO->>SLO: Error Budget 消費量計算
 alt Burn Rate > 14x (Fast Burn 1h)
  SLO->>CW: BurnRateAlarm 発火 (Critical)
  CW->>PD: P1 インシデント作成
 else Burn Rate > 6x (Slow Burn 6h)
  SLO->>CW: BurnRateAlarm 発火 (Warning)
  CW->>PD: P2 インシデント作成
 end

3-5. Application Signals の有効化方法

Application Signals を有効化するには、コンソール・AWS CLI・Terraform の 3 通りのアプローチがある。初回有効化はコンソールで確認しながら進め、本番環境の再現性確保には Terraform での管理を推奨する。

コンソール操作:

  1. AWS マネジメントコンソール → CloudWatch を開く
  2. 左ナビゲーション → Application Signalsサービス を選択
  3. 「Start Discovering Services」ボタンをクリック (初回のみ)
  4. 対象リージョン (例: ap-northeast-1) でサービスの自動検出が開始される
  5. ADOT が送出しているサービス名がサービスマップに表示されたら有効化完了

AWS CLI による確認コマンド:

# Application Signals サービス一覧確認 (過去1時間)
aws application-signals list-services \
  --start-time $(date -v-1H +%s) \
  --end-time $(date +%s) \
  --region ap-northeast-1
# SLO 一覧の確認
aws application-signals list-service-level-objectives \
  --region ap-northeast-1 \
  --output table
# 特定 SLO の Error Budget レポート取得
aws application-signals get-service-level-objective \
  --id <SLO_ID> \
  --region ap-northeast-1

Terraform による有効化:

Application Signals の有効化自体はリージョン単位の AWS 側設定であり、Terraform では aws_applicationsignals_service_level_objective リソースで SLO を定義する。ADOT Collector 設定 (awsapplicationsignals エクスポーター) の Terraform 実装は §4 で詳述する。Burn Rate アラームの Terraform 定義は §7 で扱う。

Application Signals を有効化したあと、最初に確認すべきは aws application-signals list-services の出力だ。ここに自分のサービス名が表示されればデータパスが正常に接続されている。表示されない場合は IAM 権限 (application-signals:PutServiceData) または ADOT Collector の awsapplicationsignals エクスポーター設定を見直す。


3-6. 観測性シリーズ 関連記事

本記事は観測性本番運用シリーズの Vol3 完結巻として位置づけられ、Vol1・Vol2 で構築した技術スタックの上位レイヤーを担う。

Vol2 で構築した ADOT Collector の設定に awsapplicationsignals エクスポーターを追加することで、追加のコード変更なしに Application Signals との連携が完成する。観測性の 3 層構造 (ログ → トレース → SLO) が完全に統合される仕組みは §4 で図解する。

3 部作を通じた観測性成熟度の高まりを整理すると: Vol1 (ログ層) でインフラの状態を把握し、Vol2 (トレース層) でサービス間の依存関係と処理フローを可視化し、Vol3 (SLO 層・本記事) でエンドユーザー体験の品質目標を定量管理する。各層が独立して動作しながらも相互に参照できることが、このシリーズの設計思想の核心だ。


4. ADOT + Application Signals 統合 Terraform 完全実装 — Lambda / ECS / EKS 3 形態

4-1. Vol2 ADOT Collector → Application Signals への切替ポイント

観測性 Vol2 で構築した ADOT Collector 環境は、awsapplicationsignals exporter を追加するだけで Application Signals へメトリクスを送出できる。
既存の awsxray exporter と並行運用が可能なため、トレースを継続しながら SLO 機能を段階的に追加できる。

exporters:
  awsapplicationsignals:
 region: ap-northeast-1
service:
  pipelines:
 metrics:
receivers: [otlp]
processors: [memory_limiter, batch, awsapplicationsignals]
exporters: [awsapplicationsignals]
 traces:
receivers: [otlp]
exporters: [awsxray]

Vol2 の ADOT Collector config に awsapplicationsignals exporter と metrics pipeline を追記するだけで移行が完了する。
traces pipeline は既存のまま維持するため、X-Ray トレースへの影響はない。

fig03: ADOT Collector → Application Signals 統合構成図 (Lambda / ECS / EKS 3形態)


4-2. Lambda: ADOT Layer + Application Signals 自動計装

Lambda では、Application Signals 対応の ADOT Lambda Layer を追加し、環境変数 2 つを設定するだけで自動計装が有効になる。
ランタイムコードの変更は不要であり、既存の Lambda Powertools Tracer と共存できる。

Layer ARN (Python / amd64 / ap-northeast-1):
arn:aws:lambda:ap-northeast-1:901920570463:layer:aws-otel-python-amd64-ver-1-21-0:1
最新 ARN は AWS ADOT Lambda Layer ドキュメント を参照すること。

Terraform 実装:

resource "aws_lambda_function" "my_service" {
  function_name = "my-service"
  runtime = "python3.12"
  handler = "app.handler"
  filename= "lambda.zip"
  role = aws_iam_role.lambda_role.arn

  # ADOT Lambda Layer (Application Signals 対応版)
  layers = [
 "arn:aws:lambda:ap-northeast-1:901920570463:layer:aws-otel-python-amd64-ver-1-21-0:1"
  ]

  environment {
 variables = {
AWS_LAMBDA_EXEC_WRAPPER= "/opt/otel-instrument"
OTEL_AWS_APPLICATION_SIGNALS_ENABLED  = "true"
OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT = "http://localhost:4316/v1/metrics"
OTEL_EXPORTER_OTLP_PROTOCOL  = "http/protobuf"
OTEL_PROPAGATORS = "tracecontext,baggage,xray"
 }
  }
}

resource "aws_iam_role_policy" "lambda_application_signals" {
  role = aws_iam_role.lambda_role.id
  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Action = [
  "application-signals:PutServiceData",
  "xray:PutTraceSegments",
  "xray:PutTelemetryRecords",
  "xray:GetSamplingRules",
  "xray:GetSamplingTargets",
  "cloudwatch:PutMetricData"
]
Resource = "*"
 }]
  })
}

動作確認 (AWS CLI):

aws application-signals list-services \
  --start-time $(date -d '10 minutes ago' +%s) \
  --end-time $(date +%s) \
  --region ap-northeast-1

Lambda に対して数回リクエストを送った後、上記コマンドでサービスが検出されれば計装成功。
CloudWatch コンソール → Application Signals → サービスマップ でも視覚的に確認できる。


4-3. ECS: ADOT Collector サイドカー + Application Signals 設定

ECS Fargate では、ADOT Collector をサイドカーコンテナとしてタスク定義に追加する。
アプリコンテナは localhost:4317 (OTLP gRPC) に送出するだけでよく、コード変更は最小限に抑えられる。
ADOT Collector の設定は SSM Parameter Store に保存し、タスク定義の secrets 経由で渡す方式が推奨される。

Terraform 実装:

resource "aws_ssm_parameter" "adot_config" {
  name  = "/myapp/adot/config"
  type  = "String"
  value = yamlencode({
 exporters = {
awsapplicationsignals = { region = "ap-northeast-1" }
awsxray= { region = "ap-northeast-1" }
 }
 service = {
pipelines = {
  metrics = {
 receivers  = ["otlp"]
 processors = ["memory_limiter", "batch", "awsapplicationsignals"]
 exporters  = ["awsapplicationsignals"]
  }
  traces = {
 receivers = ["otlp"]
 exporters = ["awsxray"]
  }
}
 }
  })
}

resource "aws_ecs_task_definition" "my_service" {
  family = "my-service"
  requires_compatibilities = ["FARGATE"]
  network_mode = "awsvpc"
  cpu = 512
  memory = 1024
  execution_role_arn = aws_iam_role.ecs_execution_role.arn
  task_role_arn= aws_iam_role.ecs_task_role.arn

  container_definitions = jsonencode([
 {
name  = "app"
image = "my-app:latest"
environment = [
  { name = "OTEL_EXPORTER_OTLP_ENDPOINT", value = "http://localhost:4317" },
  { name = "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", value = "true" },
  { name = "OTEL_PROPAGATORS", value = "tracecontext,baggage,xray" }
]
portMappings = [{ containerPort = 8080, protocol = "tcp" }]
 },
 {
name = "adot-collector"
image= "public.ecr.aws/aws-observability/aws-otel-collector:latest"
command = ["--config=/etc/otel/config.yaml"]
portMappings = [
  { containerPort = 4317, protocol = "tcp" },
  { containerPort = 4316, protocol = "tcp" }
]
secrets = [{
  name= "AOT_CONFIG_CONTENT"
  valueFrom = aws_ssm_parameter.adot_config.arn
}]
 }
  ])
}

resource "aws_iam_role_policy" "ecs_application_signals" {
  role = aws_iam_role.ecs_task_role.id
  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Action = [
  "application-signals:PutServiceData",
  "xray:PutTraceSegments",
  "xray:PutTelemetryRecords",
  "xray:GetSamplingRules",
  "xray:GetSamplingTargets",
  "cloudwatch:PutMetricData"
]
Resource = "*"
 }]
  })
}

コンソール確認手順:
ECS コンソール → クラスター → タスク → コンテナタブで adot-collector の稼働を確認後、
CloudWatch → Application Signals → サービスマップ に my-service が出現することを確認する。


4-4. EKS: ADOT Operator + Amazon CloudWatch Observability Add-on

EKS では amazon-cloudwatch-observability Add-on を有効化するだけで、ADOT Collector DaemonSet と Application Signals の自動設定が完了する。
Operator が Pod への自動計装用 Init Container を注入するため、アプリコードへの変更は不要。

Terraform 実装:

resource "aws_eks_addon" "cloudwatch_observability" {
  cluster_name  = aws_eks_cluster.main.name
  addon_name = "amazon-cloudwatch-observability"
  addon_version = "v2.1.0-eksbuild.1"

  configuration_values = jsonencode({
 agent = {
config = {
  logs = {
 metrics_collected = {
application_signals = {}
 }
  }
}
 }
  })

  depends_on = [aws_eks_node_group.main]
}

# IRSA for CloudWatch Agent (Application Signals)
module "irsa_cloudwatch" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "~> 5.0"

  role_name= "cloudwatch-agent-${aws_eks_cluster.main.name}"
  attach_cloudwatch_observability_policy = true

  oidc_providers = {
 main = {
provider_arn= aws_iam_openid_connect_provider.main.arn
namespace_service_accounts = ["amazon-cloudwatch:cloudwatch-agent"]
 }
  }
}

resource "aws_iam_role_policy_attachment" "cloudwatch_agent" {
  role = module.irsa_cloudwatch.iam_role_name
  policy_arn = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
}

動作確認 (kubectl):

# Add-on と Agent の稼働確認
aws eks list-addons --cluster-name my-cluster --region ap-northeast-1
kubectl get pods -n amazon-cloudwatch

# Application Signals 対応 Namespace のアノテーション確認
kubectl get namespace my-app -o yaml | grep instrumentation

Namespace へ instrumentation.opentelemetry.io/inject-python: "true" (ランタイムに応じたキー) を付与すると、
Pod 起動時に ADOT Init Container が自動注入され、Application Signals へのメトリクス送出が開始される。


4-5. IAM 権限設定 — 全形態共通

Lambda 実行ロール・ECS タスクロール・EKS IRSA ServiceAccount のいずれも、以下の IAM アクションが必要。
application-signals:PutServiceData が不足すると、サービスは起動していてもメトリクスが Application Signals コンソールに表示されない。
権限エラーは CloudTrail → イベント履歴 → ErrorCode: AccessDenied で即時確認できる。

resource "aws_iam_role_policy" "application_signals_common" {
  role = var.role_id
  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Action = [
  "application-signals:PutServiceData",
  "application-signals:GetService",
  "application-signals:ListServices",
  "cloudwatch:PutMetricData",
  "xray:PutTraceSegments",
  "xray:PutTelemetryRecords",
  "xray:GetSamplingRules",
  "xray:GetSamplingTargets"
]
Resource = "*"
 }]
  })
}

【ADOT + Application Signals 統合 Terraform 必須チェックリスト】

  • Lambda 形態:
    • ADOT Lambda Layer (Application Signals 対応版) 追加済み
    • OTEL_AWS_APPLICATION_SIGNALS_ENABLED=true 環境変数設定済み
    • AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument 設定済み
    • application-signals:PutServiceData IAM 権限付与済み
  • ECS 形態:
    • adot-collector サイドカーコンテナ追加済み (ポート 4317/4316)
    • ADOT Collector config に awsapplicationsignals exporter 設定済み
    • タスクロールに CloudWatchAgentServerPolicy 相当の権限付与済み
  • EKS 形態:
    • amazon-cloudwatch-observability Add-on 有効化済み
    • IRSA で CloudWatchAgentServerPolicy 割当て済み
    • kubectl get pods -n amazon-cloudwatch で Agent 稼働確認済み
  • 共通:
    • application-signals list-services でサービス検出確認済み
    • CloudWatch → Application Signals でサービスマップ表示確認済み

関連記事:
観測性 Vol2 — X-Ray + ADOT 分散トレーシング本番運用 — ADOT Collector 構成の前提
Lambda Vol1 — Lambda コンテナイメージ本番運用 — Lambda 計装の前提
Lambda Vol3 — Powertools + Layers 本番運用 — Powertools Tracer × Application Signals 連携
EKS Vol2 — IRSA 本番運用 — IRSA 設定参照
EKS Vol3 — ALB + Argo CD 本番運用 — Argo CD GitOps 管理


5. SLO 3 種 Terraform 実装 + Error Budget + Burn Rate 2-window アラート設計

5-1. SLO 種別の選択指針

Application Signals がネイティブサポートする SLO は 3 種類あり、監視したい品質指標によって使い分ける。

Availability SLO は成功リクエスト率を基準とした可用性指標です。SLI は SuccessCount / RequestCount × 100 で計算し、99.9% を目標に設定すると月間ダウンタイム許容は 43.2 分となります。API エンドポイントや重要なサービス呼び出しの可用性を継続的に追跡する用途に最適です。

Latency SLO はレスポンスタイムを基準とした応答速度指標です。SLI は「P99 レイテンシが 500ms 以下のリクエスト率」として計測し、95% のリクエストが閾値以内に収まることを目標とします。ユーザー体験に直結するエンドポイントのパフォーマンス劣化を早期検知する用途に適しています。

Error Rate SLO はエラー率を基準とした信頼性指標です。SLI は ErrorCount / RequestCount × 100 が 0.1% 以下であることを計測します。バックグラウンドジョブや非同期処理など、応答速度より信頼性を重視するコンポーネントに向いています。

SLO 種別SLI 計算式目標値例月間許容適用シナリオ
AvailabilitySuccessCount / RequestCount99.9%ダウンタイム 43.2 分API 可用性・依存サービス呼び出し
LatencyP99 <= 閾値のリクエスト率95.0%36 時間分の遅延リクエストユーザー向けエンドポイント
Error Rate(1 – ErrorCount / RequestCount)99.9%エラー 43.2 分相当バッチ処理・非同期ジョブ

5-2. SLO 判断フロー図 + Burn Rate 設計

fig04: SLO 3 種比較 + Burn Rate 2-window 判断フロー

flowchart TD
 A[SLO 種別を選択] --> B{測定したい品質は?}
 B -- 可用性・成功率 --> C[Availability SLO\nSuccessCount/RequestCount]
 B -- 応答速度 --> D[Latency SLO\nP99 <= 閾値のリクエスト率]
 B -- エラー率 --> E[Error Rate SLO\nErrorCount/RequestCount <= 閾値]
 C & D & E --> F{Burn Rate 設計}
 F --> G[Fast Burn: 1h ウィンドウ\n消費速度 14× でアラート\n= Error Budget の 2% を 1h で消費]
 F --> H[Slow Burn: 6h ウィンドウ\n消費速度 6× でアラート\n= Error Budget の 5% を 6h で消費]
 G --> I[CloudWatch Alarm → SNS → PagerDuty P1]
 H --> J[CloudWatch Alarm → SNS → PagerDuty P2]

5-3. Availability SLO Terraform 実装

resource "aws_applicationsignals_service_level_objective" "availability" {
  name = "my-service-availability-slo"

  sli {
 sli_metric {
metric_source_config {
  type = "RequestBasedSli"
  request_based_sli_config {
 request_based_sli_metric {
operation = "GET /api/users"
total_request_count_metric {
  metric_data_queries {
 id = "total"
 metric_stat {
metric {
  namespace= "AWS/ApplicationSignals"
  metric_name = "RequestCount"
  dimensions {
 name  = "Service"
 value = "my-service"
  }
}
stat= "Sum"
period = 60
 }
  }
}
monitored_request_count_metric {
  good_count_metric {
 metric_data_queries {
id = "good"
metric_stat {
  metric {
 namespace= "AWS/ApplicationSignals"
 metric_name = "SuccessCount"
 dimensions {
name  = "Service"
value = "my-service"
 }
  }
  stat= "Sum"
  period = 60
}
 }
  }
}
 }
  }
}
 }
  }

  goal {
 interval {
rolling_interval {
  duration_unit = "DAY"
  duration= 30
}
 }
 attainment_goal= 99.9
 warning_threshold = 99.5
  }
}

CLI での SLO 確認・Error Budget レポート:

# SLO 一覧確認
aws application-signals list-service-level-objectives \
  --region ap-northeast-1

# Error Budget レポート
aws application-signals batch-get-service-level-objective-budget-report \
  --timestamp $(date +%s) \
  --slo-ids '["my-service-availability-slo"]' \
  --region ap-northeast-1

コンソール: CloudWatch → Application Signals → SLOs

5-4. Latency SLO Terraform 実装

§5-3 と同構造。monitored_request_count_metric を Latency 用に差し替え、Metric Math 式 IF(latency_p99 <= 500, total, 0) で P99 <= 500ms のリクエスト数を good として計測する。attainment_goal = 95.0 (95% 目標)。

# §5-3 から変更点のみ: name + monitored_request_count_metric + attainment_goal
resource "aws_applicationsignals_service_level_objective" "latency" {
  name = "my-service-latency-slo"
  # sli 構造 (total_request_count_metric) は §5-3 と同一
  # monitored_request_count_metric を以下に差し替え:
  # monitored_request_count_metric {
  #good_count_metric {
  #  metric_data_queries { id="good"; expression="IF(latency_p99<=500,total,0)"; return_data=true }
  #  metric_data_queries {
  # id="latency_p99"
  # metric_stat { metric { namespace="AWS/ApplicationSignals"; metric_name="Latency"
  #dimensions { name="Service"; value="my-service" } }; stat="p99"; period=60 }
  # return_data = false
  #  }
  #}
  # }
  goal {
 interval { rolling_interval { duration_unit = "DAY"; duration = 30 } }
 attainment_goal= 95.0
 warning_threshold = 90.0
  }
}

5-5. Error Rate SLO Terraform 実装

§5-3 と同構造。monitored_request_count_metricbad_count_metric を使い ErrorCount を直接計測する。bad_count_metric は「エラー数が閾値超で SLO 違反」という設定に対応し、attainment_goal = 99.9 (エラー率 0.1% 以下目標)。

# §5-3 から変更点のみ: name + monitored_request_count_metric + attainment_goal
resource "aws_applicationsignals_service_level_objective" "error_rate" {
  name = "my-service-error-rate-slo"
  # monitored_request_count_metric を以下に差し替え:
  # monitored_request_count_metric {
  #bad_count_metric {
  #  metric_data_queries {
  # id = "bad"
  # metric_stat { metric { namespace="AWS/ApplicationSignals"; metric_name="ErrorCount"
  #dimensions { name="Service"; value="my-service" } }; stat="Sum"; period=60 }
  #  }
  #}
  # }
  goal {
 interval { rolling_interval { duration_unit = "DAY"; duration = 30 } }
 attainment_goal= 99.9
 warning_threshold = 99.5
  }
}

5-6. Burn Rate 2-window CloudWatch Alarm Terraform 実装

Error Budget の消費速度 (Burn Rate) を 1h と 6h の 2 ウィンドウで監視する。Fast Burn は短時間での急激な消費を検知し P1 アラートを発報する。Slow Burn は緩やかな消費を長期ウィンドウで検知し P2 アラートを発報する。

# Fast Burn Rate アラーム (1h window・14× 消費速度)
resource "aws_cloudwatch_metric_alarm" "slo_fast_burn" {
  alarm_name = "my-service-slo-fast-burn"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  threshold  = 14.0
  treat_missing_data  = "notBreaching"

  metric_query {
 id = "burn_rate"
 expression  = "IF(total > 0, 1 - good/total, 0)"
 label = "BurnRate"
 return_data = true
  }
  metric_query {
 id = "good"
 metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
period= 3600
stat  = "Sum"
dimensions  = { Service = "my-service" }
 }
  }
  metric_query {
 id = "total"
 metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
period= 3600
stat  = "Sum"
dimensions  = { Service = "my-service" }
 }
  }

  alarm_description = "SLO Fast Burn: Error Budget の 2% を 1h で消費 (14× 消費速度) → P1 アラート"
  alarm_actions  = [aws_sns_topic.slo_alerts.arn]
  ok_actions  = [aws_sns_topic.slo_alerts.arn]
}

# Slow Burn Rate アラーム (6h window・6× 消費速度)
resource "aws_cloudwatch_metric_alarm" "slo_slow_burn" {
  alarm_name = "my-service-slo-slow-burn"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  threshold  = 6.0
  treat_missing_data  = "notBreaching"

  metric_query {
 id = "burn_rate"
 expression  = "IF(total > 0, 1 - good/total, 0)"
 label = "BurnRate"
 return_data = true
  }
  metric_query {
 id = "good"
 metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
period= 21600
stat  = "Sum"
dimensions  = { Service = "my-service" }
 }
  }
  metric_query {
 id = "total"
 metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
period= 21600
stat  = "Sum"
dimensions  = { Service = "my-service" }
 }
  }

  alarm_description = "SLO Slow Burn: Error Budget の 5% を 6h で消費 (6× 消費速度) → P2 アラート"
  alarm_actions  = [aws_sns_topic.slo_alerts.arn]
  ok_actions  = [aws_sns_topic.slo_alerts.arn]
}

resource "aws_sns_topic" "slo_alerts" {
  name = "my-service-slo-alerts"
}

5-7. SLO 3 種マトリクス + Burn Rate 設計チェックリスト

【SLO 3 種マトリクス + Burn Rate 設計チェックリスト】
Availability SLO: SuccessCount / RequestCount → 99.9% 目標
Latency SLO: P99 <= 500ms のリクエスト率 → 95% 目標
Error Rate SLO: ErrorCount / RequestCount → 0.1% 未満目標
Fast Burn (1h): 14× 超過 → P1 アラート (Error Budget の 2% を 1h 消費)
Slow Burn (6h): 6× 超過 → P2 アラート (Error Budget の 5% を 6h 消費)
Error Budget 試算: 99.9% SLO → 月間 43.2 分のダウンタイム許容

5-8. 関連記事・クロスリンク


6. Synthetic Canary + Real User Monitoring (RUM) + SLO 統合監視 — 外形監視と実ユーザー監視の連携

6-1. Synthetic Canary と RUM の位置付け

Application Signals の SLO はサービス内部のメトリクスを基準に計測するが、エンドポイントが外部から到達可能かどうか、実ユーザーが実際に体験するパフォーマンスはどうかを把握するには追加の監視レイヤーが必要になる。

Synthetic Canary はロボットが 5 分間隔で定期的にエンドポイントにリクエストを送信する外形監視サービスです。Application Signals SLO と連携して可用性・レスポンスタイムを独立した視点で検証し、内部メトリクスでは検出できない DNS 障害やロードバランサー異常を捕捉します。

Real User Monitoring (RUM) は実ユーザーのブラウザ操作データを収集するフロントエンド監視サービスです。JavaScript エラー率・ページロード時間・Core Web Vitals を測定し、X-Ray トレースと連携することでフロントエンドからバックエンドまでの End-to-End の SLO 補完データとして機能します。

2 つを組み合わせることで SLO の完全な可観測性が実現する。Canary が 5 分間隔で Availability SLO の外部検証データを補完し、RUM がユーザー体験ベースの Latency SLO を測定する。X-Ray トレース連携により Application Signals サービスマップ上で Canary・RUM・内部 SLO を一元可視化できる。

fig05: Canary + RUM + SLO 統合監視図

6-2. Synthetic Canary Terraform 実装

Canary を Terraform で実装する際は aws_synthetics_canary リソースを使用します。重要なのは active_tracing = true を設定して X-Ray と連携させる点と、Canary スクリプトを S3 経由でデプロイする点です。

resource "aws_synthetics_canary" "api_health" {
  name  = "my-service-api-health"
  artifact_s3_location = "s3://${aws_s3_bucket.canary_artifacts.bucket}/canary/"
  execution_role_arn= aws_iam_role.canary_role.arn
  handler  = "apiCanary.handler"
  runtime_version= "syn-nodejs-puppeteer-6.2"
  start_canary= true

  schedule {
 expression = "rate(5 minutes)"
 duration_in_seconds = 0
  }

  run_config {
 timeout_in_seconds = 60
 memory_in_mb = 960
 active_tracing  = true
  }

  zip_file = data.archive_file.canary_script.output_base64sha256

  tags = {
 Service  = "my-service"
 MonitorType = "Synthetic"
  }
}

resource "aws_iam_role" "canary_role" {
  name = "synthetics-canary-role"
  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })
}

resource "aws_iam_role_policy" "canary_policy" {
  role = aws_iam_role.canary_role.id
  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect= "Allow"
  Action= ["s3:PutObject", "s3:GetBucketLocation"]
  Resource = ["${aws_s3_bucket.canary_artifacts.arn}/*"]
},
{
  Effect= "Allow"
  Action= ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]
  Resource = "arn:aws:logs:*:*:*"
},
{
  Effect= "Allow"
  Action= ["cloudwatch:PutMetricData"]
  Resource = "*"
},
{
  Effect= "Allow"
  Action= ["xray:PutTraceSegments", "xray:PutTelemetryRecords"]
  Resource = "*"
}
 ]
  })
}

AWS CLI で Canary を操作する:

# Canary の開始
aws synthetics start-canary \
  --name my-service-api-health \
  --region ap-northeast-1

# Canary ステータス確認
aws synthetics get-canary \
  --name my-service-api-health \
  --region ap-northeast-1

# Canary 実行結果確認
aws synthetics get-canary-runs \
  --name my-service-api-health \
  --region ap-northeast-1

マネジメントコンソール: CloudWatch → Synthetics Canaries → Canary 詳細 → Availability タブ で成功率グラフと最新実行ログを確認できる。

6-3. Canary スクリプト例 (Node.js)

Canary スクリプトは S3 へアップロードした ZIP ファイル内に配置する。synthetics.executeHttpStep を使用してエンドポイントのヘルスチェックを実装し、期待するステータスコードが返らない場合は Error を throw して Canary を失敗扱いにする。

// apiCanary.js
const synthetics = require('Synthetics');
const log = require('SyntheticsLogger');

const apiCanary = async () => {
  const requestOptions = {
 hostname: 'api.example.com',
 port: 443,
 path: '/api/health',
 method: 'GET',
 protocol: 'https:'
  };

  const validateResponse = async (res) => {
 if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
 }
 log.info('Health check passed');
  };

  await synthetics.executeHttpStep('HealthCheck', requestOptions, validateResponse);
};

exports.handler = async () => {
  return await apiCanary();
};

6-4. Real User Monitoring (RUM) Terraform 実装

RUM の aws_rum_app_monitor リソースは監視対象ドメインを指定し、X-Ray 連携・サンプリングレート・収集テレメトリ種別を設定する。本番環境では session_sample_rate = 0.1(10%)から開始してコストを抑制する。

resource "aws_rum_app_monitor" "my_app" {
  name= "my-app-rum"
  domain = "app.example.com"

  app_monitor_configuration {
 allow_cookies = true
 enable_x_ray  = true
 session_sample_rate = 0.1
 telemetries= ["errors", "http", "performance"]

 included_pages = ["https://app.example.com/*"]
 excluded_pages = ["https://app.example.com/admin/*"]
  }

  custom_events {
 status = "ENABLED"
  }
}

data "aws_rum_app_monitor" "my_app" {
  name = aws_rum_app_monitor.my_app.name
}

AWS CLI で RUM を操作する:

# RUM AppMonitor 作成確認
aws rum get-app-monitor \
  --name my-app-rum \
  --region ap-northeast-1

# RUM メトリクス確認 (直近1時間)
aws rum get-app-monitor-data \
  --name my-app-rum \
  --time-range "Start=$(date -d '1 hour ago' +%s),End=$(date +%s)" \
  --region ap-northeast-1

マネジメントコンソール: CloudWatch → RUM → アプリモニター詳細 → Performance / Errors タブ でページロード時間・JavaScript エラー率・HTTP エラー率をリアルタイム確認できる。

6-5. RUM JavaScript スニペット (フロントエンドへの埋め込み)

RUM データ収集には HTML の <head> 内に JavaScript スニペットを埋め込む。guestRoleArnidentityPoolId は Terraform apply 後に出力される値を使用する。enableXRay: true により RUM セッションと X-Ray トレースが紐付けられる。

// HTML <head> 内に追加 — RUM クライアント初期化
import { AwsRum } from 'aws-rum-web';

try {
  const config = {
 sessionSampleRate: 0.1,
 guestRoleArn: "arn:aws:iam::ACCOUNT_ID:role/RUM-Monitor-ap-northeast-1-XXXXXXXX",
 identityPoolId: "ap-northeast-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
 endpoint: "https://dataplane.rum.ap-northeast-1.amazonaws.com",
 telemetries: ["performance", "errors", "http"],
 allowCookies: true,
 enableXRay: true
  };

  const APPLICATION_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
  const APPLICATION_VERSION = '1.0.0';
  const APPLICATION_REGION = 'ap-northeast-1';

  const awsRum = new AwsRum(
 APPLICATION_ID,
 APPLICATION_VERSION,
 APPLICATION_REGION,
 config
  );
} catch (error) {
  // RUM 初期化エラーはアプリの動作に影響させない
}

6-6. Canary + RUM + SLO 相関監視

Canary・RUM・Application Signals SLO はそれぞれ独立したデータソースだが、CloudWatch の統合基盤上で相関させることで SLO の精度を大幅に高められる。

SLO とのマッピング:

監視種別SLO への貢献確認場所
Canary 成功率Availability SLO の外部検証データ補完CloudWatch Synthetics
Canary レスポンスタイムLatency SLO の外形監視データCloudWatch メトリクス
RUM エラー率フロントエンド Error Rate SLOCloudWatch RUM
RUM ページロード時間ユーザー体感 Latency SLOCloudWatch RUM

X-Ray トレース連携: Canary の active_tracing = true と RUM の enable_x_ray = true を有効化すると、Canary・RUM のリクエストが X-Ray トレースとして記録され Application Signals サービスマップ上に表示される。外形監視・実ユーザー監視・内部 SLO を一元可視化することで、サービス境界を越えた障害の根本原因分析が可能になる。

Canary が失敗し内部 SLO が正常を示す場合はネットワーク・DNS・ロードバランサーの問題を示唆する。RUM エラー率が急上昇し Canary が正常な場合は特定ユーザー環境やブラウザ起因の問題を示唆する。両方が悪化する場合はサービス全体の障害として Error Budget の消費速度を確認しアラートの優先度を上げる。

【Canary + RUM + SLO 統合監視チェックリスト】
Synthetic Canary:

  • aws_synthetics_canary で 5 分間隔 + active_tracing=true 設定済みか
  • Canary スクリプトでエンドポイント死活 + ステータスコード確認が実装されているか
  • S3 アーティファクトバケット + IAM ロールが Terraform で管理されているか

Real User Monitoring:

  • aws_rum_app_monitor でドメイン指定 + X-Ray 連携 (enable_x_ray=true) が有効か
  • RUM JavaScript スニペットがフロントエンドの <head> に埋め込まれているか
  • セッションサンプリングレートが適切に設定されているか (推奨 10%)

SLO 連携:

  • Canary 成功率が Availability SLO の補完指標として CloudWatch で確認できるか
  • RUM エラー率がフロントエンド Error Rate SLO に反映されているか
  • CloudWatch → Application Signals → SLO で統合確認できるか

6-7. クロスリンク


7. Burn Rate アラート → PagerDuty / OpsGenie 自動エスカレーション + コスト最適化

fig06: Burn Rate アラート → PagerDuty/OpsGenie エスカレーションフロー

SLO Error Budget が急速に消費されたとき(Burn Rate 超過)、人間の目が届く前に自動でインシデント管理ツールに通知することで、対応時間を最小化できます。本章では CloudWatch Alarm → SNS → Lambda → PagerDuty/OpsGenie の完全実装を解説します。

7-1. Fast/Slow Burn Rate アラームの復習

§5 で実装した 2-window アラーム構成をエスカレーションに接続します。

ウィンドウ倍率意味緊急度
Fast Burn (1h)14×Error Budget の 2% を 1 時間で消費緊急 (P1)
Slow Burn (6h)Error Budget の 5% を 6 時間で消費注意 (P2)

7-2. SNS トピック + Lambda エスカレーター Terraform 実装

# SNS トピック (Burn Rate アラーム → Lambda 受信)
resource "aws_sns_topic" "slo_burn_rate" {
  name = "slo-burn-rate-alerts"
}

resource "aws_sns_topic_subscription" "lambda_escalator" {
  topic_arn = aws_sns_topic.slo_burn_rate.arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.slo_escalator.arn
}

resource "aws_lambda_permission" "sns_invoke" {
  statement_id  = "AllowSNSInvoke"
  action  = "lambda:InvokeFunction"
  function_name = aws_lambda_function.slo_escalator.function_name
  principal  = "sns.amazonaws.com"
  source_arn = aws_sns_topic.slo_burn_rate.arn
}

# エスカレーター Lambda (PagerDuty / OpsGenie 両対応)
resource "aws_lambda_function" "slo_escalator" {
  function_name = "slo-burn-rate-escalator"
  runtime = "python3.12"
  handler = "escalator.handler"
  filename= "escalator.zip"
  role = aws_iam_role.escalator_role.arn

  environment {
 variables = {
PAGERDUTY_ROUTING_KEY = var.pagerduty_routing_key
OPSGENIE_API_KEY= var.opsgenie_api_key
ESCALATION_TARGET  = var.escalation_target  # "pagerduty" or "opsgenie"
 }
  }
}

# CloudWatch Alarm → SNS 接続 (§5 の Fast Burn アラーム)
resource "aws_cloudwatch_metric_alarm" "slo_fast_burn_with_sns" {
  alarm_name = "my-service-slo-fast-burn"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  threshold  = 14.0
  treat_missing_data  = "notBreaching"

  metric_query {
 id = "burn_rate"
 expression  = "IF(total > 0, 1 - good/total, 0)"
 return_data = true
  }
  metric_query {
 id = "good"
 metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
period= 3600
stat  = "Sum"
dimensions  = { Service = "my-service" }
 }
  }
  metric_query {
 id = "total"
 metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
period= 3600
stat  = "Sum"
dimensions  = { Service = "my-service" }
 }
  }

  alarm_actions = [aws_sns_topic.slo_burn_rate.arn]
  ok_actions = [aws_sns_topic.slo_burn_rate.arn]
}

7-3. Lambda エスカレーター実装 (PagerDuty / OpsGenie 両対応)

# escalator.py
import json
import os
import urllib.request
import urllib.parse

def handler(event, context):
 for record in event['Records']:
  message = json.loads(record['Sns']['Message'])
  alarm_name  = message.get('AlarmName', 'Unknown')
  alarm_state = message.get('NewStateValue', 'ALARM')
  description = message.get('NewStateReason', '')

  severity = 'critical' if 'fast-burn' in alarm_name.lower() else 'warning'
  target= os.environ.get('ESCALATION_TARGET', 'pagerduty')

  if alarm_state == 'ALARM':
if target == 'pagerduty':
 _trigger_pagerduty(alarm_name, description, severity)
else:
 _trigger_opsgenie(alarm_name, description, severity)
  elif alarm_state == 'OK':
if target == 'pagerduty':
 _resolve_pagerduty(alarm_name)
else:
 _resolve_opsgenie(alarm_name)


def _trigger_pagerduty(alarm_name, description, severity):
 """PagerDuty Events API v2"""
 payload = {
  'routing_key':  os.environ['PAGERDUTY_ROUTING_KEY'],
  'event_action': 'trigger',
  'payload': {
'summary':  f'SLO Burn Rate Alert: {alarm_name}',
'severity': severity, # 'critical' or 'warning'
'source':'AWS CloudWatch Application Signals',
'custom_details': {'description': description}
  },
  'dedup_key': alarm_name
 }
 _post('https://events.pagerduty.com/v2/enqueue', payload)


def _resolve_pagerduty(alarm_name):
 payload = {
  'routing_key':  os.environ['PAGERDUTY_ROUTING_KEY'],
  'event_action': 'resolve',
  'dedup_key': alarm_name
 }
 _post('https://events.pagerduty.com/v2/enqueue', payload)


def _trigger_opsgenie(alarm_name, description, severity):
 """OpsGenie Alerts API v2"""
 payload = {
  'message':  f'SLO Burn Rate Alert: {alarm_name}',
  'alias': alarm_name,
  'priority': 'P1' if severity == 'critical' else 'P2',
  'source':'AWS CloudWatch Application Signals',
  'description': description
 }
 _post(
  'https://api.opsgenie.com/v2/alerts',
  payload,
  headers={'Authorization': f"GenieKey {os.environ['OPSGENIE_API_KEY']}"}
 )


def _resolve_opsgenie(alarm_name):
 encoded = urllib.parse.quote(alarm_name)
 _post(
  f'https://api.opsgenie.com/v2/alerts/{encoded}/close?identifierType=alias',
  {},
  headers={'Authorization': f"GenieKey {os.environ['OPSGENIE_API_KEY']}"}
 )


def _post(url, payload, headers=None):
 data = json.dumps(payload).encode()
 req  = urllib.request.Request(url, data=data, method='POST')
 req.add_header('Content-Type', 'application/json')
 if headers:
  for k, v in headers.items():
req.add_header(k, v)
 with urllib.request.urlopen(req, timeout=10) as resp:
  return json.loads(resp.read())

AWS CLI (テスト):

# SNS 経由でアラームをシミュレート
aws sns publish \
  --topic-arn $(terraform output -raw slo_sns_topic_arn) \
  --message '{"AlarmName":"test-fast-burn","NewStateValue":"ALARM","NewStateReason":"Burn Rate 15x"}' \
  --region ap-northeast-1

# Lambda ログ確認
aws logs tail /aws/lambda/slo-burn-rate-escalator \
  --follow --region ap-northeast-1

コンソール: CloudWatch → Alarms → アラーム状態確認 → SNS → Lambda ログ

7-4. コスト最適化 5 項目

Application Signals 環境全体のコスト試算と削減策を整理します。

コスト項目概算 (月間)最適化策
Application Signals メトリクス$5-20 (サービス数 × リクエスト量依存)Canary リクエストは SLI から除外設定
Synthetic Canary$0.0012/実行 × 8,640回/月 ≒ $10.4 (5分間隔)非本番は 15分間隔に変更で $3.5 に削減
RUM$1/1万セッション → 10万セッション/月 ≒ $10セッションサンプリングを 5% に落とす
CloudWatch Alarms$0.10/アラーム × 6アラーム ≒ $0.6Burn Rate 2-window を 1-window に統合 (SLO 小規模時)
SNS + Lambda< $1 (イベント発生頻度依存)正常時のコストはほぼゼロ

コスト最適化の優先順位:
1. Canary 実行頻度を非本番環境で 15分間隔に変更 → $7/月削減
2. RUM セッションサンプリングを 10% → 5% に変更 → $5/月削減
3. Application Signals メトリクス: 不要なカスタムメトリクスを削除

# 現在の Application Signals コスト確認
aws ce get-cost-and-usage \
  --time-period Start=$(date -d '1 month ago' +%Y-%m-01),End=$(date +%Y-%m-01) \
  --granularity MONTHLY \
  --filter '{"Dimensions":{"Key":"SERVICE","Values":["AmazonCloudWatch"]}}' \
  --metrics BlendedCost \
  --region ap-northeast-1

7-5. トラブルシュート 10 選

#症状原因対処法
1Application Signals にサービスが表示されないADOT Collector が Application Signals exporter に送出していないcollector.yaml の exporters に awsapplicationsignals を追加
2SLO の SuccessCount が 0 のままLambda Layer の OTEL_AWS_APPLICATION_SIGNALS_ENABLED が未設定環境変数 OTEL_AWS_APPLICATION_SIGNALS_ENABLED=true を設定
3Burn Rate アラームが誤発火するtotal メトリクスが 0 のとき division by zeroIF(total > 0, 1 – good/total, 0) 式で 0 除算を回避
4EKS で amazon-cloudwatch-observability Add-on が起動しないIAM IRSA 権限不足CloudWatchAgentServerPolicy が IRSA ロールにアタッチされているか確認
5Canary が Timeout エラーを繰り返すVPC 内エンドポイントへのアクセス設定漏れCanary の VPC Config + Security Group + NAT Gateway/Endpoint を確認
6RUM JavaScript を埋め込んだが CloudWatch にデータが来ないCORS ポリシーまたは identityPoolId の誤りRUM AppMonitor の許可オリジン設定と Cognito Identity Pool 設定を確認
7SLO Error Budget が予期せず急減しているCanary のリクエストが SLI に含まれているCanary リクエストを SLO の除外フィルタに追加
8PagerDuty インシデントが重複作成されるdedup_key が都度変わっているdedup_key にアラーム名 (固定値) を使用
9aws_applicationsignals_service_level_objective が plan/apply でエラーAWS Provider バージョンが古い (5.x 未満)terraform providers → AWS Provider >= 5.x にアップグレード
10SLO の Attainment が 100% なのに Burn Rate アラームが発火するevaluation_periods の設定が短すぎてノイズを拾っているevaluation_periods を 2-3 に増やしてノイズ耐性を向上
【Burn Rate アラート + コスト最適化チェックリスト】
Burn Rate エスカレーション:
– [ ] Fast Burn (1h × 14×) → SNS → Lambda → PagerDuty/OpsGenie P1
– [ ] Slow Burn (6h × 6×) → SNS → Lambda → PagerDuty/OpsGenie P2
– [ ] dedup_key にアラーム名固定値を設定 (重複インシデント防止)
– [ ] Lambda escalator に OK アクション (resolve) も設定
コスト最適化:
– [ ] Canary 非本番は 15分間隔に変更 ($7/月削減)
– [ ] RUM セッションサンプリング 5-10%
– [ ] 不要 Application Signals メトリクス削除
– [ ] aws ce get-cost-and-usage で月次コスト確認

クロスリンク:
観測性 Vol2 X-Ray + ADOT 分散トレーシング基盤 — §7 Burn Rate アラームの SLI データは ADOT Collector が収集
観測性 Vol1 CloudWatch Logs Insights — Lambda escalator のログを Logs Insights で分析


8. まとめ + 観測性 3 部作完結宣言 + 9 巻 AWS 本番運用シリーズ完結 + 落とし穴 10 選

8-1. 本記事のまとめ

本記事では CloudWatch Application Signals + SLO を使った本番観測性の第 3 層として以下を実装しました。

実装内容主要リソース
Application Signals 有効化 (Lambda/ECS/EKS)ADOT Layer / サイドカー / EKS Add-on
SLO 3 種 Terraform 定義aws_applicationsignals_service_level_objective
Burn Rate 2-window アラームaws_cloudwatch_metric_alarm (1h/6h)
Synthetic Canary 外形監視aws_synthetics_canary (5分間隔)
Real User Monitoringaws_rum_app_monitor
PagerDuty/OpsGenie 自動エスカレーションSNS + Lambda escalator

8-2. 観測性 3 部作完結

AWS 本番観測性 3 部作 — 完結

3 層が揃うことで「なぜ SLO が割れたか」をログ (Vol1) + トレース (Vol2) で根本原因まで追跡できる完全な観測性スタックが完成します。

8-3. 9 巻 AWS 本番運用シリーズ完結

8-4. 落とし穴 10 選

#落とし穴回避策
1Application Signals を有効化したが SLO のデータが空ADOT Collector に awsapplicationsignals exporter を追加し、application-signals:PutServiceData IAM 権限を付与
2SLO の Availability が常に 100% で現実と乖離Canary リクエストを SLI から除外し、実ユーザーリクエストのみで計測
3Burn Rate アラームが発火しすぎる (ノイズ)evaluation_periods を 2-3 に増やし、treat_missing_data = “notBreaching” を設定
4Error Budget が月末にゼロになるRolling 30日間隔で計算し、月初にリセットされると勘違いしないよう注意
5Latency SLO の P99 が外れ値で常に割れるP99 ではなく P95 で SLO を設定し、単発スパイクを許容する設計に
6RUM セッションサンプリングを 100% にしてコスト爆発初期は 5-10% から始め、データ量を確認してから調整
7Canary が VPC 内 API にアクセスできないCanary の VPC Config を設定し、セキュリティグループで HTTPS 通信を許可
8PagerDuty インシデントが OK 後も残るLambda escalator の OK アクション (_resolve) 処理を必ず実装
9SLO Terraform resource で provider エラーAWS Provider を 5.x 以上に固定 (aws_applicationsignals_service_level_objective は最新 Provider が必要)
109 巻全記事のクロスリンクが古い URLPhase5 で各記事の ep-btn URL を最新記事に更新 (観測性 3 部作完結時)

8-5. SLO 運用成熟度モデル

SLO を導入したばかりのチームが段階的に成熟する 4 段階ロードマップを示します。

レベル状態次のアクション
Lv.0 (計測なし)SLI/SLO 未定義。障害時に「どこが壊れたか」がわからないVol1 ログ + Vol2 トレースから始める
Lv.1 (可視化)Application Signals でサービスマップとメトリクスが見えるSLO 1 種 (Availability) を定義し Error Budget を算出
Lv.2 (アラート)Burn Rate アラームで事前検知できる2-window (Fast/Slow) を実装し PagerDuty 連携
Lv.3 (自動化)Error Budget 消費に応じてデプロイ速度を自動調整Canary + RUM + SLO 統合でリリースゲートを自動化

本記事では Lv.1 → Lv.2 → Lv.3 への移行を Terraform IaC で一気通貫に実装しました。

8-6. Application Signals を本番採用する際の判断基準

Application Signals の導入コストと得られる価値のトレードオフを整理します。

導入を強く推奨するケース:
– Lambda / ECS / EKS のいずれかで ADOT (Vol2) を既に導入済みの場合 → 追加設定のみで SLO 化できる
– 複数サービス間の依存関係が複雑で「どのサービスの SLO が割れているか」を一元把握したい
– SRE チームが Error Budget に基づいたリリース判断プロセスを整備しようとしている

導入を見送る / 段階的に進めるケース:
– 単一 Lambda 関数のみで CloudWatch Alarms が十分に機能している場合
– トラフィックが月 1 万リクエスト未満でコストメリットが薄い場合 (CloudWatch Metrics の方が安価)
– ADOT Collector の運用経験がなく Vol2 が未実施の場合 → Vol2 を先に完了させる

8-7. コマンドチートシート

# Application Signals サービス一覧
aws application-signals list-services \
  --start-time $(date -d '1 hour ago' +%s) --end-time $(date +%s) --region ap-northeast-1

# SLO 一覧
aws application-signals list-service-level-objectives --region ap-northeast-1

# Error Budget レポート
aws application-signals batch-get-service-level-objective-budget-report \
  --timestamp $(date +%s) --slo-ids '["my-service-availability-slo"]' --region ap-northeast-1

# Canary ステータス
aws synthetics get-canary --name my-service-api-health --region ap-northeast-1

# RUM AppMonitor 確認
aws rum get-app-monitor --name my-app-rum --region ap-northeast-1

# コスト確認
aws ce get-cost-and-usage \
  --time-period Start=$(date -d '1 month ago' +%Y-%m-01),End=$(date +%Y-%m-01) \
  --granularity MONTHLY \
  --filter '{"Dimensions":{"Key":"SERVICE","Values":["AmazonCloudWatch"]}}' \
  --metrics BlendedCost --region ap-northeast-1

Vol2 を読む: X-Ray + ADOT 分散トレーシング基盤