【AWSハンズオン】第11回 監視とログ設定

【AWSハンズオン】第11回 監視とログ設定

CloudWatch Container Insights、VPC Flow Logs、ALB Access Logs、AWS X-Rayを設定し、アプリケーションの可視化と監視体制を構築します。パフォーマンス分析とトラブルシューティングに必要な監視基盤を整備していきましょう。

AWS #AWS#ハンズオン#terraform

【AWSハンズオン】第11回 監視とログ設定

サムネイル

CloudWatch Container Insights、VPC Flow Logs、ALB Access Logs、AWS X-Rayを設定し、アプリケーションの可視化と監視体制を構築します。パフォーマンス分析とトラブルシューティングに必要な監視基盤を整備していきましょう。

更新日: 8/13/2025

今回作業対象のブランチ

前提条件

  • 第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認証
  • 自動テストとデプロイの設定
  • ブランチ戦略とデプロイフロー
  • セキュリティスキャンの統合

検索

検索条件に一致する記事が見つかりませんでした