AWS-CDKではいくつかのコンストラクトでAWSリソースを作成することが可能です。
今回は低レベルのコンストラクトを利用したAWSリソースのArnを取得して、その文字列を加工してCWAlarmのDimensionのvalueに渡そうとしたときに詰まった部分を書いていきます。
前提
- AWS-CDKはTypeScriptで記述している
- Application LoadBalancerはCfnLoadBalanerを使ってリソースを作成している
実現したいこと
Application LoadBalancer(ALB)のTargetResponseTime(リクエストがロードバランサーから送信され、ターゲットからの応答を受信するまでの経過時間 (秒))をメトリクスとしてCloudWatchAlarmを作成したい。
Application LoadBalancerメトリクスの説明
ALBのTargetResponseTimeをメトリクスとする場合、リソースを作成するときにディメンションに以下のどれかを指定する必要がある。
- LoadBalancer
- AvailabilityZone、LoadBalancer
- TargetGroup、LoadBalancer
- TargetGroup、AvailabilityZone、LoadBalancer
参考: Application Load Balancer の CloudWatch メトリクス
今回は、LoadBalancerのみを指定するが、 以下の説明に記載されているように指定する必要があります。
ディメンション 説明 LoadBalancer ロードバランサーでメトリクスデータをフィルタリングします。ロードバランサーを次のように指定します。app/ロードバランサー名/1234567890123456 (ロードバランサー ARN の最後の部分)。
ALBのARNの例: arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/example-alb/abcdefg123456789
ディメンションには上記のARNのloadbalancer/
以降の文字列をValueとして渡してあげれば問題ない。
問題点
例えば、以下のようなALBのリソースを記述したコードがあります。
const alb = new elb.CfnLoadBalancer(this, 'example', { .... });
alb.ref
のように書くとARNを取得できるので、以下のようにリソースを作成するコードを書いてみたけど、
作成されたCW AlarmのLoadBalancerのディメンションには、そのままのARN arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/example-alb/a123bcd456e7f8g9
が指定されており、TargetResponseTimeを取得できない状態でした。
※ alb.refの返り値は文字列です
const albDimentionValue = alb.ref.replace(/.+loadbalancer\/(.+)/, '$1'); const albTargetResponseTimeAlarm = new cw.CfnAlarm(this, 'targetResponseTimeAlarm', { actionsEnabled: true, alarmName: 'TargetResponseTimeAlarm', alarmActions: [scalingPolicy.ref], comparisonOperator: "GreaterThanOrEqualToThreshold", threshold: 3, evaluationPeriods: 3, namespace: "AWS/ApplicationELB", metricName: "TargetResponseTime", statistic: "Average", dimensions: [ { name: "LoadBalancer", value: albDimentionValue } ], period: cdk.Duration.minutes(1).toSeconds(), }); albTargetResponseTimeAlarm.addDependsOn(scalingPolicy);
解決策
どうやって解決したかというと、CloudFormationにもある組み込み関数を使えば、ARNの文字列を加工することができました。 CDKにもCloudFormationと同じ組み込み関数がcoreに定義されているのでそれを利用しました。
const splitAlbArn = cdk.Fn.split('/', alb.ref); const albDimensionValue = `${cdk.Fn.select(1, splitAlbArn)}/${cdk.Fn.select(2, splitAlbArn)}/${cdk.Fn.select(3, splitAlbArn)}`; const albTargetResponseTimeAlarm = new cw.CfnAlarm(this, 'targetResponseTimeAlarm', { actionsEnabled: true, alarmName: 'TargetResponseTimeAlarm', alarmActions: [scalingPolicy.ref], comparisonOperator: "GreaterThanOrEqualToThreshold", threshold: 3, evaluationPeriods: 3, namespace: "AWS/ApplicationELB", metricName: "TargetResponseTime", statistic: "Average", dimensions: [ { name: "LoadBalancer", value: albDimensionValue } ], period: cdk.Duration.minutes(1).toSeconds(), }); albTargetResponseTimeAlarm.addDependsOn(scalingPolicy);
最後に
AWS-CDKに関する記事はまだまだ少ないので、参考になれば幸いです。