AWS CDK v2.85.0 でファイルの内容を置換しつつ S3 バケットにアップロードできる `DeployTimeSubstitutedFile` が利用可能になりました

2023.06.28

こんにちは、CX事業本部 Delivery部の若槻です。

AWS CDK v2.85.0 で、ファイルの内容を置換しつつ Amazon S3 バケットにアップロードできるコンストラクトクラス DeployTimeSubstitutedFile が利用可能になりました。

Features

- s3-deployment: create DeployTimeSubstitutedFile to allow substitutions in file (#25876) (ca2e6a2), closes #1461

DeployTimeSubstitutedFile の仕様

ドキュメントで DeployTimeSubstitutedFile コンストラクトクラスの仕様を確認してみます。

Construct Props は次のようになります。

Name Type Description
destinationBucket IBucket The S3 bucket to sync the contents of the zip file to.
source string Path to the user's local file.
substitutions { [string]: string } User-defined substitutions to make in the file.

source のパスにあるローカルファイルの内容を substitutions に従って置換し、destinationBucket にアップロードします。

Properties は次のようになります。

Name Type Description
bucket IBucket
deployedBucket IBucket The bucket after the deployment.
node Node The tree node.
objectKey string
objectKeys string[] The object keys for the sources deployed to the S3 bucket.

試してみた

CDK コード

DeployTimeSubstitutedFile を使用した CDK スタックのコードです。my-file.json ファイル内の xxxx および yyyy というプレースホルダーを置換するようにしています。

lib/cdk-sample-stack.ts

import {
  aws_s3_deployment as s3deploy,
  aws_s3 as s3,
  Stack,
  StackProps,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  public readonly myFileObjectKey: string;

  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    // アップロード先バケット
    const destinationBucket = new s3.Bucket(this, 'MyBucket', {
      bucketName: `my-bucket-${this.account}-${this.region}`,
    });

    // `DeployTimeSubstitutedFile` によるファイルの置換およびアップロード
    const myFile = new s3deploy.DeployTimeSubstitutedFile(this, 'MyFile', {
      source: 'my-file.json',
      destinationBucket: destinationBucket,
      substitutions: {
        xxxx: 'mySubstitution1',
        yyyy: 'mySubstitution2',
      },
    });

    // アップロードされたファイルのオブジェクトキー取得確認
    this.myFileObjectKey = myFile.objectKey;
    this.exportValue(myFile.objectKey, { name: 'MyFileObjectKey' });
  }
}

置換およびアップロード対象のファイルです。プレースホルダーは {{ xxxx }} のように指定します。

my-file.json

{
  "description": "This is a sample file",
  "parameter1": "{{ xxxx }}",
  "parameter2": "{{ yyyy }}"
}

cdk deploy でスタックをデプロイします。

デプロイ後に S3 バケットの中身を確認すると、オブジェクトがアップロードされています。パスは S3 バケットのルート、オブジェクト名はランダムな文字列となるようです。ローカルでのファイル名とはならないんですね。

$ aws s3 ls s3://${bucketname}                    
2023-06-29 03:01:50        115 b70caacf3a36a7bd6b9315a9deabbc9ae27a11b6812257017f1a89e76b4a7ca4

作成されたオブジェクトの内容を確認すると、ちゃんと置換が行われていますね。

$ aws s3 cp s3://${bucketname} ./tmp --recursive
$ cat ./tmp/b70caacf3a36a7bd6b9315a9deabbc9ae27a11b6812257017f1a89e76b4a7ca4
{
  "description": "This is a sample file",
  "parameter1": "mySubstitution1",
  "parameter2": "mySubstitution2"
}

アップロード対象のファイルを変更してみる

DeployTimeSubstitutedFilesource の指定を変更して、アップロード対象のファイルを変更した時の挙動を確認してみます。

lib/cdk-sample-stack.ts

    // `DeployTimeSubstitutedFile` によるファイルの置換およびアップロード
    const myFile = new s3deploy.DeployTimeSubstitutedFile(this, 'MyFile', {
-     source: 'my-file.json',
+     source: 'my-file.yaml',
      destinationBucket: destinationBucket,
      substitutions: {
        xxxx: 'mySubstitution1',
        yyyy: 'mySubstitution2',
      },
    });

