AWSで監視してアラートをメール送信する（4選）

# 監視の種類

- WAFトリガーの監視（ファイアウォール監視）
- awslogsトリガーの監視（サーバーのログ監視）
- CodePipelineトリガーの監視（デプロイ監視）
- CloudWatchアラームの監視（サーバーの負荷監視）
 
## WAFトリガーの監視

WAFログを監視してリクエストがブロックされたらメッセージ送信する。

#### 監視の流れ

WAF Logs→KinesisFirehose→S３→Lambda→SNS→Eメール
　　　　　　　　　　　　　　　　　　　　　　　→CloudWatchLogs

#### 監視内容

WAFアクション「BLOCK」だったらメッセージ送信。
（WAFルールが「AWS-AWSManagedRulesAnonymousIpList」の場合、メッセージ送信しない。）

#### 作る

※設定値を記載していない箇所はデフォルト値を使用している。

##### SNS

-  waf-monitoring-publish-sns
    - タイプ：スタンダード
    -  サブスクリプション
        - プロトコル：Eメール
        - エンドポイント：```waf@e2info.com```

エンドポイントに指定したメールアドレス宛にメールが届くので「Confirm subscription」をクリック。
サブスクリプションのステータスが「保留中の確認」となっていたのが「確認済み」となればOK

##### S3バケット

- aws-waf-logs
    - 設定はデフォルトのままでいい。

##### Kinesis Data Firehose

- aws-waf-logs
    - Source：Direct PUT or other sources
    - S3 destination：aws-waf-logs
    - S3 buffer conditions：128 MiB or 900 seconds
    - S3 compression：GZIP

※バッファ間隔についてはテスト時は60秒にしても構わないが、本番運用時は900秒に設定する。

##### WAF

- Block-Waftest
    - ルール：/waftestにアクセスしたらブロック
    - Priority：0

作成後、Logging and metricsタブの「Logging」で「Edit logging」をクリック

- Logging details
    - Amazon Kinesis Data Firehose Delivery Stream
        - aws-waf-logs

##### Lamdba

- waf-monitoring-publish-sns
    - 一から作成
    - ランタイム：node.js 10.x

Lambda関数作成後、

- トリガーを追加。
    - S3バケットaws-waf-logs
    - イベントタイプ：PUT
    - サフィックス：.gzを指定

関数コードindex.jsに下記をペースト

