AWS CDKで作るサーバーレスデータベース基盤 【第1回】 Aurora Serverless V2構築
こんにちは!製造ビジネステクノロジー部の小林です。
「インフラをコードで管理したい」
「サーバーレスデータベースの実力が知りたい」
「CDK使ってみようかなあ」
そんな疑問や興味をお持ちの方に向けて、「AWS CDKで作るサーバーレスデータベース基盤」シリーズをスタートします!
このシリーズで学べること
AWS CDKの魅力は、おなじみのプログラミング言語でAWSリソースを定義できること。
第1回となる本記事では、
- AWS CDKの基本的な使い方
- Amazon Auroraの構築
を、実際のコード例とともに解説します。
最終ゴールは?
シリーズの最終回では、RDS ProxyとRDS Data APIを比較する予定です。
- どちらが高速なのか?
- どんなユースケースに向いているのか?
- 実装の難易度は?
AWS X-Ray、Apache Benchを活用し、実測データに基づいた分析で、それぞれのパフォーマンスを評価していきます。
ステップバイステップで解説していきますので、最後までお付き合いいただけたら嬉しいです。
本シリーズで使用する環境
- AWS CDK V2(TypeScript)
- AWS Lambda(TypeScript)
- Amazon API Gateway
- Amazon Aurora Serverless V2(PostgreSQL)
- Amazon RDS Proxy
- Amazon RDS Data API
システム構成図
以下は本シリーズで構築するシステムの全体像です。
今回の記事では、VPCとAurora Serverlessの部分を構築します。
最終的なディレクトリ構成
cdk-aurora
├── bin
│ └── main.ts # CDKアプリケーションのエントリーポイント
├── lambda
│ ├── data-api-lambda.ts # Data APIを使用するLambda関数のソースコード
│ ├── package-lock.json # Lambda関数の依存関係ロックファイル
│ ├── package.json # Lambda関数の依存関係定義
│ └── rds-proxy-lambda.ts # RDS Proxyを使用するLambda関数のソースコード
├── lib
│ ├── apigateway.ts # API Gatewayリソースを定義
│ ├── aurora.ts # Aurora Serverless v2リソースを定義
│ ├── lambda.ts # Lambda関数リソースを定義
│ ├── main-stack.ts # メインCDKスタック(全リソースの統合)
│ └── vpc.ts # VPCリソースを定義
├── package-lock.json # プロジェクト全体の依存関係ロックファイル
├── package.json # プロジェクト全体の依存関係とスクリプト定義
├── test # テストコードディレクトリ
├── tsconfig.json # TypeScriptコンパイラ設定
├── cdk.json # CDK設定ファイル
└── README.md
やってみる
環境
以下の環境で実装しています。CDKはTypeScriptで実装しています。
$ sw_vers
ProductName: macOS
ProductVersion: 14.7.4
BuildVersion: 23H420
$ node -v
v20.18.3
$ npm -v
10.8.2
$ cdk --version
2.1003.0 (build b242c23)
では構築していきます。
本記事では以下のリソースを構築します。
- Amazon VPC
- プライベートサブネット(2つのアベイラビリティゾーン)
- セキュリティグループ
- Amazon Aurora Serverless V2(PostgreSQL)
- PostgreSQL 16.1互換エンジン
- 最小容量: 0.5 ACU
- 最大容量: 1 ACU
- AWS Secrets Manager
- データベースのパスワード管理用
これらのリソースはAWS CDK V2を使用してTypeScriptで定義し、CloudFormationスタックとしてデプロイします。構築したAurora Serverless V2は、後続の記事で紹介するRDS Proxy、Lambda関数、API Gatewayと連携させる基盤となります。
CDKプロジェクトを作成します。
mkdir cdk-aurora
cd cdk-aurora
cdk init app --language=typescript
lib/vpc.tsファイルを作成し、VPCを定義します。
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
export class Vpc extends Construct {
public readonly vpc: ec2.Vpc;
constructor(scope: Construct, id: string) {
super(scope, id);
this.vpc = new ec2.Vpc(this, 'AuroraVpc', {
maxAzs: 2,
natGateways: 0,
subnetConfiguration: [
{
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
cidrMask: 24
}
]
});
}
}
lib/aurora.tsファイルを作成し、Aurora Serverless v2クラスターを定義します。
import * as cdk from 'aws-cdk-lib';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import { Construct } from 'constructs';
export class Aurora extends Construct {
public readonly cluster: rds.DatabaseCluster;
public readonly dbSecret: secretsmanager.Secret;
constructor(scope: Construct, id: string, vpc: ec2.Vpc) {
super(scope, id);
// データベース認証情報のシークレットを作成
this.dbSecret = new secretsmanager.Secret(this, 'AuroraSecret', {
generateSecretString: {
secretStringTemplate: JSON.stringify({ username: 'postgres' }),
generateStringKey: 'password',
excludeCharacters: '/@" ',
},
});
// セキュリティグループの作成
const dbSecurityGroup = new ec2.SecurityGroup(this, 'DBSecurityGroup', {
vpc,
description: 'Security group for Aurora Serverless v2',
allowAllOutbound: true,
});
// VPC内からの接続を許可
dbSecurityGroup.addIngressRule(
ec2.Peer.ipv4(vpc.vpcCidrBlock),
ec2.Port.tcp(5432),
'Allow database connections from within VPC'
);
// Aurora Serverless v2クラスターの作成
this.cluster = new rds.DatabaseCluster(this, 'AuroraCluster', {
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_16_1,
}),
credentials: rds.Credentials.fromSecret(this.dbSecret),
defaultDatabaseName: 'demodb',
vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
securityGroups: [dbSecurityGroup],
writer: rds.ClusterInstance.serverlessV2('Writer', {
autoMinorVersionUpgrade: true,
}),
serverlessV2MinCapacity: 0.5,
serverlessV2MaxCapacity: 1,
});
// 出力値の設定
new cdk.CfnOutput(this, 'ClusterEndpoint', {
value: this.cluster.clusterEndpoint.hostname,
description: 'Aurora Serverless v2 Cluster Endpoint',
});
new cdk.CfnOutput(this, 'SecretArn', {
value: this.dbSecret.secretArn,
description: 'Secret ARN for database credentials',
});
new cdk.CfnOutput(this, 'DatabaseName', {
value: 'demodb',
description: 'Default Database Name',
});
}
}
lib/main-stack.tsファイルを作成し、スタック全体を組み立てます。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Vpc } from './vpc';
import { Aurora } from './aurora';
export class MainStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// VPCの作成
const vpcStack = new Vpc(this, 'VpcConstruct');
// Aurora Serverless v2の作成
const auroraStack = new Aurora(this, 'AuroraConstruct', vpcStack.vpc);
}
}
bin/main.tsファイルを更新して、main-stackを参照するようにします。
import * as cdk from 'aws-cdk-lib';
import { MainStack } from '../lib/main-stack';
const app = new cdk.App();
new MainStack(app, 'MainStack', {
});
最後に、cdk.jsonの2行目のbin/をmain.tsに修正します。
{
"app": "npx ts-node --prefer-ts-exts bin/main.ts",
"watch": {
"include": [
"**"
],
# 省略...
デプロイしていく
これでコードの準備ができました。
デプロイする前に、CDKが初めての環境では「ブートストラップ」が必要です。
ブートストラップの詳細については以下をご参照ください。
# CDKブートストラップ(初回のみ)
cdk bootstrap
# デプロイ前の構文チェックとCloudFormationテンプレート生成
cdk synth
cdk synthコマンドを実行すると、CDKが定義したインフラストラクチャがどのようなCloudFormationリソースに変換されるかが表示されます。コマンド実行結果の一部を見てみましょう。
VPCとサブネット
VpcConstructAuroraVpcF6C2749C:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
# 省略...
VpcConstructAuroraVpcPrivateSubnet1Subnet7CEADCDF:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: false
Tags:
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Isolated
# 省略...
VPCと2つのプライベートサブネット(アベイラビリティゾーンごとに1つずつ)が作成されます。
サブネットタイプはIsolatedとなっており、インターネットへの接続がないことがわかります。
Secret
AuroraConstructAuroraSecretB62C0F2A:
Type: AWS::SecretsManager::Secret
Properties:
GenerateSecretString:
ExcludeCharacters: '/@" '
GenerateStringKey: password
SecretStringTemplate: '{"username":"postgres"}'
# 省略...
Secrets Managerにデータベースの認証情報が保存されます。
パスワードは自動生成され、ユーザー名は「postgres」に設定されています。
セキュリティグループ
AuroraConstructDBSecurityGroup87E99755:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for Aurora Serverless v2
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: "-1"
SecurityGroupIngress:
- CidrIp:
Fn::GetAtt:
- VpcConstructAuroraVpcF6C2749C
- CidrBlock
Description: Allow database connections from within VPC
FromPort: 5432
IpProtocol: tcp
ToPort: 5432
# 省略...
データベース用のセキュリティグループが作成され、VPC内からの5432ポート(PostgreSQL)へのアクセスが許可されています。
Aurora Serverless v2クラスター
AuroraConstructAuroraClusterC9A177F7:
Type: AWS::RDS::DBCluster
Properties:
CopyTagsToSnapshot: true
DBClusterParameterGroupName: default.aurora-postgresql16
DBSubnetGroupName:
Ref: AuroraConstructAuroraClusterSubnetsA9C71745
DatabaseName: demodb
Engine: aurora-postgresql
EngineVersion: "16.1"
# 省略...
ServerlessV2ScalingConfiguration:
MaxCapacity: 1
MinCapacity: 0.5
# 省略...
Aurora Serverless v2クラスターが作成され、PostgreSQL 16.1エンジンを使用しています。
最小キャパシティは0.5 ACU、最大キャパシティは1 ACUに設定されています。
DBインスタンス(ライター)
AuroraConstructAuroraClusterWriter49EBEE50:
Type: AWS::RDS::DBInstance
Properties:
AutoMinorVersionUpgrade: true
DBClusterIdentifier:
Ref: AuroraConstructAuroraClusterC9A177F7
DBInstanceClass: db.serverless
Engine: aurora-postgresql
PromotionTier: 0
PubliclyAccessible: false
# 省略...
Serverlessインスタンスタイプ(db.serverless)を使用したライターインスタンスが作成されます。
出力値
Outputs:
AuroraConstructClusterEndpointAD49D660:
Description: Aurora Serverless v2 Cluster Endpoint
Value:
Fn::GetAtt:
- AuroraConstructAuroraClusterC9A177F7
- Endpoint.Address
AuroraConstructSecretArnE826CA4E:
Description: Secret ARN for database credentials
Value:
Ref: AuroraConstructAuroraSecretB62C0F2A
AuroraConstructDatabaseName66DB7FE9:
Description: Default Database Name
Value: demodb
デプロイ後に参照できる重要な情報(クラスターエンドポイント、シークレットARN、データベース名)が出力値として定義されています。
cdk synthコマンドは、実際のデプロイ前にCloudFormationテンプレートを確認することで、意図したリソースが正しく定義されているかを検証するのに役立ちますね。
# デプロイを実行
cdk deploy
デプロイが完了すると、以下のような出力が表示されます。
デプロイ時間
約624秒(10分24秒)かかりました。
CloudFormationのコンソールでも確認してみましょう。
VPC、Secret、セキュリティグループ、Auroraが作成されていますね。
RDSのコンソールです。Aurora Serverless V2が作成できました!
おわりに
今回は「AWS CDKで作るサーバーレスデータベース基盤」の第1回として、AWS CDKを使用してAmazon Aurora Serverless v2をデプロイする方法を解説しました。
今回構築したAurora Serverless v2は、次回以降構築していくサーバーレスアプリケーションの重要な基盤となります。
次回は、API Gateway + Lambda + RDS Proxyを利用して、リクエストを受け付けるAPIを構築し、Lambdaを通じてAurora Serverless v2に接続するフローを解説します。
最後までお読みいただき、ありがとうございました。