0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

aws cdkで複合アラームを作成してみたメモ

0
Last updated at Posted at 2023-06-22

概要

cdkでsnsのtopicとsubscriptionを作ってlambdaからpublishしたメモで作成したメール送付Lambdaを複合アラームに繋いでみる。

前回との差分

コード

cdk/lib/AlarmSNSStack.ts
import { Aspects, CfnOutput, Duration, Stack, StackProps, Tag } from "aws-cdk-lib";
import { Alarm, AlarmProps, AlarmRule, AlarmState, ComparisonOperator, CompositeAlarm, Metric, MetricProps, TreatMissingData } from "aws-cdk-lib/aws-cloudwatch";
import { Rule } from "aws-cdk-lib/aws-events";
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Topic } from "aws-cdk-lib/aws-sns";
import { EmailSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
import { Construct } from "constructs";

interface AlarmSNSStackProps extends StackProps { emailAdress: string }

export class AlarmSNSStack extends Stack {
  constructor(scope: Construct, id: string, props: AlarmSNSStackProps) {
    super(scope, id, props);

    // ↓↓ 前回と同じ部分
    const topicName = 'topic'
    const snsTopic = new Topic(this, topicName, { displayName: topicName, topicName, fifo: false });
    snsTopic.addSubscription(new EmailSubscription(props.emailAdress));
    const mailSenderLambda = new NodejsFunction(this, 'publishLambda', {
      runtime: Runtime.NODEJS_18_X,
      entry: `../src/handler/eventBridge/sendMail.ts`,
      environment: { snsTopic: topicName },
    })
    snsTopic.grantPublish(mailSenderLambda)
    new CfnOutput(this, `sns-confirm-subscription`, {
      value: `aws sns confirm-subscription --topic-arn ${snsTopic.topicArn} --authenticate-on-unsubscribe true --region ${props.env?.region} --profile produser --token xxxCopyAndPasteTokenfromMailxxx`,
    })
    new CfnOutput(this, `sns-list`, {
      value: `aws sns list-subscriptions-by-topic --topic-arn ${snsTopic.topicArn} --profile produser`,
    })
    // ↑↑ 前回と同じ部分

    const alarmProp: Omit<AlarmProps, 'metric'> = {
      threshold: 5, // データポイントのメトリックのvalueのしきい値
      comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
      datapointsToAlarm: 2, // x分以内のyデータポイント: y
      evaluationPeriods: 3, // x分以内のyデータポイント: x
      treatMissingData: TreatMissingData.NOT_BREACHING,
      actionsEnabled: false,
    } as const;
    const metricProps: MetricProps = {
      namespace: 'Test',
      metricName: 'TestCount',
      period: Duration.minutes(1),
      statistic: 'Sum'
    } as const;
    const alarmRules = ['test1', 'test2'].map(alarmName => {
      const metric = new Metric({ ...metricProps, dimensionsMap: { Target: alarmName } });
      const alarm = new Alarm(this, alarmName, { ...alarmProp, alarmName, metric });
      return AlarmRule.fromAlarm(alarm, AlarmState.ALARM)
    });
    const compositeAlarmName = 'composite-alarm';
    const compositeAlarm = new CompositeAlarm(this, compositeAlarmName, { compositeAlarmName, alarmRule: AlarmRule.anyOf(...alarmRules) });
    const rule = new Rule(this, 'composit-rule', { eventPattern: { resources: [compositeAlarm.alarmArn], detail: { state: { value: ['ALARM', 'OK'] } } } });
    rule.addTarget(new LambdaFunction(mailSenderLambda))

    Aspects.of(this).add(new Tag('Stack', 'AlarmSNSStack'));
  }
}

前回はただのHandlerだったが、今回はEventBridgeHandlerとなる。
型の2つ目は自作する必要があったので、取得したEventから作成した。

src/domain/eventBridge/types.ts
import { EventBridgeHandler } from "aws-lambda"

export type AlarmStateChangeHandler = EventBridgeHandler<"CloudWatch Alarm State Change", Detail, void>;

type StateValue = 'OK' | 'ALARM' | 'INSUFFICIENT';

interface Detail {
  alarmName: string
  state: State
  previousState: PreviousState
  configuration: Configuration
}

interface State {
  value: StateValue
  reason: string //  'arn:aws:cloudwatch:ap-northeast-1:0000000000:alarm:test2 transitioned to OK at Thursday 22 June, 2023 14:26:01 UTC',
  reasonData: string // '{"triggeringAlarms":[{"arn":"arn:aws:cloudwatch:ap-northeast-1:0000000000:alarm:test2","state":{"value":"OK","timestamp":"2023-06-22T14:26:01.928+0000"}},{"arn":"arn:aws:cloudwatch:ap-northeast-1:0000000000:alarm:test1","state":{"value":"OK","timestamp":"2023-06-22T14:25:30.174+0000"}}]}'
  timestamp: string // yyyy-MM-dd'T'HH:mm:ss.SSS+0000
}

interface PreviousState {
  value: StateValue
  reason: string
  reasonData: string
  timestamp: string
}

interface Configuration {
  alarmRule: string // '(ALARM("arn:aws:cloudwatch:ap-northeast-1:0000000000:alarm:test1") OR ALARM("arn:aws:cloudwatch:ap-northeast-1:0000000000:alarm:test2"))'
}

アラームの確認

状態を確認するLambdaを作成した。

cdk/lib/alarm-sns-stack.ts
+    const describeLambda = new NodejsFunction(this, 'describeLambda', {
+      runtime: Runtime.NODEJS_18_X,
+      entry: `../src/handler/invoke/describeAlarm.ts`,
+      environment: { compositeAlarmName },
+      initialPolicy: [new PolicyStatement({ actions: ['cloudwatch:DescribeAlarms'], resources: ['*'] })]
+    });

複合アラームを取得するときはAlarmTypesの明示が必要なことに注意。
省略するとメトリックアラームのみ返却される

src/handler/invoke/describeAlarm.ts
import { CloudWatchClient, DescribeAlarmsCommand } from "@aws-sdk/client-cloudwatch";
import { Handler } from "aws-lambda";

export const handler: Handler = async (event, context) => {
  const envList = ['AWS_REGION', 'compositeAlarmName'] as const;
  envList.forEach(k => { if (!process.env[k]) throw new Error(`${k} environment required`) });
  const processEnv = process.env as Record<typeof envList[number], string>;

  const client = new CloudWatchClient({ region: processEnv.AWS_REGION });
  const compositeAlarmCommand = new DescribeAlarmsCommand({
    AlarmNames: [processEnv.compositeAlarmName],
    AlarmTypes: ['CompositeAlarm']
  })
  const compositeResult = await client.send(compositeAlarmCommand);
  console.log('composite', compositeResult);

  const alarmCommand = new DescribeAlarmsCommand({
    AlarmNamePrefix: 'test'
  });
  const alarmResult = await client.send(alarmCommand);
  console.log('alarms', alarmResult);
}

この時点のソース

参考

cdk CompositeAlarm
Amazon CloudWatch Metrics & Alarms for typical Serverless application using AWS CDK: Part 2
CloudWatchの複合アラームを仕組みを確認しつつ使ってみた
CloudWatch複合アラームでELBの5XXをいい感じに検知しようとしたらうまくいかなかった話

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?