```index.js
const aws = require("aws-sdk");
const s3 = new aws.S3();
const sns = new aws.SNS({region: 'ap-northeast-1'});
const zlib = require('zlib');

exports.handler = (event, context, callback) => {
    const params = {
        Bucket: process.env.S3_BUCKET,
        Key: event.Records[0].s3.object.key
    };
    s3.getObject(params, (err, getData) => {
        if (err) {
            callback(err);
            return;
        }

        const body = getData.Body;

        zlib.gunzip(body, (err, data) => {
            if (err) {
                callback(err);
                return;
            }

            // gzip展開したデータを分割
            const logs = data.toString("utf-8").split('\n');

            // 通知対象のログをフィルタリング
            const blockLogs = logs.filter(function (evt) {
                return evt.match(/BLOCK|COUNT/);
            }).filter(function (evt) {

                let jsonEvt = JSON.parse(evt);
                let evtCountry = jsonEvt.httpRequest.country;
                let evtHost = null;
                let evtUA = null;
                let evtUri = jsonEvt.httpRequest.uri;
                let evtClientIP = jsonEvt.httpRequest.clientIp;
                for (const header in jsonEvt.httpRequest.headers) {
                    if (jsonEvt.httpRequest.headers[header].name == 'Host') {
                        evtHost = jsonEvt.httpRequest.headers[header].value;
                    }
                    if (jsonEvt.httpRequest.headers[header].name == 'User-Agent') {
                        evtUA = jsonEvt.httpRequest.headers[header].value;
                    }
                }

                console.log(evtCountry + "/" + evtHost + "/" + evtUA + "/" + evtUri + "/" + evtClientIP);

                if (evtCountry != 'JP') {
                    console.log('Not Notify(Country):' + evtCountry);
                    return false;
                }

                // このIPアドレスに対するブロックは通知しない（完全一致）
                if (process.env.DONT_NOTIFY_IPADDRESSES && evtClientIP) {
                    const dont_nofity_ipaddresses = process.env.DONT_NOTIFY_IPADDRESSES.split(',');
                    for (var dont_nofity_ipaddress of dont_nofity_ipaddresses) {
                        if (dont_nofity_ipaddress.indexOf(evtClientIP) != -1) {
                            console.log('Not Notify(IP):' + evtClientIP);
                            return false;
                        }
                    }
                }

                // このUAに対するブロックは通知しない（
                if (process.env.DONT_NOTIFY_USERAGENTS && evtUA) {
                    if (evtUA.indexOf(process.env.DONT_NOTIFY_USERAGENTS) != -1) {
                        console.log('Not Notify(UA):' + evtUA);
                        return false;
                    }
                }

                // このホストに対するブロックは通知しない
                if (process.env.DONT_NOTIFY_HOSTS && evtHost) {
                    if (evtHost.indexOf(process.env.DONT_NOTIFY_HOSTS) != -1) {
                        console.log('Not Notify(Host):' + evtHost);
                        return false;
                    }
                }

                return true;

            }).filter(function (evt) {
                return !evt.match(/$^/);
            }).map(function (evt) {
                return evt;
            });
            
            console.log('blockLogs length:' + blockLogs.length);

            if (blockLogs.length == 0) {
                callback();
                return;
            }

            const subject = 'Notify From AWS WAF Logs';
            let payload = {default: ''};
            for (const logIndex in blockLogs) {
                const log = JSON.parse(blockLogs[logIndex]);

                // このルールは通知しない
                if (process.env.DONT_NOTIFY_RULES) {
                    if (log.terminatingRuleId.indexOf(process.env.DONT_NOTIFY_RULES) != -1) {
                        console.log('Not Notify(RULE):' + log.terminatingRuleId);
                        continue;
                    }
                }

                // BLOCK以外は通知しない
                if (log.action != 'BLOCK') {
                    console.log('Not Notify(Action is not BLOCK):' + log.action);
                    continue;
                }

                payload['default'] += log.terminatingRuleId;
                payload['default'] += '|';
                payload['default'] += log.httpRequest.clientIp;
                payload['default'] += '|';
                payload['default'] += log.httpRequest.country;
                payload['default'] += '|';
                for (const header in log.httpRequest.headers) {
                    if (log.httpRequest.headers[header].name == 'Host') {
                        payload['default'] += log.httpRequest.headers[header].value;
                    }
                }
                payload['default'] += '|';
                payload['default'] += log.httpRequest.uri;
                payload['default'] += '|';
                payload['default'] += log.httpRequest.httpMethod;
                payload['default'] += '|';
                payload['default'] += log.httpRequest.args;
                payload['default'] += '|';
                payload['default'] += log.httpRequest.httpVersion;
                payload['default'] += '\n';
                for (const header in log.httpRequest.headers) {
                    if (log.httpRequest.headers[header].name == 'User-Agent') {
                        payload['default'] += log.httpRequest.headers[header].value;
                    }
                }
                payload['default'] += '|';
                payload['default'] += log.action;
                payload['default'] += '\n';
                payload['default'] += '---';
                payload['default'] += '\n';
            }
            // payload['default'] += blockLogs.join('\n---\n');
            console.log('payload:' + JSON.stringify(payload));
            if (payload['default'] !== ''){
                sns.publish({
                    Subject: subject,
                    Message: JSON.stringify(payload),
                    MessageStructure: 'json',
                    TargetArn: process.env.SNS_ARN
                }, function (err, data) {
                    if (err) callback(err);
                    else callback(null, data);
                });
            }
            
            callback(null);
        });
    });
};
```

「Deploy」


- 環境変数の追加
    - DONT_NOTIFY_IPADDRESSES：空
    - DONT_NOTIFY_RULES：AWS-AWSManagedRulesAnonymousIpList
    - DONT_NOTIFY_USERAGENTS：空
    - S3_BUCKET：aws-waf-logs
    - SNS_ARN：作成したSNS`waf-monitoring-publish-sns`のARNをコピペ

