AWS Workshop「Building CI/CD pipelines for lambda canary deployments using AWS CDK 」をTypeScriptで試してみる(前編)
AWS CDK を試してみたいと思っていたところ、以下のワークショップ資料を見つけたので、 今回はそちらに沿って、AWS CDK (TypeScript)で Lambda カナリアデプロイを試してみた記事になります。 catalog.us-east-1.prod.workshops.aws
ワークショップでは Python を使用していましたが、今回は TypeScript で実装してみました! 前編となる今回の記事では、CDK のインストールから Lambda カナリアデプロイまでを試してみます。
こんな人向け
「AWS Workshops」とは
AWSおよびAWSパートナーによって作成されたワークショップで、実践的なスキルやテクニックを紹介しており、現在100ものコンテンツが公開されています。
「AWS Cloud Development Kit(CDK)」 とは
AWS Cloud Development Kit (CDK) は、AWSインフラを Python, TypeSctipt, Java といったアプリケーション言語で定義し、AWS CloudFormation を通じてプロビジョニングできるツール。 同様なツールとして Terraform があげられますが、Terraform は独自言語を利用することから、使い慣れた言語で記述する AWS CDK と大きく違うところですね。
カナリアデプロイ とは
アプリケーションの新しいバージョンをデプロイする際に、最初に一部のユーザーでテストを行い、段階的に新しいバージョンのアプリケーションへ切り替えていく方式。 Lambda カナリアデプロイは AWS CodeDeploy を利用して実現します。
概要がわかったところで、さっそくワークショップの資料に沿って進めていきます!
事前準備
こちらのワークショップのリンクに沿って準備します↓
prerequisitesprerequisites
必要なもの
・An AWS account
・AWS CLI
・Node.js
・AWS CDK Toolkit
・Git
・An IDE for your programming language
AWS CDK Toolkit のインストールもこれだけ
$ npm install -g aws-cdk
無事インストールできたようです!
$ cdk --verion 2.37.1 (build f15dee0)
Create your AWS CDK project
$ mkdir cdk-ts-lambda-canary-deploy && cd cdk-ts-lambda-canary-deploy
ワークショップ用のディレクトリを作成した後、TypeScript の CDK プロジェクトを作成します。
$ cdk init cdk-ts-lambda-canary-deploy --language typescript
Project structure
ファイル構造
├── README.md ├── bin │ └── cdk-ts-lambda-canary-deploy.ts ├── cdk.json ├── jest.config.js ├── lib │ └── cdk-ts-lambda-canary-deploy-stack.ts ├── package.json ├── test │ └── cdk-ts-lambda-canary-deploy.test.ts └── tsconfig.json
Entry point
bin/cdk-ts-lambda-canary-deploy.ts
スタックの生成処理を行うためのエントリーポイントを記載するファイル
Main stack
lib/cdk-ts-lambda-canary-deploy-stack.ts
リソース定義を記載するファイル
Adding our app configuration
Adding stack code
メインスタックの lib/cdk-ts-lambda-canary-deploy-stack.ts
ファイルにリソース定義を記載していきます。
いくつかポイントを絞って解説していきます!(コード全体は最後に記載の github をご確認ください)
`const environmentType = this.node.tryGetContext('environmentType')`
this.node.tryGetContext
で cdk.json に定義した context を取得できます。
const myLambda = new NodejsFunction(this, 'MyFunction', { functionName: context['lambda']['name'], handler: 'main', runtime: Runtime.NODEJS_16_X, entry: path.join(__dirname, '../lambda/handler.ts'), currentVersionOptions: { description: `Version deployed on ${currentDate}`, removalPolicy: RemovalPolicy.RETAIN } })
Lambda 関数を TypeScript で作成する場合は aws-cdk-lib/aws-lambda-nodejs の
NodejsFunction
を使います。 NodejsFunction は自動的に JS ファイルにコンパイルしたものを Lambda にデプロイしてくれます!
Adding lambda code
次に Lambda 関数の実装を行いましょう。
$ mkdir lambda && touch lambda/handler.ts
ワークショップと同様に簡単なメッセージを返す function を作成します。
$ npm install -D @types/aws-lambda
import { Handler } from 'aws-lambda'; export const main: Handler = async () => { return { statusCode: 200, body: JSON.stringify({ message: 'hello world', }), }; };
Modifying cdk.json file
cdk.json
ファイルを以下のように修正します。
{ "app": "npx ts-node --prefer-ts-exts bin/cdk-ts-lambda-canary-deploy.ts", : "context": { : "prefix": "cdk-workshop-stack", "qa": { "region": "ap-northeast-1", "lambda": { "name": "cdk-workshop-function-qa", "alias": "live", "stage": "qa" }, "tags": { "App":"cdk-workshop", "Environment": "QA", "IaC": "CDK" } }, "prod": { } } }
Modifying cdk-ts-lambda-canary-deploy.ts file
エントリーポイントの bin/cdk-ts-lambda-canary-deploy.ts
ファイルを修正します。
#!/usr/bin/env node import * as cdk from 'aws-cdk-lib'; import { CdkTsLambdaCanaryDeployStack } from '../lib/cdk-ts-lambda-canary-deploy-stack'; const app = new cdk.App(); const environmentType = app.node.tryGetContext('environmentType'); const environmentContext = app.node.tryGetContext(environmentType); const region = environmentContext['region']; const account = app.node.tryGetContext('account'); const stackName = `${app.node.tryGetContext("prefix")}-${environmentType}` new CdkTsLambdaCanaryDeployStack(app, stackName, { env: { account, region, } });
上記の定義により、environmentType=qa
の context が指定された場合は以下のプロパティが渡されます。
"region": "ap-northeast-1", "lambda": { "name": "cdk-workshop-function-qa", "alias": "live", "stage": "qa" }, "tags": { "App":"cdk-workshop", "Environment": "QA", "IaC": "CDK" }
Deploy the app
Running cdk bootstrap command
スタック以外に Lambda 関数など外部ファイルを含んでおり、CDK はこれらを S3 にアップロードしますが、そのS3 バケットを作成します。 リージョンごとに必要となります!
$ cdk bootstrap aws://AWS_ACCOUNT/REGION
Running cdk deploy command
$ cdk deploy -c environmentType=qa
Lambda からレスポンスが返ってくることを確認できました↓
$ curl https://2uxvuqmdf4.execute-api.ap-northeast-1.amazonaws.com/qa/ {"message":"hello world"}%
次に Lambda のメッセージを変更して、カナリアデプロイを試してみます!
lambda/handler.ts
ファイルを少し書き換えてみます。
import { Handler } from 'aws-lambda'; export const main: Handler = async () => { return { statusCode: 200, body: JSON.stringify({ message: 'hello world ver2', -> ここを変更 }), }; };
再度デプロイ!
$ cdk deploy -c environmentType=qa
AWS コンソールから確認して、トラフィックの10%が新しいバージョンに割り当てられてることが確認できます。
実際にリクエストを送ってみると、新しいバージョンにもリクエストが送られていることが確認できました!
$ for i in {1..10}; do curl -w '\n' https://2uxvuqmdf4.execute-api.ap-northeast-1.amazonaws.com/qa/; done {"message":"hello world"} {"message":"hello world"} {"message":"hello world"} {"message":"hello world ver2"} {"message":"hello world"} {"message":"hello world"} {"message":"hello world"} {"message":"hello world"} {"message":"hello world"} {"message":"hello world"}
5分後・・デプロイが完了!
再度リクエストを送ってみると、今後は全てのリクエストが新しいバージョンに送られていることが確認できたのでカナリアデプロイがうまくいってそうです🎉
$ for i in {1..10}; do curl -w '\n' https://2uxvuqmdf4.execute-api.ap-northeast-1.amazonaws.com/qa/; done {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"} {"message":"hello world ver2"}
Cleanup
$ cdk destroy -c environmentType=qa Are you sure you want to delete: cdk-workshop-stack-qa (y/n)? y cdk-workshop-stack-qa: destroying... ✅ cdk-workshop-stack-qa: destroyed
最後に
上記のワークショップで実装したコードは github にも載せているのでよければ参考にしてください!
AWS workshops のサイトは他にもいろいろなワークショップが公開されていたので、試してみたいと思います!