🦔

TypeScriptでAWS CDKを使った時のメモ

2023/09/11に公開

雑にメモるシリーズ - CDKに入門したのときのメモ。入門書はこちら

TypeScriptでプロジェクトを初期化

mkdir aws-cdk && cd aws-cdk

❱❱❱ npx aws-cdk init app --language=typescript
Applying project template app for typescript
# Welcome to your CDK TypeScript project

This is a blank project for CDK development with TypeScript.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

* `npm run build`   compile typescript to js
* `npm run watch`   watch for changes and compile
* `npm run test`    perform the jest unit tests
* `cdk deploy`      deploy this stack to your default AWS account/region
* `cdk diff`        compare deployed stack with current state
* `cdk synth`       emits the synthesized CloudFormation template

Executing npm install...
✅ All done!

いろいろインストールされている。ディレクトリがいっぱいできている。

❱❱❱ npm list
aws-cdk@0.1.0 /Users/me/Projects/aws-cdk
├── @types/jest@29.5.4
├── @types/node@20.5.9
├── aws-cdk-lib@2.95.1
├── aws-cdk@2.95.1
├── constructs@10.2.70
├── jest@29.6.4
├── source-map-support@0.5.21
├── ts-jest@29.1.1
├── ts-node@10.9.1
└── typescript@5.2.2

❱❱❱ ls
README.md		cdk.json		lib			package-lock.json	test
bin			jest.config.js		node_modules		package.json		tsconfig.json

CDK自身が使⽤するリソース(IAMロール、S3バケット、ECRリポジトリなど)を作成するためのブートストラップを実行。対象アカウント、リージョンにつき1回だけ実施。

❱❱❱ npx cdk bootstrap
 ⏳  Bootstrapping environment aws://123456789012/ap-northeast-1...
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
CDKToolkit: creating CloudFormation changeset...
 ✅  Environment aws://123456789012/ap-northeast-1 bootstrapped.

💡 入門書には npx aws-cdk bootstrap とあるが aws-cdk はないと怒られる。ここでCFn
関連のファイルが出力されるcdk.outディレクトリも作られる。

initしたときのプロジェクトの構成は以下

❱❱❱ tree -L 1 -F
./
├── README.md
├── bin/
├── cdk.json
├── cdk.out/
├── jest.config.js
├── lib/
├── node_modules/
├── package-lock.json
├── package.json
├── test/
└── tsconfig.json

bin/aws-cdk.ts から lib/aws-cdk-stack.ts を呼び出している。

S3

lib/aws-cdk-stack.ts で、以下のように、S3のバケツを作ってみる。

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3'; // 追加

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

    // 追加
    new s3.Bucket(this, "aws-cdk-test-backet-by-me", {
      removalPolicy: cdk.RemovalPolicy.DESTROY
    });

  }
}

💡 removalPolicyのデフォルトはRetain、つまりCFnのスタックを消してもS3バケツ自体は消えない。ここではRemovalPolicy.DESTROYにしてスタックと一緒に消えるようにしておく。

Lambda

以下のパッケージを入れておくべし。

開発時に AWS Lambda 関数を TypeScript で書く際に型情報を提供するためのもの

npm i -D @types/aws-lambda

CDKはLamdaをビルドする際にDockerコンテナを使う。なんでわざわざDocker?と思うがそういうもんらしく、Dockerデーモンが動いていなくて以下のError#1を何度かくらった。Dockerを立ち上げておくのも重いのでesbuidを入れることでDockerなしでビルドできるようにする[1]

npm i -D esbuild

lib/simple-lambda-stack.tsではNodejsFunctionコンストラクト[2]を使うことでTypeScriptのコードが楽に扱える

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_lambda_nodejs as lambda } from "aws-cdk-lib"

export class SimpleLambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    new lambda.NodejsFunction(this, "SimpleLambdaFunction", {
      entry: "lambda/index.ts"
    });

  }
}

CFnファイルを作る

npx cdk synth

cdk.out/AwsCdkStack.template.json が出来上がったCFnのファイル。

差分を確認

過去にデプロイしている場合は以下で差分を確認する。

npx cdk diff

スタックをAWSにデプロイ

npx cdk deploy --all

よく使うオプション(入門書より抜粋)

$ npx aws-cdk deploy SampleStack # スタックを指定してデプロイ
$ npx aws-cdk deploy --all --require-approval=never # デプロイ時の確認を⾏わない
$ npx aws-cdk deploy --all --hotswap # Lambda関数などの開発時に変更を⾼速に反映する
$ npx aws-cdk deploy --all --no-rollback # スタックの更新失敗時に⾃動ロールバックしない
$ npx aws-cdk deploy --all -c key=value # Context を指定

スタックの削除

❱❱❱ npx cdk destroy            
Are you sure you want to delete: AwsCdkStack (y/n)? y
AwsCdkStack: destroying... [1/1]

 ✅  AwsCdkStack: destroyed

Error

Error#1

❱❱❱ npx cdk synth
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
ERRO[0002] Can't add file /Users/me/Projects/aws-cdk-2/node_modules/aws-cdk-lib/aws-lambda-nodejs/lib/package-manager.js to tar: io: read/write on closed pipe 

Next Step

ここからはコマンドリファレンスを見ながら遊ぶとよいと思います。

付録

Lambaのデプロイと同時に関数を実行するサンプル。customResourceを使う。

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_lambda_nodejs as lambda } from "aws-cdk-lib"
import * as cr from 'aws-cdk-lib/custom-resources';
import * as iam from 'aws-cdk-lib/aws-iam';

export class SimpleLambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    const simpleLambda = new lambda.NodejsFunction(this, "SimpleLambdaFunction", {
      entry: "lambda/index.ts",
      role: new iam.Role(this, 'LambdaExecutionRole', {
        assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
        managedPolicies: [
          iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')
        ]
      }),
    });

    const customResource = new cr.AwsCustomResource(this, 'InvokeSimpleLambda', {
      onCreate: {
        service: 'Lambda',
        action: 'invoke',
        parameters: {
          FunctionName: simpleLambda.functionName,
        },
        physicalResourceId: cr.PhysicalResourceId.of('InvokeSimpleLambdaUniqueId'),
      },
      policy: cr.AwsCustomResourcePolicy.fromSdkCalls({resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE})
    });

    simpleLambda.grantInvoke(customResource);

  }
}
脚注
  1. AWS CDKでDocker Desktopを使わずにLambda関数(aws_lambda_nodejs)をローカルビルドする ↩︎

  2. 普通のLamdaだとFunctionコンストラクトかな ↩︎

Discussion