kakakakakku blog

Weekly Tech Blog: Keep on Learning!

AWS CDK でローカルファイルを Amazon S3 にアップロードできる aws_s3_deployment

AWS CDK で aws_s3_deployment モジュールを使うとローカルにある ZIP ファイル・ディレクトリなどを Amazon S3 にアップロードできる❗️使いどころとしては,静的ファイル・設定ファイル・データセットなどのアップロードも AWS CDK のワークフローに含めて IaC 化したいときなどにハマると思う💡さっそく試す \( 'ω')/

docs.aws.amazon.com

1. ZIP ファイルをアップロードする

まずはローカルにある ZIP ファイルを Amazon S3 にアップロードする.ZIP ファイルはサンプルとして MySQL のサンプルデータセット「sakila database」sakila-db.zip を使う.AWS CDK の実装としては aws_s3_deployment.BucketDeploymentsources に ZIP ファイルを指定して destinationBucket に Amazon S3 バケットを指定するだけ👌 簡単〜

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

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

    const bucket = new aws_s3.Bucket(this, 'SandboxCdkS3DeploymentBucket', {
      bucketName: 'sandbox-cdk-s3-deployment-bucket',
    });

    new aws_s3_deployment.BucketDeployment(this, 'SandboxCdkS3Deployment', {
      sources: [aws_s3_deployment.Source.asset('./datasets/sakila-db.zip')],
      destinationBucket: bucket,
    });
  }
}

cdk deploy コマンドを実行すると,ZIP ファイルが自動的に展開されてアップロードされていた❗️

ZIP ファイルをアップロードできた

2. ZIP ファイルのままアップロードする

デフォルトでは ZIP ファイルは展開されるけど extract: false オプションを付けると ZIP のままアップロードできる.しかしファイル名が異なる点には注意する👀

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

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

    const bucket = new aws_s3.Bucket(this, 'SandboxCdkS3DeploymentBucket', {
      bucketName: 'sandbox-cdk-s3-deployment-bucket',
    });

    new aws_s3_deployment.BucketDeployment(this, 'SandboxCdkS3Deployment', {
      sources: [aws_s3_deployment.Source.asset('./datasets/sakila-db.zip')],
      destinationBucket: bucket,
      extract: false,
    });
  }
}

cdk deploy コマンドを実行すると,e64c076b781d54f6210a9d9f8bfb08e40e8176ecf6f7542a5465d7b9be376574.zip という名前で ZIP ファイルのままアップロードされていた❗️

ZIP ファイルのままアップロードできた

3. ディレクトリをアップロードする

ZIP ファイルではなくローカルにあるディレクトリをアップロードすることもできる.使いどころを考えると一番使うのはディレクトリのアップロードかもしれない.さらに include / exclude でフィルタもあって,不要なファイルをアップロードしないように制御できるのは助かる👌

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

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

    const bucket = new aws_s3.Bucket(this, 'SandboxCdkS3DeploymentBucket', {
      bucketName: 'sandbox-cdk-s3-deployment-bucket',
    });

    new aws_s3_deployment.BucketDeployment(this, 'SandboxCdkS3Deployment', {
      sources: [aws_s3_deployment.Source.asset('./bin', { exclude: ['*.js'] })],
      destinationBucket: bucket,
    });
  }
}

単純に除外するなら sources に指定する AssetOptionsexclude を指定すればアップロード対象をまとめるときに除外できる.また BucketDeployment 自体に includeexclude を指定することもできて,Amazon S3 へのアップロード前に考慮される.ちなみに includeexclude の構文に関しては AWS CLI の aws s3 sync コマンドと同じ💡

awscli.amazonaws.com

今回はサンプルとして AWS CDK プロジェクトの bin ディレクトリの3ファイルを対象にしつつ *.js を除外する.

$ tree bin
bin
├── sandbox-cdk-aws.d.ts
├── sandbox-cdk-aws.js
└── sandbox-cdk-aws.ts

cdk deploy コマンドを実行すると,sandbox-cdk-aws.d.tssandbox-cdk-aws.ts のみアップロードされていた❗️

ディレクトリをアップロードできた

仕組み

ドキュメントにも書いてあるけど,aws_s3_deployment モジュールは内部的に AWS Lambda 関数を作って,AWS Lambda 関数の中から AWS CLI の aws s3 sync コマンドを実行して Amazon S3 にファイルをアップロードしている.AWS Lambda 関数のコード index.py は以下にある.

github.com

よって,AWS CloudFormation のリソース一覧を見るとカスタムリソース Custom::CDKBucketDeployment の中に AWS Lambda 関数が含まれていて,実際に以下のような AWS Lambda 関数が作られていた.あくまで個人的にだけどカスタムリソースなどによって勝手にリソースが作られることに少し抵抗はあって,今回だと Amazon S3 にファイルをアップロードするために AWS Lambda 関数が作られるのか〜という気持ちになったりはする💨

aws_s3_deployment モジュール用の AWS Lambda 関数が存在する