AWS CDKで作成したリソースのARN文字列を取得して加工する方法

f:id:ryskit:20200109205701p:plain

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に関する記事はまだまだ少ないので、参考になれば幸いです。