【CDK】CloudWatch AlarmでEC2インスタンスのCPU使用率を監視し、SNSでEメール通知を受けとる

2024.06.01

リテールアプリ共創部のるおんです。

最近はCDKでのインフラ構築にはまっています。書き慣れた言語でインフラ構築をできるのはいいですよね。

今回は、EC2インスタンスが特定の使用率を超えたらCloudWatch Alarmを使用して、SNSからEメールに対して通知をする機能をCDKを使って実装してみました。使用した言語はTypeScriptです。

CloudWatch Alarmとは

CloudWatch Alarmは、Amazon CloudWatchの機能の一つで、特定のメトリクスが設定した閾値を超えた場合にアラームを発生させることができます。

これにより、システムの異常を迅速に検知し、適切な対応を取ることができます。

参考:Amazon CloudWatch でのアラームの使用

全体像

今回は以下の構成をAWS CDKを用いてデプロイしたいと思います。

EC2のCPU使用率をCloudWatchで監視し、異常を検知したらCloudWatch AlarmがSNSを通じてemailを送信するというシンプルな構成です。

今回は検証のため、Alarmが発生するCPU使用率の閾値を、低めの20%として設定します。

CDKを書いてみる

今回は、すでに対象のEC2が存在することを前提に、CloudWatch Alarmと、SNSのコードを記述していきます。また、TypeScriptが使用できてAWS CDKを用いて手元のマシンからデプロイができることを前提に進めていきます。

初めてCDKを触るという方はこちらを参考に環境構築を行なってください。

実装

まず、プロジェクトを作成してCDKを開始します。

mkdir cdk_sample
cd cdk_sample
cdk init app --language typescript

CDKが構築できたら、lib/cdk_sample-stack.tsに以下のコードを記述します。

import * as cdk from 'aws-cdk-lib';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import * as actions from 'aws-cdk-lib/aws-cloudwatch-actions';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';
import { Construct } from 'constructs';

export class CdkSampleStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // SNSトピックの作成
    const topic = new sns.Topic(this, 'Topic', {
      displayName: 'EC2 CPU Alarm Topic',
    })
    // メールアドレスをSNSトピックにサブスクライブ
    topic.addSubscription(new subscriptions.EmailSubscription('your_email@example.com'));

    // 既存のEC2インスタンスIDを指定
    const instanceId = 'i-xxxxxxxxxxxxxxx';

    // CloudWatchアラームを作成
    const alarm = new cloudwatch.Alarm(this, 'CpuUtilizationAlarm', {
      metric: new cloudwatch.Metric({
        namespace: 'AWS/EC2',
        metricName: 'CPUUtilization',
        dimensionsMap: { InstanceId: instanceId },
        period: cdk.Duration.minutes(1),
        statistic: 'Average',
      }),
      threshold: 20,
      evaluationPeriods: 5,
      datapointsToAlarm: 3
    });

    // CloudWatchアラームにアクションを追加
    alarm.addAlarmAction(new actions.SnsAction(topic));
  }
}

解説

それではこのコードについて簡単に解説します。

 // SNSトピックの作成
const topic = new sns.Topic(this, 'Topic', {
displayName: 'EC2 CPU Alarm Topic',
})
// メールアドレスをSNSトピックにサブスクライブ
topic.addSubscription(new subscriptions.EmailSubscription('your_email@example.com'));

まずここでは、SNSトピックを作成し、指定したメールアドレスをSNSトピックにサブスクライブしています。このトピックは、CloudWatchアラームが発生した際に通知を送るために使用されます。

    // 既存のEC2インスタンスIDを指定
    const instanceId = 'i-xxxxxxxxxxxxxxx';

    // CloudWatchアラームを作成
    const alarm = new cloudwatch.Alarm(this, 'CpuUtilizationAlarm', {
      metric: new cloudwatch.Metric({
        namespace: 'AWS/EC2',
        metricName: 'CPUUtilization',
        dimensionsMap: { InstanceId: instanceId },
        period: cdk.Duration.minutes(1),
        statistic: 'Average',
      }),
      threshold: 20,
      evaluationPeriods: 5,
      datapointsToAlarm: 3
    });

    // CloudWatchアラームにアクションを追加
    alarm.addAlarmAction(new actions.SnsAction(topic));

次に、ここではCloudWatchアラームを作成しています。このアラームは、指定したEC2インスタンスのCPU使用率が20%を超えた場合に発生します。1分単位で評価します。 metricNameCPUUtilizationとすることでCPU使用率を監視するようにしています。またdimensionsMapに対象のインスタンスIDを指定します。thresholdには閾値を指定します。

evaluationPeriodsを5に、datapointsToAlarmを3に指定するようにすることで、5回の評価のうち、3回が閾値を超えたらAlarmが発生するようにしています。 period を1分に指定しているので、今回の場合は 5分のうち3分間閾値を超えたらAlarmが発生します。こうすることで、より信頼性の高いアラーム設定が可能となります。

その他、プロパティについては、公式ドキュメントを参考にしてみてください。

そして最後に、作成したCloudWatch Alarmに対してSNS通知のアクションを渡しています。

デプロイ

スタックをデプロイします

cdk deploy

デプロイが完了したら、正しくリソースが作成されていることを確認します。

また、指定したメールアドレスにSNSのサブスクリプション確認メールが届くので、Confirm subscriptionと書いてあるリンクをクリックしてサブスクリプションを承認してください。

動作確認

それでは動作確認をしてみましょう。本当に一定の使用率を超えるとEメールが届くのでしょうか。

事前に用意しておいたEC2インスタンスにログインし、CPU使用率を高めます。

stressコマンドを使用してサーバーに負荷をかけます。stressコマンドをインストールして実行します。

sudo yum install -y stress
stress --cpu 8 --timeout 300

これでCPU使用率を上げることができます。 実際に、マネジメントコンソール上で以下のように閾値を超えてAlarm状態になっているのが確認できると思います。

また、指定したメールアドレスに通知が届いていることを確認します。

以上で動作確認は終了です。

最後に

今回は、CloudWatch+SNSの構成をAWS CDKでデプロイしてみました。

参考になりましたら幸いです。

参考