Amazon CloudWatch SyntheticsでCanary実行がタイムアウトした時にもアラームを発生させたい(AWS CDK)

2021.09.22

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、Amazon CloudWatch SyntheticsでのCanary実行がタイムアウトした時にもアラームを発生させる実装をAWS CDKで実装してみました。

前回の実装ではCanary実行のタイムアウトに対応できなかった

以前に下記エントリでCloudWatch SyntheticsによるURL監視で失敗を検知したらCloudWatch Alarmでアラームを発生させる(およびSNSトピックによる通知をする)実装をCDKで行いました。

この実装のうちCloudWatch Alarmのリソースの実装を抜粋したものが下記です。

lib/aws-cdk-app-stack.ts

    const canaryAlarm = new cloudwatch.Alarm(this, 'canary-alarm', {
      alarmName: 'canary-alarm',
      metric: canary.metricFailed(),
      evaluationPeriods: 1,
      threshold: 1,
      statistic: cloudwatch.Statistic.SUM,
      comparisonOperator:
        cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
      period: cdk.Duration.minutes(10),
    });

しかし上記の実装だと、Canary実行がタイムアウトした場合に、CloudWatch Alarmではデータ不足となってアラームが発生しません。

Canary実行のタイムアウトは、ブラウザでプロンプト表示が行われるなど監視スクリプト(pupetter)での処理が進められなくなった場合に発生します。例えば下記のプロンプト表示が行われるサイトを監視対象とした場合だと、

下記のようにCanary実行がNo test result returned.Connection timed out after XXXXXXmsというタイムアウトの失敗となります。

するとCloudWatch Alarm側ではデータ不足となりアラームは発生しません。

そこで今回はそのようなサイトの監視にも対応できるように、Canaryの実行結果が通常の失敗およびタイムアウトのいずれでもCloudWatch Alarmでアラーム発生させる実装をしてみます。

Canary実行のタイムアウト時にもアラームを発生させる

CDKコード

lib/aws-cdk-app-stack.ts

import * as path from 'path';
import * as cdk from '@aws-cdk/core';
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as synthetics from '@aws-cdk/aws-synthetics';

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

    const canary = new synthetics.Canary(this, 'WebsiteCanary', {
      canaryName: `website-canary`,
      schedule: synthetics.Schedule.rate(cdk.Duration.minutes(3)),
      runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_2,
      test: synthetics.Test.custom({
        code: synthetics.Code.fromAsset(
          path.join(__dirname, `../src/lambda/website-canary-handler`)
        ),
        handler: 'index.handler',
      }),
      environmentVariables: {
        URL: process.env.MONITORED_URL!,
      },
    });

    new cloudwatch.Alarm(this, 'canary-alarm', {
      alarmName: 'canary-alarm',
      metric: canary.metricSuccessPercent(),
      evaluationPeriods: 1,
      threshold: 100,
      statistic: cloudwatch.Statistic.SUM,
      comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD,
      period: cdk.Duration.minutes(3),
      treatMissingData: cloudwatch.TreatMissingData.BREACHING,
    });
  }
}
  • CanaryとCloudWatch Alarmのリソースを作成しています。
  • treatMissingDataBREACHINGとすることにより、Canary実行タイムアウトによるデータ欠落を不正(しきい値を超えている)として処理してアラームが発生するようにします。
  • 下記の設定により3 分内の1データポイントのSuccessPercent < 100というしきい値となります。評価期間内でCanary実行が一度でも失敗し成功率が100%を下回ればアラームが発生します。
    • メトリクス(metric):metricSuccessPercent
    • スレッショルド(threshold):100
    • 統計(statistic):SUM
    • 比較(comparisonOperator):LESS_THAN_THRESHOLD

これによりCanary実行が通常の失敗およびタイムアウトのいずれでもアラームが発生するようになります。

動作確認

Canary実行の成功時、失敗時、タイムアウト時の3通りの動作を確認してみます。(キャプチャの時系列が前後しているのは気にしないで下さい)

Canary成功時

Canaryの実行を成功させた際の動作です。

$ export MONITORED_URL=https://dev.classmethod.jp/
$ cdk deploy

アラームは発生していません。OK状態となっています。

Canary失敗(通常)時

Canaryの実行を失敗(通常)させた際の動作です。

実行が失敗するURLを指定してCDKデプロイします。

$ export MONITORED_URL=https://dev.classmethod.jp/hoge
$ cdk deploy

Canary実行が失敗しました。

アラームが発生しました。(Canary失敗からほぼノータイムでした。)

メトリクスの詳細を見るとSuccessPercentが0となっています。

Canary失敗(タイムアウト)時

Canaryの実行をタイムアウトさせた際の動作です。

正常なURLを指定して一旦アラームをOK状態に戻します。

実行がタイムアウトするURLを指定してCDKデプロイします。

$ export MONITORED_URL=https://1741r.csb.app/
$ cdk deploy

Canary実行がタイムアウトしました。

アラームが発生しました。(Canaryのタイムアウトから10分を要しました。データポイントが無い場合はある場合に比べて時間を要するようです)

メトリクスの詳細を見るとSuccessPercentは100のままです。しかしデータ欠落時の設定によりしきい値を超えていると判断されているため、アラーム状態となります。

Canary実行を成功させるとOKのデータポイントが記録されてCloudWatch AlarmはOK状態となりました。

おわりに

Amazon CloudWatch SyntheticsでのCanary実行がタイムアウトした時にもアラームを発生させる実装をAWS CDKで実装してみました。

CloudWatch Alarmやメトリクスの理解が浅かったこと、そして実際にCanaryを実行してデバッグをするのに逐一待ち時間が掛かることなどにより検証がなかなか大変でした。

参考

以上