CDKインフラストラクチャ
このドキュメントでは、MBC CQRS ServerlessフレームワークがAWS CDKを使用してプロビジョニングするAWSインフラストラクチャについて説明します。このアーキテクチャを理解することで、デプロイのカスタマイズや問題のトラブルシューティングに役立ちます。
システムアーキテクチャ概要
以下の図は、フレームワークによって作成される完全なAWSインフラストラクチャを示しています:
作成されるAWSリソース
認証(Cognito)
Amazon Cognitoはユーザー認証と認可を提供します:
CDK実装:
import * as cognito from 'aws-cdk-lib/aws-cognito';
// ユーザープールを作成
const userPool = new cognito.UserPool(this, 'UserPool', {
userPoolName: `${env}-${appName}-user-pool`,
selfSignUpEnabled: false,
signInAliases: {
username: true,
preferredUsername: true,
},
passwordPolicy: {
minLength: 6,
requireLowercase: false,
requireUppercase: false,
requireDigits: false,
requireSymbols: false,
},
mfa: cognito.Mfa.OFF,
accountRecovery: cognito.AccountRecovery.NONE,
deletionProtection: true,
customAttributes: {
tenant: new cognito.StringAttribute({ maxLen: 50, mutable: true }),
company_code: new cognito.StringAttribute({ maxLen: 50, mutable: true }),
member_id: new cognito.StringAttribute({ maxLen: 2048, mutable: true }),
roles: new cognito.StringAttribute({ mutable: true }),
},
});
// ユーザープールクライアントを作成
const userPoolClient = userPool.addClient('UserPoolClient', {
authFlows: {
userPassword: true,
userSrp: true,
},
});
API Gateway
HTTP APIはCognito認可付きのRESTfulエンドポイントを提供します:
CDK実装:
import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
import * as apigatewayv2Integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';
import * as apigatewayv2Authorizers from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
// HTTP APIを作成
const httpApi = new apigatewayv2.HttpApi(this, 'HttpApi', {
apiName: `${env}-${appName}-api`,
corsPreflight: {
allowOrigins: ['*'],
allowMethods: [apigatewayv2.CorsHttpMethod.ANY],
allowHeaders: ['*'],
maxAge: cdk.Duration.hours(1),
},
});
// Lambda統合
const lambdaIntegration = new apigatewayv2Integrations.HttpLambdaIntegration(
'LambdaIntegration',
lambdaFunction
);
// Cognitoオーソライザー
const cognitoAuthorizer = new apigatewayv2Authorizers.HttpUserPoolAuthorizer(
'CognitoAuthorizer',
userPool,
{ userPoolClients: [userPoolClient] }
);
// パブリックヘルスチェックルート
httpApi.addRoutes({
path: '/',
methods: [apigatewayv2.HttpMethod.GET],
integration: lambdaIntegration,
});
// 保護されたAPIルート
httpApi.addRoutes({
path: '/{proxy+}',
methods: [
apigatewayv2.HttpMethod.GET,
apigatewayv2.HttpMethod.POST,
apigatewayv2.HttpMethod.PUT,
apigatewayv2.HttpMethod.DELETE,
apigatewayv2.HttpMethod.PATCH,
],
integration: lambdaIntegration,
authorizer: cognitoAuthorizer,
});
Lambda関数
メインコンピューティングレイヤーはNestJSアプリケーションを実行します:
CDK実装:
import * as lambda from 'aws-cdk-lib/aws-lambda';
// 依存関係用のLambdaレイヤーを作成
const lambdaLayer = new lambda.LayerVersion(this, 'MainLayer', {
layerVersionName: `${env}-${appName}-main-layer`,
code: lambda.Code.fromAsset('dist_layer'),
compatibleRuntimes: [lambda.Runtime.NODEJS_20_X],
compatibleArchitectures: [lambda.Architecture.ARM_64],
});
// Lambda関数を作成
const lambdaFunction = new lambda.Function(this, 'LambdaApi', {
functionName: `${env}-${appName}-lambda-api`,
runtime: lambda.Runtime.NODEJS_20_X,
architecture: lambda.Architecture.ARM_64,
handler: 'main.handler',
code: lambda.Code.fromAsset('dist'),
memorySize: 512,
timeout: cdk.Duration.seconds(30),
layers: [lambdaLayer],
tracing: lambda.Tracing.ACTIVE,
loggingFormat: lambda.LoggingFormat.JSON,
vpc: vpc,
vpcSubnets: { subnets: privateSubnets },
securityGroups: securityGroups,
environment: {
NODE_OPTIONS: '--enable-source-maps',
TZ: 'Asia/Tokyo',
NODE_ENV: env,
APP_NAME: appName,
LOG_LEVEL: 'info',
S3_BUCKET_NAME: ddbBucket.bucketName,
SNS_TOPIC_ARN: mainSnsTopic.topicArn,
COGNITO_USER_POOL_ID: userPool.userPoolId,
DATABASE_URL: databaseUrl,
},
});
SNSとSQS(イベント駆動メッセージング)
異なるイベントタイプに対するフィルタリング付きメッセージルーティング:
CDK実装:
import * as sns from 'aws-cdk-lib/aws-sns';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';
// SNSトピックを作成
const mainSnsTopic = new sns.Topic(this, 'MainSnsTopic', {
topicName: `${env}-${appName}-main-sns`,
});
const alarmSnsTopic = new sns.Topic(this, 'AlarmSnsTopic', {
topicName: `${env}-${appName}-alarm-sns`,
});
// デッドレターキューを作成
const taskDlq = new sqs.Queue(this, 'TaskDLQ', {
queueName: `${env}-${appName}-task-dead-letter-queue`,
});
// DLQ付きタスクキューを作成
const taskQueue = new sqs.Queue(this, 'TaskQueue', {
queueName: `${env}-${appName}-task-action-queue`,
deadLetterQueue: {
queue: taskDlq,
maxReceiveCount: 5,
},
});
// 通知キューを作成
const notificationQueue = new sqs.Queue(this, 'NotificationQueue', {
queueName: `${env}-${appName}-notification-queue`,
});
// Create Sub-task Status Queue (サブタスクステータスキューを作成)
const subTaskStatusQueue = new sqs.Queue(this, 'SubTaskStatusQueue', {
queueName: `${env}-${appName}-sub-task-status-queue`,
});
// インポートキューを作成
const importQueue = new sqs.Queue(this, 'ImportQueue', {
queueName: `${env}-${appName}-import-action-queue`,
});
// メッセージフィルタリングでキューをサブスクライブ
mainSnsTopic.addSubscription(
new subscriptions.SqsSubscription(taskQueue, {
filterPolicy: {
action: sns.SubscriptionFilter.stringFilter({
allowlist: ['task-execute'],
}),
},
rawMessageDelivery: true,
})
);
mainSnsTopic.addSubscription(
new subscriptions.SqsSubscription(notificationQueue, {
filterPolicy: {
action: sns.SubscriptionFilter.stringFilter({
allowlist: ['command-status', 'task-status'],
}),
},
rawMessageDelivery: true,
})
);
mainSnsTopic.addSubscription(
new subscriptions.SqsSubscription(subTaskStatusQueue, {
filterPolicy: {
action: sns.SubscriptionFilter.stringFilter({
allowlist: ['sub-task-status'],
}),
},
rawMessageDelivery: true,
})
);
mainSnsTopic.addSubscription(
new subscriptions.SqsSubscription(importQueue, {
filterPolicy: {
action: sns.SubscriptionFilter.stringFilter({
allowlist: ['import-execute'],
}),
},
rawMessageDelivery: true,
})
);
S3バケット
アプリケーションデータと静的アセットのストレージ:
CDK実装:
import * as s3 from 'aws-cdk-lib/aws-s3';
// DynamoDB属性バケット
const ddbBucket = new s3.Bucket(this, 'DdbAttributesBucket', {
bucketName: `${env}-${appName}-ddb-attributes`,
versioned: false,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
removalPolicy: cdk.RemovalPolicy.DESTROY,
cors: [
{
allowedMethods: [
s3.HttpMethods.GET,
s3.HttpMethods.PUT,
s3.HttpMethods.POST,
],
allowedOrigins: ['*'],
allowedHeaders: ['*'],
maxAge: 3000,
},
],
});
// パブリックアセットバケット
const publicBucket = new s3.Bucket(this, 'PublicBucket', {
bucketName: `${env}-${appName}-public`,
versioned: false,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
// Lambdaアクセスを付与
ddbBucket.grantReadWrite(lambdaFunction);
publicBucket.grantReadWrite(lambdaFunction);