前提条件
- 第1回から第10回までの構築が完了していること
- こちらからDockerコンテナでの実行環境が準備できていること
Terraform実行環境の起動
前回と同様に、Dockerコンテナ内で作業を進めます。
# コンテナを起動してbashに入る
docker-compose run --rm terraform
これ以降のコマンドは、すべてこのコンテナ内で実行します。
基礎知識
なぜ監視が必要なのか、WEBアプリ開発者の視点から見ると
ローカル開発環境では、エラーが発生したら即座にログを確認し、console.log
でデバッグできます。しかし、本番環境では以下の課題があります。
開発環境 | 本番環境の課題 | 必要な解決策 |
---|---|---|
ターミナルでログを直接確認 | 複数のコンテナが分散して動作 | ログを一箇所に集約(CloudWatch Logs) |
エラーが起きたらすぐ気づく | ユーザーからの報告まで気づかない | 自動アラート通知(CloudWatch Alarms) |
処理が遅い箇所をコードで特定 | どのサービスがボトルネックか不明 | 分散トレーシング(X-Ray) |
docker stats でリソース確認 |
過去のメトリクスが見れない | メトリクス履歴保存(Container Insights) |
CloudWatch Container Insights
Container Insightsは、コンテナのメトリクスを自動収集し、時系列データとして保存します。
収集されるメトリクスと活用方法
メトリクス | 何がわかるか | 活用例 |
---|---|---|
CPU使用率 | 処理負荷の状況 | スケールアウトのタイミング判断 |
メモリ使用率 | メモリリークの有無 | メモリ不足によるクラッシュ防止 |
ネットワークI/O | 通信量の変化 | DDoS攻撃の検知 |
タスク数 | サービスの稼働状況 | 異常終了の検知 |
AWS X-Ray
X-Rayは、一つのリクエストが複数のサービスを経由する様子を可視化します。従来はサイドカーコンテナでX-Rayデーモンを動かす方法が一般的でしたが、VPCエンドポイント経由で直接X-Ray APIに送信する方法がよりシンプルです。
X-Ray SDK直接送信方式のメリット
従来方式(サイドカー) | SDK直接送信方式 | メリット |
---|---|---|
別コンテナでデーモン起動 | アプリ内でSDK使用 | コンテナ管理が不要 |
UDPでデーモンに送信 | HTTPSでAPI直接送信 | ネットワーク設定がシンプル |
パブリックイメージが必要 | VPCエンドポイント利用可 | NAT Gateway不要 |
リソース追加(CPU/メモリ) | 追加リソース不要 | コスト削減 |
ログの種類と収集目的
ログタイプ | 何を記録するか | トラブルシューティング例 |
---|---|---|
アプリケーションログ | エラーメッセージ、処理内容 | 500エラーの原因特定、バグの再現 |
ALBアクセスログ | すべてのHTTPリクエスト | 不正アクセスの検知、レスポンスタイムの分析 |
VPC Flow Logs | ネットワーク通信の詳細 | 通信エラーの原因、セキュリティ侵害の調査 |
Container Insights | リソース使用状況 | パフォーマンス劣化の原因、容量計画 |
アラートの重要性
問題が発生してから対応するのではなく、予兆を検知して未然に防ぐことが重要です。
監視項目 | 閾値の目安 | 設定理由 |
---|---|---|
CPU使用率 | 80% | 100%になる前に対処の時間を確保 |
メモリ使用率 | 80% | メモリ不足によるクラッシュを防止 |
エラー率 | 5% | ユーザー影響が拡大する前に検知 |
レスポンスタイム | 3秒 | ユーザー体験の劣化を防止 |
今回作成するリソース
リソース | 説明 | 数量 |
---|---|---|
CloudWatch Dashboard | メトリクス可視化ダッシュボード | 1個 |
ALB Access Logs用S3バケット | アクセスログ保存 | 1個 |
X-Ray VPCエンドポイント | X-Ray APIへのプライベート接続 | 1個 |
CloudWatch Alarms | 異常検知アラーム | 複数 |
SNS Topic | アラート通知先 | 1個 |
Log Insights Queries | ログ分析クエリ | 複数 |
Terraformコードの実装
変数の追加
監視関連の変数を追加します。
# terraform/variables.tf に追加
variable "enable_alb_access_logs" {
description = "ALBアクセスログを有効にするか"
type = bool
default = true
}
variable "enable_xray_tracing" {
description = "X-Rayトレーシングを有効にするか"
type = bool
default = true
}
variable "alarm_email" {
description = "アラーム通知先のメールアドレス"
type = string
default = ""
}
variable "cpu_utilization_threshold" {
description = "CPU使用率のアラーム閾値(%)"
type = number
default = 80
}
variable "memory_utilization_threshold" {
description = "メモリ使用率のアラーム閾値(%)"
type = number
default = 80
}
variable "error_rate_threshold" {
description = "エラー率のアラーム閾値(%)"
type = number
default = 5
}
ALB Access Logsの設定
ALBのすべてのリクエスト情報を記録するためのS3バケットを作成します。
# terraform/monitoring.tf
# ALBアクセスログ用S3バケット
resource "aws_s3_bucket" "alb_logs" {
count = var.enable_alb_access_logs ? 1 : 0
bucket = "${var.project_name}-${var.environment}-alb-logs"
force_destroy = true
tags = {
Name = "${var.project_name}-${var.environment}-alb-logs"
}
}
# バケットのパブリックアクセスブロック
resource "aws_s3_bucket_public_access_block" "alb_logs" {
count = var.enable_alb_access_logs ? 1 : 0
bucket = aws_s3_bucket.alb_logs[0].id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# ALBサービスアカウントからのアクセス許可
resource "aws_s3_bucket_policy" "alb_logs" {
count = var.enable_alb_access_logs ? 1 : 0
bucket = aws_s3_bucket.alb_logs[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::582318560864:root" # 東京リージョンのALBサービスアカウント
}
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.alb_logs[0].arn}/*"
}
]
})
}
# ログのライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "alb_logs" {
count = var.enable_alb_access_logs ? 1 : 0
bucket = aws_s3_bucket.alb_logs[0].id
rule {
id = "delete-old-logs"
status = "Enabled"
filter {}
expiration {
days = 30
}
transition {
days = 7
storage_class = "GLACIER_IR"
}
}
}
ALBログ設定の目的と詳細
パラメータ | 設定値 | なぜこの設定が必要か |
---|---|---|
Principal.AWS | 582318560864 | ALBサービスがログを書き込むための専用アカウント(リージョン固定) |
expiration.days | 30 | 古いログは分析価値が低下するため自動削除してコスト削減 |
transition.storage_class | GLACIER_IR(7日後) | アクセス頻度が下がるログを低コストストレージに移動 |
force_destroy | true | 開発環境ではterraform destroy 時にログも削除可能に |
ALBへのログ設定追加
既存のALBリソースにアクセスログの出力先を設定します。
# terraform/alb.tf に追加
# ALBリソースのaccess_logsブロックを有効化
resource "aws_lb" "main" {
# 既存の設定は維持
dynamic "access_logs" {
for_each = var.enable_alb_access_logs ? [1] : []
content {
bucket = aws_s3_bucket.alb_logs[0].id
prefix = "alb"
enabled = true
}
}
# depends_onを追加
depends_on = [
aws_s3_bucket_policy.alb_logs
]
}
X-Ray設定(SDKから直接送信)
サイドカーコンテナを使わず、アプリから直接X-Ray APIに送信する設定を行います。
# terraform/xray.tf
# X-Rayサービスマップ用のサンプリングルール
resource "aws_xray_sampling_rule" "main" {
count = var.enable_xray_tracing ? 1 : 0
rule_name = "${var.project_name}-${var.environment}-sampling"
priority = 1000
version = 1
reservoir_size = 1
fixed_rate = 0.05 # 5%のリクエストをサンプリング
url_path = "*"
host = "*"
http_method = "*"
service_type = "*"
service_name = "*"
resource_arn = "*"
tags = {
Name = "${var.project_name}-${var.environment}-sampling-rule"
}
}
# ECS Task RoleにX-Ray権限を追加
resource "aws_iam_role_policy" "ecs_xray_policy" {
count = var.enable_xray_tracing ? 1 : 0
name = "${var.project_name}-${var.environment}-ecs-xray-policy"
role = aws_iam_role.ecs_task_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords",
"xray:GetSamplingRules",
"xray:GetSamplingTargets",
"xray:GetSamplingStatisticSummaries"
]
Resource = "*"
}
]
})
}
X-Ray権限設定の理由
権限 | 用途 | なぜ必要か |
---|---|---|
PutTraceSegments | トレースデータ送信 | アプリの実行情報をX-Rayに送信 |
PutTelemetryRecords | テレメトリ送信 | SDKの動作状況をX-Rayに報告 |
GetSamplingRules | サンプリングルール取得 | 動的にサンプリング率を調整 |
GetSamplingTargets | サンプリング目標取得 | トラフィックに応じた自動調整 |
Task DefinitionへのX-Ray環境変数追加
サイドカーコンテナは使わず、環境変数のみ設定します。
# terraform/ecs_service.tf のTask Definition更新
resource "aws_ecs_task_definition" "app" {
# 既存の設定は維持
container_definitions = jsonencode([
{
name = "${var.project_name}-${var.environment}-app"
# 既存の設定は維持
environment = concat(
# 既存の環境変数
[
{
name = "AWS_XRAY_TRACING_NAME"
value = "${var.project_name}-${var.environment}"
},
{
name = "AWS_XRAY_CONTEXT_MISSING"
value = "LOG_ERROR"
},
{
name = "_X_AMZN_TRACE_ID"
value = "" # ALBから自動的に設定される
}
]
)
# X-Rayサイドカーコンテナは追加しない
}
])
}
X-Ray環境変数の設定意図
環境変数 | 設定値 | 目的 |
---|---|---|
AWS_XRAY_TRACING_NAME | プロジェクト名-環境名 | サービスマップ上の表示名 |
AWS_XRAY_CONTEXT_MISSING | LOG_ERROR | トレースIDがない場合はエラーログ出力(クラッシュ防止) |
_X_AMZN_TRACE_ID | 空文字 | ALBがトレースIDを自動注入するためのプレースホルダー |
X-Ray VPCエンドポイントの追加
NAT Gatewayなしでも、X-Ray APIに接続できるようにします。
# terraform/vpc_endpoints.tf に追加
# X-Ray Endpoint
resource "aws_vpc_endpoint" "xray" {
count = var.enable_vpc_endpoints && var.enable_xray_tracing ? 1 : 0
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.xray"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpc_endpoints.id]
private_dns_enabled = true
tags = {
Name = "${var.project_name}-${var.environment}-xray-endpoint"
}
}
アプリ側のX-Ray実装例
HonoでX-Ray SDKを使用する実装例です。
// backend/src/tracing/xray.ts
import AWSXRay from 'aws-xray-sdk-core'
import { Context, Next } from 'hono'
// X-Rayの初期化
AWSXRay.config([
AWSXRay.plugins.ECSPlugin,
])
// タスク定義の環境変数からサービス名を取得
const serviceName = process.env.AWS_XRAY_TRACING_NAME || ''
// VPCエンドポイント経由で送信するための設定
AWSXRay.setContextMissingStrategy('LOG_ERROR')
export const xrayMiddleware = () => {
return async (c: Context, next: Next) => {
// X-Rayが有効でない場合はスキップ
if (!AWSXRay.getSegment()) {
await next()
return
}
const segment = AWSXRay.getSegment()
const subsegment = segment?.addNewSubsegment('hono-handler')
try {
// リクエスト情報を記録
subsegment?.addAnnotation('path', c.req.path)
subsegment?.addAnnotation('method', c.req.method)
subsegment?.addAnnotation('service', serviceName)
await next()
// レスポンス情報を記録
subsegment?.addAnnotation('statusCode', c.res.status)
} catch (error) {
subsegment?.addError(error as Error)
throw error
} finally {
subsegment?.close()
}
}
}
// データベースクエリのトレース例
export const traceDatabase = async (queryName: string, fn: () => Promise<any>) => {
// X-Rayトレーシングが有効でない場合は通常実行
if (!AWSXRay.getSegment()) {
return await fn()
}
const subsegment = AWSXRay.getSegment()?.addNewSubsegment(`db-${queryName}`)
try {
subsegment?.addAnnotation('query', queryName)
subsegment?.addAnnotation('service', serviceName)
const result = await fn()
return result
} catch (error) {
subsegment?.addError(error as Error)
throw error
} finally {
subsegment?.close()
}
}
CloudWatch Alarms
システムの異常を早期発見するためのアラームを設定します。
# terraform/alarms.tf
# SNS Topic(アラーム通知先)
resource "aws_sns_topic" "alarms" {
name = "${var.project_name}-${var.environment}-alarms"
tags = {
Name = "${var.project_name}-${var.environment}-alarms"
}
}
# メール通知設定
resource "aws_sns_topic_subscription" "alarm_email" {
count = var.alarm_email != "" ? 1 : 0
topic_arn = aws_sns_topic.alarms.arn
protocol = "email"
endpoint = var.alarm_email
}
# CPU使用率アラーム
resource "aws_cloudwatch_metric_alarm" "ecs_cpu_high" {
alarm_name = "${var.project_name}-${var.environment}-ecs-cpu-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/ECS"
period = "300"
statistic = "Average"
threshold = var.cpu_utilization_threshold
alarm_description = "This metric monitors ECS CPU utilization"
alarm_actions = [aws_sns_topic.alarms.arn]
dimensions = {
ClusterName = aws_ecs_cluster.main.name
ServiceName = aws_ecs_service.app.name
}
tags = {
Name = "${var.project_name}-${var.environment}-cpu-alarm"
}
}
# メモリ使用率アラーム
resource "aws_cloudwatch_metric_alarm" "ecs_memory_high" {
alarm_name = "${var.project_name}-${var.environment}-ecs-memory-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "2"
metric_name = "MemoryUtilization"
namespace = "AWS/ECS"
period = "300"
statistic = "Average"
threshold = var.memory_utilization_threshold
alarm_description = "This metric monitors ECS memory utilization"
alarm_actions = [aws_sns_topic.alarms.arn]
dimensions = {
ClusterName = aws_ecs_cluster.main.name
ServiceName = aws_ecs_service.app.name
}
tags = {
Name = "${var.project_name}-${var.environment}-memory-alarm"
}
}
# Target Group異常ホストアラーム
resource "aws_cloudwatch_metric_alarm" "alb_unhealthy_hosts" {
alarm_name = "${var.project_name}-${var.environment}-alb-unhealthy"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "2"
metric_name = "UnHealthyHostCount"
namespace = "AWS/ApplicationELB"
period = "60"
statistic = "Maximum"
threshold = "0"
alarm_description = "Alert when unhealthy targets detected"
alarm_actions = [aws_sns_topic.alarms.arn]
dimensions = {
TargetGroup = split(":", aws_lb_target_group.ecs.arn)[5]
LoadBalancer = split("/", aws_lb.main.arn)[2]
}
tags = {
Name = "${var.project_name}-${var.environment}-unhealthy-alarm"
}
}
CloudWatch Dashboard
メトリクスを一覧で確認できるダッシュボードを作成します。
# terraform/dashboard.tf
resource "aws_cloudwatch_dashboard" "main" {
dashboard_name = "${var.project_name}-${var.environment}-dashboard"
dashboard_body = jsonencode({
widgets = [
{
type = "metric"
properties = {
metrics = [
["AWS/ECS", "CPUUtilization", { stat = "Average" }],
[".", "MemoryUtilization", { stat = "Average" }]
]
view = "timeSeries"
stacked = false
region = var.aws_region
title = "ECS Resource Utilization"
period = 300
}
},
{
type = "metric"
properties = {
metrics = [
["AWS/ApplicationELB", "TargetResponseTime", { stat = "Average" }],
[".", "RequestCount", { stat = "Sum", yAxis = "right" }]
]
view = "timeSeries"
region = var.aws_region
title = "ALB Performance"
period = 300
}
},
{
type = "metric"
properties = {
metrics = [
["AWS/ApplicationELB", "HTTPCode_Target_2XX_Count", { stat = "Sum" }],
[".", "HTTPCode_Target_4XX_Count", { stat = "Sum" }],
[".", "HTTPCode_Target_5XX_Count", { stat = "Sum" }]
]
view = "timeSeries"
region = var.aws_region
title = "HTTP Response Codes"
period = 300
}
},
{
type = "log"
properties = {
query = "SOURCE '${aws_cloudwatch_log_group.ecs.name}' | fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 20"
region = var.aws_region
title = "Recent Errors"
}
}
]
})
}
出力の追加
# terraform/outputs.tf に追加
# 監視関連の出力
output "cloudwatch_dashboard_url" {
description = "CloudWatch Dashboard URL"
value = "https://console.aws.amazon.com/cloudwatch/home?region=${var.aws_region}#dashboards:name=${aws_cloudwatch_dashboard.main.dashboard_name}"
}
output "xray_service_map_url" {
description = "X-Ray Service Map URL"
value = var.enable_xray_tracing ? "https://console.aws.amazon.com/xray/home?region=${var.aws_region}#/service-map" : ""
}
output "sns_topic_arn" {
description = "SNS Topic ARN for alarms"
value = aws_sns_topic.alarms.arn
}
output "alb_logs_bucket" {
description = "ALB Access Logs S3 Bucket"
value = var.enable_alb_access_logs ? aws_s3_bucket.alb_logs[0].id : ""
}
terraform.tfvarsの設定
# terraform/terraform.tfvars に追加
# ALBアクセスログを有効化
enable_alb_access_logs = true
# X-Rayトレーシングを有効化
enable_xray_tracing = true
# アラーム閾値
cpu_utilization_threshold = 80
memory_utilization_threshold = 80
error_rate_threshold = 5
以下は環境変数
# .env 追記
# アラートを送信するメールアドレスを設定します
[email protected]
リソースを作成
Terraformコンテナ内で以下のコマンドを実行します。
# terraformディレクトリへ移動
cd terraform
# 実行計画の確認
terraform plan
# リソースの作成
terraform apply
SNSトピックのメール購読を設定した場合、確認メールが届きます。メール内のリンクをクリックして購読を確認してください。
作成結果の確認
# CloudWatch Dashboard URLの確認
terraform output cloudwatch_dashboard_url
# X-Ray Service Map URLの確認
terraform output xray_service_map_url
# ALBログバケットの確認
terraform output alb_logs_bucket
動作確認
以下、一定のトラフィックがないと正確な確認ができない場合があります。
現場で試す場合はSTG環境などで収集してから試してみましょう。とりあえず、学習段階では管理コンソールからリソースが適切に作られていることを確認し、慣れないうちはトラブルシューティングの確認や当リポジトリのコードをAIに喰わせるなどして何が原因かを特定しましょう。
CloudWatch Dashboardの確認
出力されたURLにアクセスし、ダッシュボードでメトリクスが表示されることを確認します。
# ダッシュボードURLを取得して開く
terraform output -raw cloudwatch_dashboard_url
期待される表示内容
- ECS Resource Utilization: CPU/メモリ使用率のグラフ
- ALB Performance: レスポンスタイムとリクエスト数
- HTTP Response Codes: ステータスコード別の集計
- Recent Errors: 直近のエラーログ
Log Insightsでのログ分析
CloudWatch Logs Insightsで分析クエリを実行します。
# エラーログの検索
aws logs start-query \
--log-group-name $(terraform output -raw cloudwatch_log_group_name) \
--start-time $(date -u -d '1 hour ago' +%s) \
--end-time $(date +%s) \
--query-string 'fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 20'
# クエリ結果の取得(上記コマンドで返されたqueryIdを使用)
aws logs get-query-results --query-id <QUERY_ID>
ALBアクセスログの確認
S3バケットにログが保存されていることを確認します。
# アクセスログファイルの一覧
aws s3 ls s3://$(terraform output -raw alb_logs_bucket)/alb/ --recursive | head -10
X-Rayトレースの確認
X-Rayサービスマップとトレース情報を確認します。
# サービスマップの統計情報取得
aws xray get-service-graph\
--start-time $(date -u -d '5 minutes ago' '+%Y-%m-%dT%H:%M:%S') \
--end-time $(date -u '+%Y-%m-%dT%H:%M:%S') \
--query 'Services[*].[ServiceName,Type,State]' \
--output table
# トレースサマリーの取得
aws xray get-trace-summaries \
--start-time $(date -u -d '5 minutes ago' +%s) \
--end-time $(date +%s) \
--query 'TraceSummaries[0:5].[Id,Duration,ResponseTime]' \
--output table
ブラウザでService Mapを確認
terraform output -raw xray_service_map_url
アラームの動作確認
設定したアラームが正しく動作することを確認します。
# アラームの状態確認
# PROJECT_NAMEやENVIRONMENTはそれぞれの環境に合わせて設定してください。
aws cloudwatch describe-alarms \
--alarm-names \
"${PROJECT_NAME}-${ENVIRONMENT}-ecs-cpu-high" \
"${PROJECT_NAME}-${ENVIRONMENT}-ecs-memory-high" \
"${PROJECT_NAME}-${ENVIRONMENT}-alb-unhealthy" \
--query 'MetricAlarms[*].[AlarmName,StateValue,StateReason]' \
--output table
アラームのテスト(CPU使用率を意図的に上げる)
# ECSタスクに負荷をかけるテスト
ALB_DNS=$(terraform output -raw alb_dns_name)
for i in {1..100}; do
curl -s http://$ALB_DNS/api/users &
done
wait
# アラーム状態の確認(数分後)
aws cloudwatch describe-alarms \
--alarm-name-prefix "${PROJECT_NAME}-${ENVIRONMENT}" \
--query 'MetricAlarms[?StateValue!=`OK`].[AlarmName,StateValue]' \
--output table
パフォーマンス分析の実践
Container Insightsメトリクスの分析
# ECSサービスのCPU使用率推移
START_TIME=$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) && END_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) && echo "Start: $START_TIME" && echo "End: $END_TIME" && aws cloudwatch get-metric-statistics --namespace AWS/ECS --metric-name CPUUtilization --dimensions Name=ServiceName,Value=$(terraform output -raw ecs_service_name) Name=ClusterName,Value=$(terraform output -raw ecs_cluster_id) --start-time "$START_TIME" --end-time "$END_TIME" --period 300 --statistics Average Maximum --query 'Datapoints[*].[Timestamp,Average,Maximum]' --output table
VPC Flow Logsでのトラフィック分析
# トップトーカー(最も通信量の多いIPアドレス)の特定
aws logs start-query \
--log-group-name $(terraform output -raw vpc_flow_logs_group_name) \
--start-time $(date -u -d '1 hour ago' +%s) \
--end-time $(date +%s) \
--query-string 'stats sum(bytes) as TotalBytes by srcaddr | sort TotalBytes desc | limit 10'
# 拒否されたトラフィックの分析
aws logs start-query \
--log-group-name $(terraform output -raw vpc_flow_logs_group_name) \
--start-time $(date -u -d '1 hour ago' +%s) \
--end-time $(date +%s) \
--query-string 'filter action = "REJECT" | stats count(*) by dstport | sort count desc'
トラブルシューティング
アラームが発動しない場合
確認項目 | 確認コマンド | 対処方法 |
---|---|---|
SNS購読確認 | aws sns list-subscriptions-by-topic --topic-arn $(terraform output -raw sns_topic_arn) |
PendingConfirmationの場合はメール確認 |
メトリクスデータ | aws cloudwatch list-metrics --namespace AWS/ECS --metric-name CPUUtilization |
メトリクスが存在しない場合はContainer Insights設定確認 |
アラーム履歴 | aws cloudwatch describe-alarm-history --alarm-name <ALARM_NAME> --max-records 5 |
閾値設定の見直し |
X-Rayトレースが表示されない場合
確認項目 | 確認コマンド | 対処方法 |
---|---|---|
VPCエンドポイント | aws ec2 describe-vpc-endpoints --filters Name=service-name,Values=com.amazonaws.*.xray |
エンドポイントが作成されているか確認 |
IAM権限 | aws iam get-role-policy --role-name $(terraform output -raw ecs_task_role_arn | cut -d/ -f2) --policy-name <POLICY_NAME> |
X-Ray権限が付与されているか確認 |
サンプリングルール | aws xray get-sampling-rules |
fixed_rateを一時的に1.0に変更してテスト |
アプリログ | aws logs tail $(terraform output -raw cloudwatch_log_group_name) --follow --filter-pattern "xray" |
X-Ray SDKのエラーメッセージ確認 |
ALBログが出力されない場合
# S3バケットポリシーの確認
aws s3api get-bucket-policy --bucket $(terraform output -raw alb_logs_bucket) | jq -r .Policy | jq .
# ALBのログ設定確認
aws elbv2 describe-load-balancer-attributes \
--load-balancer-arn $(terraform output -raw alb_arn) \
--query 'Attributes[?Key==`access_logs.s3.enabled`]'
メトリクスが表示されない場合
# Container Insightsの設定確認
aws ecs describe-clusters \
--clusters $(terraform output -raw ecs_cluster_id) \
--query 'clusters[0].settings'
# 手動でContainer Insightsを有効化
aws ecs put-cluster-settings \
--cluster $(terraform output -raw ecs_cluster_id) \
--name containerInsights \
--value enabled
運用時のベストプラクティス
ログ分析の定期実行
本番運用では、定期的にログを分析してシステムが正常に稼働しているかどうかを確認しておきましょう
# 週次レポート用のスクリプト例
#!/bin/bash
# 過去1週間のエラー率を計算
START_TIME=$(date -u -d '7 days ago' +%s)
END_TIME=$(date +%s)
echo "=== 週次システムレポート ==="
echo "期間: $(date -d @$START_TIME) - $(date -d @$END_TIME)"
# エラーログの集計
aws logs start-query \
--log-group-name $(terraform output -raw cloudwatch_log_group_name) \
--start-time $START_TIME \
--end-time $END_TIME \
--query-string 'stats count() by bin(5m) | sort @timestamp'
# ALBのエラー率
aws cloudwatch get-metric-statistics \
--namespace AWS/ApplicationELB \
--metric-name HTTPCode_Target_5XX_Count \
--dimensions Name=LoadBalancer,Value=$(terraform output -raw alb_arn | cut -d/ -f2-) \
--start-time $(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 86400 \
次のステップ
次回は、CI/CDパイプライン構築を行います。
- GitHub ActionsによるCI/CDパイプライン
- OIDCを使用した安全なAWS認証
- 自動テストとデプロイの設定
- ブランチ戦略とデプロイフロー
- セキュリティスキャンの統合