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?

CDKのL2 Constructで指定できないパラメータをL1 Constructで指定する

Last updated at Posted at 2024-11-09

概要

CDK(L2 Construct)でAWSリソースを作っていると指定できないプロパティがあります。

CDKのバージョンを上げれば解消されることもありますが、いつでも最新のCDKが使える状況ではないかもしれません。また、最新化したとしても依然として指定できないケースもあります。

より低レイヤーなL1 Constructを使うことで解決する方法を紹介します。

前提

バージョン情報

  • CDK:2.89.0
  • TypeScript

CDKのレイヤーについて

CDKには大きく3つのレイヤーが存在しています。

レイヤー名 説明
L1 Cfnのテンプレートを直接記述できる。L2よりも細かい指定ができる。
L2 普通に書いてたらこのレイヤーを使ってる。
L3 本記事とは無関係なので割愛。

極端な例ですが、L2でS3バケットを作ろうと思った場合以下のように1行書けば作れます。

const bucket = new s3.Bucket(this, 'MyFirstBucket');

作成したバケットにバケットポリシーをつけたらかったらaddToResourcePolicy()を使えばいいです。

const bucket = new s3.Bucket(this, 'MyBucket');
const result = bucket.addToResourcePolicy(
  new iam.PolicyStatement({
    actions: ['s3:GetObject'],
    resources: [bucket.arnForObjects('file.txt')],
    principals: [new iam.AccountRootPrincipal()],
  })
);

L2を使うことでこのように少ないコード量でリソースを定義することができるのは大きなメリットでしょう。

L2では書けないケース

CDKのバージョンが上がるにつれて少しずつ減ってきていますが、新しいサービスや整備が進んでいないサービスだとL2では書けないことがあります。いくつか例を出しましょう。

例1:S3 サーバーアクセスのログ記録

S3にはアクセスログを記録する機能があります。(下図)

Monosnap test-system-maintenance-v2-339713138572-apne1-dev - S3 バケット | S3 | ap-northeast-1 2024-10-06 16-44-26.png

ログの保存先としてS3バケットを指定することができますが、設定パラメータの中でログオブジェクトキーの形式を指定することができます。

Monosnap サーバーアクセスのログ記録を編集 - S3 バケット test-system-maintenance-v2-339713138572-apne1-dev | S3 | ap-northeast-1 2024-10-06 16-48-02.png

Athenaでの検索を考慮するとパーティション分割されている後者を使いたいところです。最新のCDKだとtargetObjectKeyFormatが用意されているので問題なく指定できますが、バージョンが2.89.0だとこれが指定できません。

スクリーンショット 2024-10-06 16.54.18.png

例2:Glue

L2すらないようなケースもあります。

aws-cdk-lib.aws_glue moduleのリファレンスの冒頭には次のような記述があります。

There are no official hand-written (L2) constructs for this service yet. Here are some suggestions on how to proceed:

実験的なライブラリとして@aws-cdk/aws-glue-alphaが提供されていますのでこちらを利用することで少し書くのが楽になります。

ただし、不足している部分は多いです。Serde parametersの設定などはできませんので例えば先ほどのアクセスログをAthenaで検索するには以下のようなテーブル定義をすればいいのですが、input.regexなどは指定できないです。

CREATE EXTERNAL TABLE `s3_access_logs_db.mybucket_logs`(
  `bucketowner` STRING, 
  `bucket_name` STRING, 
  `requestdatetime` STRING, 
  `remoteip` STRING, 
  `requester` STRING, 
  `requestid` STRING, 
  `operation` STRING, 
  `key` STRING, 
  `request_uri` STRING, 
  `httpstatus` STRING, 
  `errorcode` STRING, 
  `bytessent` BIGINT, 
  `objectsize` BIGINT, 
  `totaltime` STRING, 
  `turnaroundtime` STRING, 
  `referrer` STRING, 
  `useragent` STRING, 
  `versionid` STRING, 
  `hostid` STRING, 
  `sigv` STRING, 
  `ciphersuite` STRING, 
  `authtype` STRING, 
  `endpoint` STRING, 
  `tlsversion` STRING,
  `accesspointarn` STRING,
  `aclrequired` STRING)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.serde2.RegexSerDe' 
WITH SERDEPROPERTIES ( 
  'input.regex'='([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*)(?: ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*))?.*$') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://amzn-s3-demo-bucket1-logs/prefix/'

解決策

こういったケースの解決策の一つとしてL1の利用が考えられます。

先の例のケースで具体的に見ていきます。

例1:S3 サーバーアクセスのログ記録

// バケット作成(これはL2)※ バケット作成時のプロパティは割愛
const bucket = new s3.Bucket(this, 'MyBucket');
// L2で定義したリソースをL1で再定義 
const cfnBucket = bucket.node.defaultChild as CfnBucket;
// L1でのリソース設定
cfnBucket.addPropertyOverride("LoggingConfiguration", {
          TargetObjectKeyFormat: {
            "PartitionedPrefix": {
              "PartitionDateSource": "EventTime" // パーティション分割の基準となる日付はイベント発生日時とする。
            }
          }

L1で再定義するところは{L2リソース}.node.defaultChild as {適切なデータ型}という形式で取得できます。

addPropertyOverride()の中身はCfnのリファレンスを見て頑張って記載します。今回の例だとTargetObjectKeyFormatで指定できることはわかっているのでそこを起点に調べてみます。

PartitionedPrefixが用意されていて、PartitionDateSourceとしてEventTimeDeliveryTimeが指定できるそうなのでそのように指定しています。

例2:Glue

こっちも同じです


(table.node.defaultChild as CfnTable).addPropertyOverride("TableInput", {
        "StorageDescriptor": {
          "SerdeInfo": {
            "Parameters": {
              "input.regex": '([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*)(?: ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*))?.*$',
              "serialization.format": '1'
            }
          }
        }
      });

プロパティの部分は今までL1を使ってないとしんどいですが、慣れれば難しくないと思います。

参考文献

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?