【CloudFormation】AWSマルチAZ3層アーキテクチャの構築_CloudWatch・SNS

皆様、お世話になっております。鈴木と申します。
今回はAWS CloudFormationを使用して、EC2のCloudWatchアラームを設定し、SNS通知を行う構成を作成します。

1.目次

目次はこちら

2.要件

  • EC2のメモリ・ディスク・CPU使用率を監視して80%と90%にしきい値を設定。
    超えた場合にSNSでアラート通知を行う。
  • Apacheのエラーログを収集してエラーログの検出時にSNS通知するように設定する。
  • EC2インスタンスにエージェントをインストールする際にユーザーデータを使用して設定するようにする。

3.使用サービスについて

3-1.CloudWatchについて

Amazon CloudWatchは、AWS(Amazon Web Services)が提供するモニタリングおよび管理サービスであり、AWSリソースとアプリケーションのパフォーマンスと運用データを収集し、視覚化するために使用されます。以下の表で、CloudWatchの主要な機能と利点を簡単にまとめます。

機能 説明
モニタリング AWSリソース(EC2インスタンス、RDSデータベース、S3バケットなど)のメトリクスをリアルタイムで監視。
ログ管理 アプリケーションやシステムのログデータを収集、モニタリング、分析するためのCloudWatch Logs。
アラーム設定 特定の条件を満たした場合に通知を受け取るためのアラームを設定。閾値を超えるとアラートを送信。
ダッシュボード カスタマイズ可能なダッシュボードでメトリクスを視覚化し、一目でシステムの状態を把握。
イベント管理 CloudWatch Eventsを使用して、システム変更やスケジュールされたイベントに基づいてAWSリソースを自動化。
メトリクスのカスタマイズ ユーザー定義メトリクスを収集して監視。アプリケーション固有のメトリクスもカスタムメトリクスとして取り扱い可能。
ログインサイトの統合 Amazon Elasticsearch ServiceやAWS Lambdaと連携して、ログデータの検索やリアルタイム処理を実現。
アクティビティの追跡 CloudTrailと連携してAWSアカウントのアクティビティを追跡し、セキュリティとコンプライアンスの向上。
コスト管理 リソース使用状況を監視して、コスト最適化とリソース利用の効率化をサポート。
メトリクスの保存 長期間のメトリクスデータを保存して、履歴データを基にしたトレンド分析やキャパシティプランニングを可能に。

CloudWatchを活用することで、システムの可視性が向上し、問題の迅速な検出と対応が可能になります。また、リソースの効率的な利用とコスト削減にも貢献します。

3-2.Amazon SNSの概要

Amazon SNS(Simple Notification Service)は、AWSが提供するフルマネージドなメッセージングサービスで、アプリケーション間やデバイス間でメッセージを迅速かつ信頼性高く送信するために使用されます。以下の表で、SNSの主要な機能と利点を簡単にまとめます。

機能 説明
メッセージ配信 メッセージを複数の購読者(メール、SMS、HTTP/HTTPSエンドポイント、SQSキューなど)に配信。
トピックベースの送信 トピックを使用して、複数の購読者に対して効率的にメッセージをブロードキャスト。
メッセージのフィルタリング メッセージ属性を使用して、特定の条件に一致するメッセージのみを購読者に配信。
モバイルプッシュ通知 iOS、Android、Kindleなどのモバイルデバイスにプッシュ通知を送信。
スケーラビリティ 大量のメッセージを同時に送信可能。高スループットを持つシステムに対応。
信頼性と可用性 メッセージの冗長保存と複数のデリバリ試行により、高い信頼性と可用性を提供。
セキュリティ メッセージの暗号化とIAMポリシーによるアクセス制御で、データのセキュリティを確保。
統合の容易さ AWS Lambda、Amazon S3、Amazon EC2など、他のAWSサービスと容易に統合可能。
コスト効率 実際に送信したメッセージの数に基づく課金モデルで、コストを最適化。
グローバルな配信 世界中のユーザーに対して迅速にメッセージを配信可能。AWSのグローバルインフラストラクチャを利用。

Amazon SNSを活用することで、リアルタイムな通知システムを構築し、ユーザーとのコミュニケーションやシステム間の連携を強化することができます。

4.構成図

file

5.EC2設定

CloudWatch・SNSの構築の前にEC2インスタンスにエージェントをインストールするところからスタートします。
構築の概要は下記の通りです。
file

5-1.前提

  • IAMロール(CloudWatchAgentAdminPolicy/CloudWatchAgentServerPolicy)を付与

