インフラ

CDK L1 ConstructのリソースをL2 Constructにリファクタリングする

cdk

前回の続きです。

cdk
Former2を使って、既存リソースをCDK管理下においてみたCDKの管理化に既存リソースをおきたいことがありました。 CDK管理下に置くことは、CDK書いて、CFn生成、CFnスタックインポートで...

Former2でリソースをインポートできましたが、生成されるCDKはL1 Constructを使っています。
L2 Constructを使ったほうがCDKのメリットを活かせます。

L2に自動でリファクタリングすることは現在できないため、手動にはなりますがリファクタリングしていきます。

結論から書くと、普通にリファクタリングすると生成されるCFnテンプレートの論理IDが変わってリソース再作成が発生します。
そのため、overrideLogicalIdメソッドを使って論理IDを変更しないようにする必要があります。

スナップショットテスト導入

リファクタリング時、意図しない変更を検知できるようにスナップショットテストを導入します。

Amazon Web Services ブログ あらゆる言語でのCDKアプリケーションのテスト

# test/import-cdk.test.ts
import * as cdk from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { ImportCdkStack } from '../bin/import-cdk'

test('SQS Queue Snapshot', () => {
  const app = new cdk.App();
  const stack = new ImportCdkStack(app, 'ImportCdkStack', { env: { region: 'ap-northeast-1' } });

  expect(Template.fromStack(stack)).toMatchSnapshot();
});

テストを実行して、スナップショットを生成します。

$ npm run test
> import-cdk@0.1.0 test /Users/satomasaki/work/src/github.com/msato0731/import-cdk
> jest

 PASS  test/import-cdk.test.ts
  ✓ SQS Queue Snapshot (16 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        3.293 s, estimated 4 s

生成されるCFnテンプレートに変更がなければ、2回目以降の実行時も同様にテストが成功します。

既存のL1 ConstructをL2にリファクタリング

スナップショットテストを導入できたところで、リファクタリングしていきます。
L2に置き換えた結果は以下です。

#!/usr/bin/env node
import 'source-map-support/register';
// cdk v2に変更
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';

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

      // L1 Construct
      // const SQSQueue = new sqs.CfnQueue(this, 'SQSQueue', {
      //     delaySeconds: 0,
      //     maximumMessageSize: 262144,
      //     messageRetentionPeriod: 345600,
      //     receiveMessageWaitTimeSeconds: 0,
      //     visibilityTimeout: 40,
      //     queueName: "import-test",
      // });
      
      // L2 Construct 
      const SQSQueue = new sqs.Queue(this, 'SQSQueue', {
        deliveryDelay: cdk.Duration.seconds(0),
        maxMessageSizeBytes: 262144,
        retentionPeriod: cdk.Duration.days(4),
        receiveMessageWaitTime: cdk.Duration.seconds(0),
        visibilityTimeout: cdk.Duration.seconds(40),
        queueName: "import-test",
      });
      // L2 Constructにすると論理IDにランダムな文字列が入るため上書き
      (SQSQueue.node.defaultChild as sqs.CfnQueue).overrideLogicalId("SQSQueue")

      SQSQueue.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY)
  }
}

const app = new cdk.App();
new ImportCdkStack(app, 'ImportCdkStack', { env: { region: 'ap-northeast-1' } });
app.synth();

テスト結果も問題なさそうです。

$ npm run test

> import-cdk@0.1.0 test /Users/satomasaki/work/src/github.com/msato0731/import-cdk
> jest

 PASS  test/import-cdk.test.ts (8.89 s)
  ✓ SQS Queue Snapshot (23 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        8.939 s, estimated 9 s

diffの結果は、Metadataの変更のみです。

npm run cdk diff ImportCdkStack                                                                                                                                                                                 (git)-[master]

> import-cdk@0.1.0 cdk /Users/satomasaki/work/src/github.com/msato0731/import-cdk
> cdk "diff" "ImportCdkStack"

Stack ImportCdkStack
Resources
[~] AWS::SQS::Queue SQSQueue SQSQueue 
 └─ [~] Metadata
     └─ [~] .aws:cdk:path:
         ├─ [-] ImportCdkStack/SQSQueue
         └─ [+] ImportCdkStack/SQSQueue/Resource

overrideLogicalIdメソッドを使って論理IDを固定する

上記コードの以下の記述についてです。

(SQSQueue.node.defaultChild as sqs.CfnQueue).overrideLogicalId("SQSQueue")

L2とL1で生成されるCFnテンプレートの論理IDが変わることに対する対策です。

リソース名が変わると、既存のリソースが削除されて置き換わるような動きになります。
CDKのConstruct IDをもとに、CFnの論理IDが設定されます。
L1とL2で以下のような違いがあります。

  • L1: Construct Id (例 SQSQueue
  • L2: Construct Id + ランダムな文字列 (例 SQSQueue7674CD17

※例はConstruct IdにSQSQueueを設定した場合

# 論理ID上書きしなかった場合の「cdk diff」
$ npm run cdk diff ImportCdkStack

> import-cdk@0.1.0 cdk /Users/satomasaki/work/src/github.com/msato0731/import-cdk
> cdk "diff" "ImportCdkStack"

Stack ImportCdkStack
Resources
[-] AWS::SQS::Queue SQSQueue destroy
[+] AWS::SQS::Queue SQSQueue SQSQueue7674CD17
# スナップショットテストも失敗
$ npm run test

> import-cdk@0.1.0 test /Users/satomasaki/work/src/github.com/msato0731/import-cdk
> jest

 FAIL  test/import-cdk.test.ts
  ✕ SQS Queue Snapshot (21 ms)

  ● SQS Queue Snapshot

    expect(received).toMatchSnapshot()

    Snapshot name: `SQS Queue Snapshot 1`

    - Snapshot  - 1
    + Received  + 1

    @@ -5,11 +5,11 @@
            "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
            "Type": "AWS::SSM::Parameter::Value",
          },
        },
        "Resources": Object {
    -     "SQSQueue": Object {
    +     "SQSQueue7674CD17": Object {

overrideLogicalIdメソッドを使って、上書きすることでL1で作ったときと同様の論理IDにすることができます。

参考 How to Override Logical IDs of Resources in AWS CDK

cdk
Former2を使って、既存リソースをCDK管理下においてみたCDKの管理化に既存リソースをおきたいことがありました。 CDK管理下に置くことは、CDK書いて、CFn生成、CFnスタックインポートで...
cdk book
[書評]CDK使っている人は一度読んでおきたい「The CDK Book」こんにちは、ちゃりおです。 「The CDK Book」読んでみました。 CDKは比較的新しいIaCツールのため、実践的な内容につい...
datadog
CDKを使ってECSにDatadogAgentコンテナを追加して監視してみたCDKでECSにDatadogAgentコンテナを追加して、Datadog上からメトリクスを確認してみました。 ECS on Farga...