変更後のアップロード対象ファイルです。

my-file.yaml

version: 1.0.0
metadata:
  name: my-file
  description: This is a sample file
  parameter1: {{ xxxx }}
  parameter2: {{ yyyy }}

cdk deploy コマンドでスタックをデプロイします。

デプロイ完了後に S3 バケットの中身を確認すると、変更前と変更後のオブジェクトが S3 バケットに併存していますね。変更前のオブジェクトは削除され、変更後のオブジェクトが追加されるという冪等性のある挙動を期待していましたが、そうではないようです。

$ aws s3 ls s3://${bucketname}    
2023-06-29 03:20:40        138 583d9aa21a5e56757e5e91c0065b4ad9a24879cb30b6c58354bce7bfd4ec56ce
2023-06-29 03:01:50        115 b70caacf3a36a7bd6b9315a9deabbc9ae27a11b6812257017f1a89e76b4a7ca4

変更後のファイルの内容を確認すると、ちゃんと置換は行われています。

$ aws s3 cp s3://${bucketname} ./tmp --recursive
$ cat ./tmp/583d9aa21a5e56757e5e91c0065b4ad9a24879cb30b6c58354bce7bfd4ec56ce
version: 1.0.0
metadata:
  name: my-file
  description: This is a sample file
  parameter1: mySubstitution1
  parameter2: mySubstitution2

DeployTimeSubstitutedFile コンストラクトを削除してみる

作成した DeployTimeSubstitutedFile コンストラクトを削除した時の挙動も確認してみます。

lib/cdk-sample-stack.ts

export class CdkSampleStack extends Stack {
  public readonly myFileObjectKey: string;

  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    // アップロード先バケット
    const destinationBucket = new s3.Bucket(this, 'MyBucket', {
      bucketName: `my-bucket-${this.account}-${this.region}`,
    });

    // // `DeployTimeSubstitutedFile` によるファイルの置換およびアップロード
    // const myFile = new s3deploy.DeployTimeSubstitutedFile(this, 'MyFile', {
    //   source: 'my-file.yaml',
    //   destinationBucket: destinationBucket,
    //   substitutions: {
    //     xxxx: 'mySubstitution1',
    //     yyyy: 'mySubstitution2',
    //   },
    // });

    // // アップロードされたファイルのオブジェクトキー確認
    // this.myFileObjectKey = myFile.objectKey;
    // this.exportValue(myFile.objectKey, { name: 'MyFileObjectKey' });
  }
}

cdk deploy コマンドでスタックをデプロイします。

デプロイ完了後に S3 バケットの中身を確認すると、既存のファイルは削除されずに残っています。やはり作りっぱなしになるようですね。

aws s3 ls s3://${bucketname}                                              
2023-06-29 03:20:40        138 583d9aa21a5e56757e5e91c0065b4ad9a24879cb30b6c58354bce7bfd4ec56ce
2023-06-29 03:01:50        115 b70caacf3a36a7bd6b9315a9deabbc9ae27a11b6812257017f1a89e76b4a7ca4

注意点

DeployTimeSubstitutedFile を試した結果、次のような点に注意する必要がありました。

  • アップロードされるオブジェクトキー(ディレクトリやオブジェクト名)の指定は出来ない
  • ファイルの変更やコンストラクト削除した場合でも、既存のオブジェクトは削除されない(冪等性がない)

所感

はじめは CDK でデプロイを管理しているフロントエンドアプリの構成ファイルをデプロイ先の環境ごとに動的に作成するというユースケースで便利になると思いましたが、上記の注意点のような制約があるため今のところは難しそうです。

しかしオブジェクトキーが指定可能となったりデプロイ毎の冪等性の担保されるようになれば、かなり便利なクラスに化けると思います。もしくはこの置換機能が BucketDeployment コンストラクトクラス自体に実装されると嬉しいかも知れません。

以上