- 基本設定
    - メモリ：256
    - タイムアウト：0分10秒

- IAM
    - Lambda関数`waf-monitoring-publish-sns`作成時にIAMロールが作成されているので、そのロールにアクセス権限を追加する
        - AmazonS3ReadOnlyAccess
        - AmazonSNSFullAccess

##### 動作確認
- ブラウザから対象のホスト/waftestにアクセス。403エラーが表示される。エンドポイントに指定したメールアドレスにメールが送信されればOK
- Cloud Watch Logs＞/aws/lambda/waf-monitoring-publish-snsにログが出力されていればOK



## awlogsトリガーの監視

#### 監視の流れ

awslogs→CloudWatchサブスクリプションフィルタ→Lambda→SNS→Eメール
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　→CloudWatchLogs

#### 監視内容

対象ログ出力内容に「ERRORまたはFATALまたはEXCEPTIONまたはErrorまたはFatalまたはException」が含まれていたらメッセージ送信。

#### 作る

※設定値を記載していない箇所はデフォルト値を使用している。

##### SNS

- monitoring-publish-sns
    - タイプ：スタンダード
    - サブスクリプション
        - プロトコル：Eメール
        - エンドポイント：```awslogs@e2info.com```

##### awslogsエージェント

参考：
[クイックスタート: 実行中の EC2 Linux インスタンスに CloudWatch Logs エージェントをインストールして設定する](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html)

サーバーにsshアクセスする

yumアップデート

```
sudo yum update -y
```

awslogsパッケージをインストール

```
sudo yum install -y awslogs
```

awscli.confで東京リージョンを指定

```
cd /etc/awslogs/
sudo vim awscli.conf

[default]
region = ap-northeast-1
```

awslogs.confでCloudWatchLogsに出力するログを指定（設定値は各自のサーバー設定に置き換えてください。）

```
[messages]
file = /var/log/messages
log_stream_name = {hostname}_messages
datetime_format = %b %d %H:%M:%S
log_group_name = /aws/ec2/messages

[httpd-access_log]
datetime_format = %d/%b/%Y:%H:%M:%S %z
file = /var/log/httpd/hoge-access_log
buffer_duration = 5000
log_stream_name = {hostname}_httpd_hoge-access-log
initial_position = start_of_file
log_group_name = /aws/ec2/hoge/apache/accesslog

[httpd-error_log]
datetime_format = %d/%b/%Y:%H:%M:%S %z
file = /var/log/httpd/hoge-error_log
buffer_duration = 5000
log_stream_name = {hostname}_httpd_hoge-error-log
initial_position = start_of_file
log_group_name = /aws/ec2/hoge/apache/errorlog

[laravel_log]
datetime_format = [%Y/%m/%d %H:%M:%S.%S]
file = /var/www/hoge/storage/logs/laravel*.log
buffer_duration = 5000
log_stream_name = {hostname}_laravel
initial_position = start_of_file
log_group_name = /aws/ec2/hoge/laravel
```

awslogs起動

```
sudo systemctl start awslogsd
```

awslogs再起動ON

```
sudo systemctl enable awslogsd.service
```

Cloud Watch Logs に```log_group_name```で指定した名前のロググループが作成されていればOK

##### Lambda

- monitoring-publish-sns
    - 一から作成
    - ランタイム：node.js 10.x

Lambda関数作成後、

- トリガーを追加
    - Cloud Watch Logs
        - 先程作成したロググループを選択

関数コードindex.jsに下記をペースト