5-2.初期設定時

初回はウィザードを使用して設定すると間違いないです。

# CloudWatchエージェントのインストール
sudo yum install amazon-cloudwatch-agent

# ウィザードを使用して初期設定
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

こちらを使用して必要なものを選択して作成しましょう。
ウィザードの中でSSMパラメータストアに保存するかの質問があります。

Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:
1

こちらがですが、今回はyesにしましょう。
私は今回デフォルトの「AmazonCloudWatch-linux」で設定しております。

ちなみに、私の設定ファイルは以下の通りで、メモリ・ディスク使用率の取得とエラーログの収集が含まれています。
※CPU使用率はエージェントをインストールすればデフォルトで収集できます。

{
  "agent": {
    "metrics_collection_interval": 60,
    "run_as_user": "root"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/httpd/error_log",
            "log_group_name": "ApacheErrorLogs_{instance_id}",
            "log_stream_name": "{instance_id}",
            "log_group_class": "STANDARD",
            "retention_in_days": -1
          }
        ]
      }
    }
  },
  "metrics": {
    "aggregation_dimensions": [
      ["InstanceId"]
    ],
    "append_dimensions": {
      "AutoScalingGroupName": "${aws:AutoScalingGroupName}",
      "ImageId": "${aws:ImageId}",
      "InstanceId": "${aws:InstanceId}",
      "InstanceType": "${aws:InstanceType}"
    },
    "metrics_collected": {
      "disk": {
        "measurement": ["used_percent"],
        "metrics_collection_interval": 60,
        "resources": ["*"]
      },
      "mem": {
        "measurement": ["mem_used_percent"],
        "metrics_collection_interval": 60
      }
    }
  }
}

ここまでできたら、以下のコマンドでSSMパラメータストアの情報を読み取って起動します。

# パラメータストアに保存した設定を読み込んで起動
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c ssm:AmazonCloudWatch-linux -s

これで一通りの流れが完了です。メモリ等読み取れるようになります。

5-2.EC2の2台目以降のユーザーデータ

一度作成してSSMパラメータストアに情報がある限りは2台目以降のインスタンスの立ち上げはもっと簡単にメトリクスを収集できるようになります。

# CloudWatchエージェントのインストール
sudo yum install amazon-cloudwatch-agent

# パラメータストアに保存した設定を読み込んで起動
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c ssm:AmazonCloudWatch-linux -s

これだけでメトリクスを収集できるようになります。

6.CloudWatch.SNSソースコード(CPU・ディスク・メモリ使用率)

YAML形式にて記述しております。

AWSTemplateFormatVersion: '2010-09-09'
Description: >-
  CloudFormation template to create SNS notifications for EC2 metrics (CPU, Memory, Disk) exceeding thresholds.

