Solutions ConstructsでAWSインフラ構築
先日、AWS Solutions Constructsが発表されました。これはAWS-CDKにおいて、抽象化されたリソースを表すConstructs
のよく使う組み合わせをWell-Architected準拠の設定込みで一発で構築できるライブラリです。例えばLambda + DynamoDB
やCloudFront + S3
などの組み合わせのパターンが25個(2020/7月現在)提供されています。
これをつかってパパっとAWS上にWebAPIを構築したいと思います。
注意
2020/7/6現在、Solutions ConstructsのstabilityはすべてExperimentalとなっています。
本番環境などでの使用はよく検討した上で行ってください。
環境
- AWS-CDK CLI v1.47.0
- ※ Solutions ConstrucsはCDK v1.46.0以上に対応しています。
- TypeScript v3.9.2
- npm v6.14.5
- node.js v12.18.0
使用するConstructs
今回は以下のSolutions Constructsを使用します。
構成図は以下のとおりです。
CDKによって、API Gateway, Lambda, Cognito, DynamoDBテーブルを作成します。
さらに、各リソースのオプションはデフォルトで下記のWell-Architected準拠の設定が施されています。
- Cognito
- ユーザープールに対するパスワードポリシーの設定
- ユーザープールに対するアドバンスドセキュリティの有効化
- API Gateway
- エンドポイントのエッジ最適化設定
- アクセスログの有効化
- 最小限のIAMロールの設定
- すべてのメソッドに対するIAM認証設定
- Lambda
- 最小限のIAMロールの設定
- ログ出力の有効化
- keep-alive時のコネクション再利用設定(Node.jsファンクション)
- DynamoDB
- オンデマンドモードの設定
- AWSマネージドCMKによる暗号化設定
作成手順
AWS-CDK CLIをグローバルインストールします。
npm install -g aws-cdk
インストール後にプロジェクトを作成します。
cdk init app --language=typescript
今回使用するライブラリをインストールします。(SolutionsConstructsの最新verが1.47.0なので統一)
npm install -s @aws-cdk/aws-lambda@1.47.0 @aws-cdk/aws-apigateway@1.47.0 @aws-cdk/aws-dynamodb@1.47.0 @aws-cdk/aws-cognito@1.47.0 @aws-solutions-constructs/aws-cognito-apigateway-lambda@1.47.0 @aws-solutions-constructs/aws-lambda-dynamodb@1.47.0
Constructsを使ってCDKを記述します。
import * as cdk from "@aws-cdk/core";
import * as lambda from "@aws-cdk/aws-lambda";
import { CognitoToApiGatewayToLambda } from "@aws-solutions-constructs/aws-cognito-apigateway-lambda";
import { LambdaToDynamoDB } from "@aws-solutions-constructs/aws-lambda-dynamodb";
import {
AttributeType,
BillingMode,
TableEncryption,
} from "@aws-cdk/aws-dynamodb";
export class CdkWebappStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
const apigwToLambda = new CognitoToApiGatewayToLambda(
this,
"CognitoToApiGatewayToLambdaPattern",
{
deployLambda: true,
lambdaFunctionProps: {
runtime: lambda.Runtime.NODEJS_12_X,
handler: "index.handler",
code: lambda.Code.asset(`${__dirname}/lambda`),
},
}
);
new LambdaToDynamoDB(this, "LambdaToDynamoPattern", {
deployLambda: false,
existingLambdaObj: apigwToLambda.lambdaFunction, // 生成済みのLambdaを使用
dynamoTableProps: {
partitionKey: { name: "id", type: AttributeType.STRING },
// デフォルトの設定は以下の通り
// キャパシティーモード: オンデマンド
// 暗号化タイプ: KMS - AWSマネージドCMK
// 無料枠で使用するために設定を変更している。
billingMode: BillingMode.PROVISIONED,
readCapacity: 5,
writeCapacity: 5,
encryption: TableEncryption.DEFAULT,
},
});
}
}
lib/lambdaディレクトリにはlambdaのソースを配置します。
const { DynamoDB } = require("aws-sdk");
exports.handler = async function (event) {
console.log("request:", JSON.stringify(event, undefined, 2));
// create AWS SDK clients
const dynamo = new DynamoDB();
// APIのパスをパーティションキーとして、アクセス回数を記録する
await dynamo
.updateItem({
TableName: process.env.DDB_TABLE_NAME,
Key: { id: { S: event.path } },
UpdateExpression: "ADD hits :incr",
ExpressionAttributeValues: { ":incr": { N: "1" } },
})
.promise();
return {
statusCode: 200,
headers: { "Content-Type": "text/plain" },
body: `Hello, AWS Solutions Constructs! You've hit ${event.path}\n`,
};
};
以下のコマンドでインフラをデプロイできます
npm run build && cdk deploy
cdk deploy
実行時にリソースのデプロイ確認があるので、yを入力してデプロイを開始しましょう。
API Gatewayのコンソールから/foo
メソッドのテストをおこなうと正常にレスポンスが返されることが確認できます。
また、DynamoDBに、アクセスしたパスの文字列とアクセス回数が記録されていることが確認できます。
まとめ
このように、Solution ConstructsではAWSでよく使われるリソースの組み合わせをConstructsをして提供してくれています。それを利用することで、爆速で今までよりもすばやく、かつ、Well-Architectedに準拠したインフラを構築することが可能になりました。