```
var zlib = require('zlib');
var aws = require('aws-sdk');
var sns = new aws.SNS({ region: 'ap-northeast-1' });
exports.handler = function(input, context, callback) {
var data = Buffer.from(input.awslogs.data, 'base64');

console.log("リクエスト受信");

  zlib.gunzip(data, function(e, result) {
    if (e) {
      callback(e);
    } else {
      result = JSON.parse(result.toString('utf-8'));
      var logs = result['logEvents']
                     .filter(function(evt) { return evt['message'].match(/ERROR|FATAL|EXCEPTION|Error|Fatal|Exception/) ;})
                     .filter(function(evt) { return !evt['message'].match(/$^/) ;})
                     .map(function(evt) { return evt['message'] });

console.log('processing' + logs.length + '/' + result['logEvents'].length + ' events.');

      if (logs.length === 0) {
console.log("通知対象外");

        callback();
        return;
      }


      var logString = logs.join('\n---\n');

      // 指定文字列が含まれる場合は通知しない
      if (process.env.DONT_NOTIFY_STRING && logString) {
console.log("debug:DONT_NOTIFY_STRING1");
          const dont_nofity_strings = process.env.DONT_NOTIFY_STRING.split(',');
console.log("debug:DONT_NOTIFY_STRING2");
          for (var dont_nofity_string of dont_nofity_strings) {
console.log("debug:DONT_NOTIFY_STRING3:dont_nofity_string:" + dont_nofity_string);
              if (logString.indexOf(dont_nofity_string) != -1) {
console.log("debug:DONT_NOTIFY_STRING4:logString.indexOf(dont_nofity_string):" + logString.indexOf(dont_nofity_string));
                  console.log('Not Notify(DONT_NOTIFY_STRING)' + dont_nofity_string);
                  callback();
                  return;
              }
          }
      }


console.log("通知");

      var subject = 'Notify From CloudWatch Logs';
      var payload = { default: '' };
      payload['default'] += 'NotifyAt: ' + new Date() + '\n';
      payload['default'] += 'Log: ' + result['logGroup'] + ' - ' + result['logStream'] + '\n';
      payload['default'] += 'Filter: ' + result['subscriptionFilters'] + '\n';
      payload['default'] += 'Messages:\n';
      payload['default'] += logString;
      sns.publish({
        Subject: subject,
        Message: JSON.stringify(payload),
        MessageStructure: 'json',
        TargetArn: process.env.SNS_ARN
      }, function(err, data) {
        if (err) callback(err);
        else callback(null, data);
      });
    }
  });
};

```

「Deploy」

- 環境変数の追加
    - DONT_NOTIFY_STRING：Error: websocket: close 1006
    - SNS_ARN：作成したSMS`monitoring-publish-sns`のARNをコピペ

- 基本設定
    - メモリ：256
    - タイムアウト：0分10秒

- IAM
    - Lambda関数`monitoring-publish-sns`作成時にIAMロールが作成されているので、そのロールにポリシーを追加する。
        - AmazonSNSFullAccess

##### Cloud Watch Lambda サブスクリプションフィルタ

- Lambdaサブスクリプションフィルタ
    - /aws/ec2/messages
        - 送信先：monitoring-publish-sns
        - フィルタのパターン：?ERROR ?Error ?FATAL ?Fatal ?EXCEPTION ?Exception
        - フィルター名：LambdaStream_monitoring-publish-sns
    - /aws/ec2/hoge/apache/accesslog
        - 上と同じ
    - /aws/ec2/hoge/apache/errorlog
        - 上と同じ
    - /aws/ec2/hoge/laravel
        - 上と同じ

##### 動作確認

対象ファイルにechoコマンドでファイルに追記
フィルタパターン（?ERROR ?Error ?FATAL ?Fatal ?EXCEPTION ?Exception）を追記したときに、メッセージ送信されること

```
echo 追記する文字列 >> 書き込みたいファイル

// フィルタパターンテスト
echo Error test >> /var/log/httpd/hoge-error_log
echo ERROR test >> /var/log/httpd/hoge-error_log
echo Fatal test >> /var/log/httpd/hoge-error_log
echo FATAL test >> /var/log/httpd/hoge-error_log
echo Exception test >> /var/log/httpd/hoge-error_log
echo EXCEPTION test >> /var/log/httpd/hoge-error_log
echo Error test >> /var/log/messages
echo Error test >> /var/log/httpd/hoge-access_log
echo Error test >> /var/www/hoge/storage/logs/laravel-2021-02-22.log
```

フィルタパターンを対象ファイルに追記してメール送信されればOK
Cloud Wacth ロググループに```/aws/lambda/monitoring-publish-sns```が生成されていればOK

## CI_CDトリガーの監視