Resources:
  NotificationTopic:
    Type: "AWS::SNS::Topic"
    Properties:
      DisplayName: "EC2 Monitoring Notifications"
      Subscription:
        - Protocol: email
          Endpoint: !Ref SNSEmail

  CloudWatchAlarmCPUWarning:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "naoki-web01-CPUUtilization-Warning"
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      MetricName: "CPUUtilization"
      Namespace: "AWS/EC2"
      Period: 300
      Statistic: "Average"
      Threshold: 80
      AlarmDescription: "Alarm when CPU usage exceeds 80%"
      AlarmActions:
        - !Ref NotificationTopic
      Dimensions:
        - Name: "InstanceId"
          Value: !Ref InstanceId

  CloudWatchAlarmCPUCritical:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "naoki-web01-CPUUtilization-Critical"
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      MetricName: "CPUUtilization"
      Namespace: "AWS/EC2"
      Period: 300
      Statistic: "Average"
      Threshold: 90
      AlarmDescription: "Alarm when CPU usage exceeds 90%"
      AlarmActions:
        - !Ref NotificationTopic
      Dimensions:
        - Name: "InstanceId"
          Value: !Ref InstanceId

  CloudWatchAlarmMemoryWarning:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "naoki-web01-mem-used-percent-Warning"
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      MetricName: "mem_used_percent"
      Namespace: "CWAgent"
      Period: 300
      Statistic: "Average"
      Threshold: 80
      AlarmDescription: "Alarm when memory usage exceeds 80%"
      AlarmActions:
        - !Ref NotificationTopic
      Dimensions:
        - Name: "InstanceId"
          Value: !Ref InstanceId
        - Name: "ImageId"
          Value: !Ref ImageId
        - Name: "InstanceType"
          Value: !Ref InstanceType

  CloudWatchAlarmMemoryCritical:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "naoki-web01-mem-used-percent-Critical"
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      MetricName: "mem_used_percent"
      Namespace: "CWAgent"
      Period: 300
      Statistic: "Average"
      Threshold: 90
      AlarmDescription: "Alarm when memory usage exceeds 90%"
      AlarmActions:
        - !Ref NotificationTopic
      Dimensions:
        - Name: "InstanceId"
          Value: !Ref InstanceId
        - Name: "ImageId"
          Value: !Ref ImageId
        - Name: "InstanceType"
          Value: !Ref InstanceType

  CloudWatchAlarmDiskWarning:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "naoki-web01-Disk-80percent-used"
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      MetricName: "disk_used_percent"
      Namespace: "CWAgent"
      Period: 300
      Statistic: "Average"
      Threshold: 80
      AlarmDescription: "Alarm when disk usage exceeds 80%"
      AlarmActions:
        - !Ref NotificationTopic
      Dimensions:
        - Name: "path"
          Value: "/"     
        - Name: "InstanceId"
          Value: !Ref InstanceId     
        - Name: "ImageId"
          Value: !Ref ImageId
        - Name: "InstanceType"
          Value: !Ref InstanceType
        - Name: "device"
          Value: !Ref Device    
        - Name: "fstype"
          Value: !Ref FilesystemType 

  CloudWatchAlarmDiskCritical:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "naoki-web01-Disk-90percent-used"
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      MetricName: "disk_used_percent"
      Namespace: "CWAgent"
      Period: 300
      Statistic: "Average"
      Threshold: 90
      AlarmDescription: "Alarm when disk usage exceeds 90%"
      AlarmActions:
        - !Ref NotificationTopic
      Dimensions:
        - Name: "path"
          Value: "/"     
        - Name: "InstanceId"
          Value: !Ref InstanceId     
        - Name: "ImageId"
          Value: !Ref ImageId
        - Name: "InstanceType"
          Value: !Ref InstanceType
        - Name: "device"
          Value: !Ref Device            
        - Name: "fstype"
          Value: !Ref FilesystemType

Outputs:
  NotificationTopicArn:
    Description: "SNS Topic ARN"
    Value: !Ref NotificationTopic

7.ソースコード詳細(CPU・ディスク・メモリ使用率)

このテンプレートは、EC2インスタンスのCPU、メモリ、およびディスク使用率が80%、90%の閾値を超えた場合にSNS通知を作成します。

7-1.SNS

プロパティ名 内容 説明
Type AWS::SNS::Topic リソースのタイプ
DisplayName EC2 Monitoring Notifications SNSトピックの表示名
Subscription SNSトピックに設定されるサブスクリプション
Protocol email サブスクリプションのプロトコル(ここではメール)
Endpoint !Ref SNSEmail サブスクリプション先のメールアドレス

7-2.アラート設定

プロパティ名 説明
Type リソースの種類
AlarmName アラームの名前
ComparisonOperator 比較演算子
EvaluationPeriods 評価期間の数
MetricName 監視するメトリクスの名前
Namespace メトリクスの名前空間
Period メトリクスを収集する期間(秒単位)
Statistic 統計方法
Threshold アラームをトリガーする閾値
AlarmDescription アラームの説明
AlarmActions アラームがトリガーされたときに実行されるアクション
Dimensions メトリクスの次元 (パスやAMI IDなど)

8.CloudWatch.SNSソースコード(エラーログ用)

AWSTemplateFormatVersion: '2010-09-09'
Description: >-
  CloudFormation template to create SNS notifications for Apache error logs detected in CloudWatch Logs.

Resources:
  # SNSトピックの作成
  SNSTopic:
    Type: 'AWS::SNS::Topic'
    Properties:
      TopicName: 'ApacheErrorLogsTopicweb01'

  # SNSトピックにメールサブスクリプションの作成
  SNSSubscription:
    Type: 'AWS::SNS::Subscription'
    Properties:
      Protocol: 'email'
      Endpoint: !Ref EmailAddress
      TopicArn: !Ref SNSTopic

  # CloudWatch Logs Metric Filterの作成
  MetricFilter:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '?error ?Error ?ERROR'
      LogGroupName: !Ref LogGroupName
      MetricTransformations:
        - MetricValue: '1'
          MetricNamespace: !Ref MetricNamespace
          MetricName: !Ref MetricName

  # CloudWatch アラームの作成
  Alarm:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: 'Alarm when error logs are detected'
      MetricName: !Ref MetricName
      Namespace: !Ref MetricNamespace
      Statistic: 'Sum'
      Period: '300'  # 5分間隔で集計
      EvaluationPeriods: '1'
      Threshold: '1'
      ComparisonOperator: 'GreaterThanOrEqualToThreshold'
      AlarmActions:
        - Ref: 'SNSTopic'
      OKActions:
        - Ref: 'SNSTopic'
      InsufficientDataActions:
        - Ref: 'SNSTopic'

9.CloudWatch.SNSソースコード詳細(エラーログ用)

9-1.SNS

プロパティ名 内容 説明
Type AWS::SNS::Topic リソースのタイプ
TopicName ApacheErrorLogsTopicweb01 SNSトピックの名前
Type AWS::SNS::Subscription リソースのタイプ
Protocol email サブスクリプションのプロトコル(メール)
Endpoint !Ref EmailAddress メールサブスクリプション先のメールアドレス
TopicArn !Ref SNSTopic SNSトピックのARN

9-2.メトリクスフィルター設定

プロパティ名 内容 説明
Type AWS::Logs::MetricFilter リソースのタイプ
FilterPattern !Ref FilterPattern ログフィルタリングのパターン
LogGroupName !Ref LogGroupName CloudWatchロググループの名前
MetricTransformations MetricValue: '1', MetricNamespace: !Ref MetricNamespace, MetricName: !Ref MetricName メトリクス変換の設定

9-3.アラート設定

プロパティ名 内容 説明
Type AWS::CloudWatch::Alarm リソースのタイプ
AlarmDescription ‘Alarm when error logs are detected’ アラームの説明
MetricName !Ref MetricName メトリクスの名前
Namespace !Ref MetricNamespace メトリクスの名前空間
Statistic ‘Sum’ 統計方法
Period ‘300’ メトリクスを収集する期間(秒単位)
EvaluationPeriods ‘1’ 評価期間の数
Threshold ‘1’ アラームをトリガーする閾値
ComparisonOperator ‘GreaterThanOrEqualToThreshold’ 比較演算子
AlarmActions Ref: 'SNSTopic' アラームがトリガーされたときに実行されるアクション
OKActions Ref: 'SNSTopic' アラームがOK状態になったときのアクション
InsufficientDataActions Ref: 'SNSTopic' データ不足時のアクション

10.検証

10-1.検証内容

  • メモリ使用率を80%以上にしてアラート通知をする
  • エラーログを入力してアラート通知をする

10-2.ディスク使用率

今回はディスク使用率80%の閾値を例にとって、アラート通知を行います。
まずはEC2(Amazon Linux2023)にてストレスコマンドをインストールします。

# stressコマンドのインストール
sudo yum install -y epel-release
sudo yum install -y stress

続いて現在のメモリ使用率を確認しつつ負荷をかけてメモリ使用率を上昇させます。

free -h

file
上記の情報から、約730Miの負荷をかけることでメモリ使用率が80%を超えることがわかります。
下記コマンドで負荷をかけていきます。

#バックグラウンドで500Mの負荷をかける
stress -m 1 --vm-bytes 500M --vm-hang 0 &

file
これで約83%のメモリ負荷をかけられていることがわかります。
CloudWatchダッシュボードでもメモリ負荷がかけられ、アラートが出ていることが確認できます。
file

さらにSNSでもアラートが発報されていることを確認できました。
file

最後に実行中のjobsを下記で停止しましょう。

#jobの確認
jobs

#jobの削除(数字は上記を参照)
kill %1

10-3.エラーログ

今回設定ファイルで参照しているファイルが/var/log/httpd/error_logになります。
メトリクスでerrorが出た際にSNS通知するようにしているのでこのファイルに直接的なエラーメッセージを追加してみます。

echo "error" | sudo tee -a /var/log/httpd/error_log

下記にerrorと書き込まれていることを確認できました。
file

ダッシュボードでも確認できました。
file

SNSでも約2分後あたりに発報されておりました。
file

11.感想

CloudWatchエージェントの設定にはかなり苦労しましたが、SSMパラメータストアを使用した方法を試したところ、すぐに成功しました。この経験から、まだまだ知識不足だと感じています。次回はこの構築の最終投稿として、Healthイベント通知についてお話しする予定です。よろしくお願いします。

Last modified: 2024-08-07

Author