#### 監視の流れ

CodePipeline→SNS→Eメール

#### 監視内容

CodePipeline実行して、「リリース失敗」したらerrorメッセージ送信して「リリース成功」したらsuccessメッセージ送信する。

#### 作る

※CodePipelineリソースは事前に作成してあるものとする。
※設定値を記載していない箇所はデフォルト値を使用している。

##### SNS

- cicd-error-publish-sns
    - タイプ：スタンダート
    - サブスクリプション
        - プロトコル：Eメール
        - エンドポイント：```cicd-erro@e2info.com```
- cicd-success-publish-sns
    - タイプ：スタンダード
    - サブスクリプション
        - プロトコル：Eメール
        - エンドポイント：```cicd-success@e2info.com```

##### CodePipeline 通知ルール

- pipeline-success
    - 通知をトリガーするイベント
        - Pipeline execution：Succeeded
        - Manual approval：Succeeded
    - ターゲット
        - SNSトピック：SNS`cicd-success-publish-sns`のARN
- pipeline-error
    - 通知をトリガーするイベント
        - Action execution：Failed
        - Stage execution：Failed
        - Pipeline execution：Failed
        - Manual approval：Failed
    - ターゲット
        - SNSトピック：SNS`cicd-error-publish-sns`のARN

##### IAM
- CodePipeline`hoge-pipeline`作成時にIAMロールが作成されているのでそのロールにポリシーを追加する
    - AmazonSNSFullAccess

ポリシーアタッチ手順：CodePipeline＞パイプライン＞パイプラインを選択＞設定＞全般タブ＞サービスロール＞ポリシーをアタッチ

##### 動作確認

１．Succeededメッセージ送信確認
CodePipeline＞パイプライン＞hoge-pipeline＞変更をリリース

パイプラインの実行成功時に指定したメールアドレス（```cicd-success@e2info.com```）にメッセージ送信されること。

>メッセージ送信されない
調査：通知ターゲットのステータスが「到達できない」となっている。
原因：SNSトピックを作成してからCodePipeline通知ルール作成時にターゲットを指定する流れではポリシーがうまいことセットされないらしい。[参考](https://sayjoyblog.com/aws-codepipeline-notification/)
解決：CodePipeline通知ルールを作成時にSNSトピックを作成する。またはSNSトピックのアクセスポリシーを編集する。

SNSトピックのアクセスポリシーを編集する

```
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "CodeNotification_publish",
      "Effect": "Allow",
      "Principal": {
        "Service": "codestar-notifications.amazonaws.com"
      },
      "Action": "SNS:Publish",
      "Resource": "作成したSNSトピックのARN"
    }
  ]
}
```

メッセージ送信された。

２．Errorメッセージ送信確認

通知をトリガーするイベント「Faild」の場合、CodePipeline設定値を壊さなければメッセージ送信テストできない。AWSマネージドなトリガーのため厳密なテストは不要と判断し、テスト時のみ、通知をトリガーするイベントに「Succeeded」を追加する。

CodePipeline＞パイプライン＞hoge-pipeline＞変更をリリース

パイプラインの実行停止時に指定したメールアドレス（```cicd-error@e2info.com```）にメッセージ送信されること。
テスト終了後、通知をトリガーするイベント「Succeeded」のチェックを外す。


## CloudWatchアラームの監視

#### 監視の流れ

CloudWatchアラーム→SNS→Eメール

#### 監視内容

対象リソースの負荷状況に応じてメッセージ送信する。

#### 作る

##### SNS

- metrics-alarm-publish-sns
    - タイプ：スタンダード
    - サブスクリプション
        - プロトコル：Eメール
        - エンドポイント：```metrics-alarm@e2info.com```

##### Cloud Watch エージェント

EC2のメモリやディスク容量の監視を行うために必要。

サーバーアクセスし、CloudWatchエージェントをインストールする

```
sudo yum install amazon-cloudwatch-agent
```

再起動設定ON

```
sudo systemctl enable awslogsd.service
```

ウィザードを使って設定ファイルを作成する

```
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
```

操作ログ
今回取得したいデータは、ディスク使用率とメモリ使用率のみ。
StatsD、CollectDから取得できるメトリクスは不要。

```
On which OS are you planning to use the agent?
1. linux
2. windows
default choice: [1]:
1
Trying to fetch the default region based on ec2 metadata...
Are you using EC2 or On-Premises hosts?
1. EC2
2. On-Premises
default choice: [1]:
1
Which user are you planning to run the agent?
1. root
2. cwagent
3. others
default choice: [1]:
1
Do you want to turn on StatsD daemon?
1. yes
2. no
default choice: [1]:
2
Do you want to monitor metrics from CollectD?
1. yes
2. no
default choice: [1]:
2
Do you want to monitor any host metrics? e.g. CPU, memory, etc.
1. yes
2. no
default choice: [1]:
1
Do you want to monitor cpu metrics per core? Additional CloudWatch charges may apply.
1. yes
2. no
default choice: [1]:
1
Do you want to add ec2 dimensions (ImageId, InstanceId, InstanceType, AutoScalingGroupName) into all of your metrics if the info is available?
1. yes
2. no
default choice: [1]:
1
Would you like to collect your metrics at high resolution (sub-minute resolution)? This enables sub-minute resolution for all metrics, but you can customize for specific metrics in the output json file.
1. 1s
2. 10s
3. 30s
4. 60s
default choice: [4]:
4
Which default metrics config do you want?
1. Basic
2. Standard
3. Advanced
4. None
default choice: [1]:
1
Current config as follows:
{
        "agent": {
                "metrics_collection_interval": 60,
                "run_as_user": "root"
        },
        "metrics": {
                "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
                        }
                }
        }
}
Are you satisfied with the above config? Note: it can be manually customized after the wizard completes to add additional items.
1. yes
2. no
default choice: [1]:
1
Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html) configuration file to import for migration?
1. yes
2. no
default choice: [2]:
1
What is the file path for the existing cloudwatch log agent configuration file?
default choice: [/var/awslogs/etc/awslogs.conf]
/etc/awslogs/awslogs.conf　// 各々の設定値を書く。
Do you want to monitor any log files?
1. yes
2. no
default choice: [1]:
2
Saved config file to /opt/aws/amazon-cloudwatch-agent/bin/config.json successfully.
Current config as follows:
{
        "agent": {
                "metrics_collection_interval": 60,
                "run_as_user": "root"
        },
        "logs": {
                "force_flush_interval": 5,
                "logs_collected": {
                        "files": {
                                "collect_list": [
                                        // 各々のサーバー設定が書かれている。
                                ]
                        }
                }
        },
        "metrics": {
                "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
                        }
                }
        }
}
Please check the above content of the config.
The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
Edit it manually if needed.
Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:
1
What parameter store name do you want to use to store your config? (Use 'AmazonCloudWatch-' prefix if you use our managed AWS policy)
default choice: [AmazonCloudWatch-linux]
AmazonCloudWatch-from-metrics-alarm-to-sns
Trying to fetch the default region based on ec2 metadata...
Which region do you want to store the config in the parameter store?
default choice: [ap-northeast-1]

Which AWS credential should be used to send json config to parameter store?
1. *********(From SDK)
2. Other
default choice: [1]:

Successfully put config to parameter store AmazonCloudWatch-from-metrics-alarm-to-sns.
Program exits now.
```

設定ファイルの確認

```
less /opt/aws/amazon-cloudwatch-agent/bin/config.json
```

CloudWatchエージェント起動

```
sudo systemctl start amazon-cloudwatch-agent
```

起動確認

```
sudo systemctl status amazon-cloudwatch-agent
```

ログの場所：/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log

>別サーバーでCloudWatchエージェントを上記コマンドで起動しようとしたところ、起動しない。下記コマンドで起動できた。

```
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a start
```

```
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
```


CloudWatch＞メトリクス
「CWAgent」が追加されていればOK




参考：
[はじめてのCloudWatch Agent導入](https://blog.serverworks.co.jp/tech/2020/01/28/cloudwtach-agent-ssm-centos/)
[CloudWatch エージェントを使用して Amazon EC2 インスタンスとオンプレミスサーバーからメトリクスとログを収集する](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html)



##### Cloud Watch アラーム

- ec2-hoge-Memory-80
    - メトリクスの選択
        - CWAgent＞ImageId,InstanceId,InstanceType
        - インスタンス名：hoge
        - path：/
        - メトリクス名：mem_used_percent
    - 統計：平均値
    - 期間：5分
    - しきい値の種類：静的
    - disk_used_percent が次の時...：より大きい
    - ... よりも：80
    - アラーム状態トリガー：アラーム状態
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns
    - アラーム状態トリガー：OK
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns

- ec2-hoge-Disk-70
    - メトリクスの選択
        - CWAgent＞ImageId,InstanceId,InstanceType,device,fstype,path
        - インスタンス名：hoge
        - path：/
        - メトリクス名：disk_used_percent
    - 統計：平均値
    - 期間：5分
    - しきい値の種類：静的
    - disk_used_percent が次の時...：より大きい
    - ... よりも：70
    - アラーム状態トリガー：アラーム状態
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns
    - アラーム状態トリガー：OK
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns

- ec2-hoge-CPU-70
    - メトリクスの選択
        - インスタンス名：hoge
        - メトリクス名：CPUUtilization
    - 統計：平均値
    - 期間：5分
    - しきい値の種類：静的
    - CPUUtilization が次の時...：以上
    - ... よりも：70
    - アラーム状態トリガー：アラーム状態
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns
    - アラーム状態トリガー：OK
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns

- ec2-hoge-status
    - メトリクスの選択
        - インスタンス名：hoge
        - メトリクス名：StatusCheckFailed
    - 統計：平均値
    - 期間：1分
    - しきい値の種類：静的
    - StatusCheckFailed が次の時...：以上
    - ... よりも：0.99
    - アラーム状態トリガー：アラーム状態
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns
    - アラーム状態トリガー：OK
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns

- aurora-instance-hoge-CPU-70
    - メトリクスの選択
        - インスタンス名：hoge
        - メトリクス名：CPUUtilization
    - 統計：平均値
    - 期間：5分
    - しきい値の種類：静的
    - CPUUtilization が次の時...：以上
    - ... よりも：70
    - アラーム状態トリガー：アラーム状態
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns
    - アラーム状態トリガー：OK
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns

- aurora-cluster-hoge-CPU-70
    - メトリクスの選択
        - DBClusterIdentifier：hoge
        - メトリクス名：CPUUtilization
    - 統計：平均値
    - 期間：5分
    - しきい値の種類：静的
    - CPUUtilization が次の時...：以上
    - ... よりも：70
    - アラーム状態トリガー：アラーム状態
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns
    - アラーム状態トリガー：OK
    - 既存のSNSトピックを選択：metrics-alarm-publish-sns

参考：
[Amazon CloudWatch でのアラームの使用](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)
[CloudWatch メトリクスの使用状況のモニタリング](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CloudWatch-Logs-Monitoring-CloudWatch-Metrics.html)
[インスタンスの利用可能な CloudWatch メトリクスのリスト表示](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html)

##### 動作確認

サーバーにアクセスし、下記コマンドを入力。メッセージ送信されること。

```
aws cloudwatch set-alarm-state --alarm-name アラーム名 --state-value 状態（OK、ALARM、INSUFFICIENT_DATA） --state-reason "コマンド実行理由"

// EC2インスタンスCPU使用率70以上
aws cloudwatch set-alarm-state --alarm-name ec2-hoge-CPU-70 --state-value ALARM --state-reason "test" 

// AuroraクラスターCPU使用率70以上
aws cloudwatch set-alarm-state --alarm-name aurora-cluster-hoge-CPU-70 --state-value ALARM --state-reason "test"

// 上記の要領で他のテストも実行する。
```

コマンド実行後、マネジメントコンソールから対象のアラームがアラーム状態になったことを確認し、メッセージ送信されていること。
その数秒後に対象のアラームがOK状態に戻り、メッセージ送信されていること。

参考：
[設定した CloudWatch Alarm をテストする方法](https://dev.classmethod.jp/articles/tsnote-cloudwatch-alarm-test-001/)