実践!AWS CDK #22 RDS クラスター
はじめに
今回は RDS の Aurora DB クラスターを作成します。
クラスターの作成のみで DB インスタンスは作りません。(こいつは次回)
前回の記事はこちら。
AWS 構成図
設計
プロパティは以下の通り。
devio-stg-rds-cluster
項目 | 値 |
---|---|
DB クラスター ID | devio-stg-rds-cluster |
エンジン | Aurora MySQL |
エンジンバージョン | 5.7.mysql_aurora.2.10.0 |
キャパシティータイプ | プロビジョニング済み: シングルマスター |
DB 名 | devio |
マスターユーザー名 | admin(Secrets Manager から取得) |
マスターパスワード | Secrets Manager で自動生成 |
暗号化 | 有効 |
ログエクスポート | CloudWatch Logs: エラーログ |
メンテナンスウィンドウ | 月曜 4:30-5:00 JST(日曜 19:30-20:00 UTC) |
自動バックアップ | 有効(7 日) |
バックアップウィンドウ | 4:00-4:30 JST(19:00-19:30 UTC) |
サブネットグループ | devio-stg-rds-sng |
クラスターパラメータグループ | 前回作ったやつ |
VPC セキュリティグループ | devio-stg-sg-rds |
データベースポート | 3306 |
実装
RDS に関する処理を行うクラスに、ハイライト部分を追記しました。
import * as cdk from '@aws-cdk/core'; import { CfnDBSubnetGroup, CfnDBClusterParameterGroup, CfnDBParameterGroup, CfnDBCluster } from '@aws-cdk/aws-rds'; import { CfnSubnet, CfnSecurityGroup } from '@aws-cdk/aws-ec2'; import { CfnSecret } from '@aws-cdk/aws-secretsmanager'; import { Resource } from './abstract/resource'; import { SecretsManager, OSecretKey } from './secretsManager'; export class Rds extends Resource { public dbCluster: CfnDBCluster; private readonly subnetDb1a: CfnSubnet; private readonly subnetDb1c: CfnSubnet; private readonly securityGroupRds: CfnSecurityGroup; private readonly secretRdsCluster: CfnSecret; private static readonly databaseName = 'devio'; constructor( subnetDb1a: CfnSubnet, subnetDb1c: CfnSubnet, securityGroupRds: CfnSecurityGroup, secretRdsCluster: CfnSecret ) { super(); this.subnetDb1a = subnetDb1a; this.subnetDb1c = subnetDb1c; this.securityGroupRds = securityGroupRds; this.secretRdsCluster = secretRdsCluster; }; createResources(scope: cdk.Construct) { const subnetGroup = this.createSubnetGroup(scope); const clusterParameterGroup = this.createClusterParameterGroup(scope); const parameterGroup = this.createParameterGroup(scope); this.dbCluster = this.createCluster(scope, subnetGroup, clusterParameterGroup); } private createSubnetGroup(scope: cdk.Construct): CfnDBSubnetGroup { const subnetGroup = new CfnDBSubnetGroup(scope, 'RdsDbSubnetGroup', { dbSubnetGroupDescription: 'Subnet Group for RDS', subnetIds: [this.subnetDb1a.ref, this.subnetDb1c.ref], dbSubnetGroupName: this.createResourceName(scope, 'rds-sng') }); return subnetGroup; } private createClusterParameterGroup(scope: cdk.Construct): CfnDBClusterParameterGroup { const clusterParameterGroup = new CfnDBClusterParameterGroup(scope, 'RdsDbClusterParameterGroup', { description: 'Cluster Parameter Group for RDS', family: 'aurora-mysql5.7', parameters: { time_zone: 'UTC' } }); return clusterParameterGroup; } private createParameterGroup(scope: cdk.Construct): CfnDBParameterGroup { const parameterGroup = new CfnDBParameterGroup(scope, 'RdsDbParameterGroup', { description: 'Parameter Group for RDS', family: 'aurora-mysql5.7' }); return parameterGroup; } private createCluster(scope: cdk.Construct, subnetGroup: CfnDBSubnetGroup, clusterParameterGroup: CfnDBClusterParameterGroup): CfnDBCluster { const cluster = new CfnDBCluster(scope, 'RdsDbCluster', { engine: 'aurora-mysql', backupRetentionPeriod: 7, databaseName: Rds.databaseName, dbClusterIdentifier: this.createResourceName(scope, 'rds-cluster'), dbClusterParameterGroupName: clusterParameterGroup.ref, dbSubnetGroupName: subnetGroup.ref, enableCloudwatchLogsExports: ['error'], engineMode: 'provisioned', engineVersion: '5.7.mysql_aurora.2.10.0', masterUserPassword: SecretsManager.getDynamicReference(this.secretRdsCluster, OSecretKey.MasterUserPassword), masterUsername: SecretsManager.getDynamicReference(this.secretRdsCluster, OSecretKey.MasterUsername), port: 3306, preferredBackupWindow: '19:00-19:30', preferredMaintenanceWindow: 'sun:19:30-sun:20:00', storageEncrypted: true, vpcSecurityGroupIds: [this.securityGroupRds.attrGroupId] }); return cluster; } }
事前に Secrets Manager で作成しておいた マスターユーザー名
と マスターパスワード
を以下のコードでクラスターのプロパティに設定しています。
masterUserPassword: SecretsManager.getDynamicReference(this.secretRdsCluster, OSecretKey.MasterUserPassword), masterUsername: SecretsManager.getDynamicReference(this.secretRdsCluster, OSecretKey.MasterUsername),
[お詫び]
一貫性を保つため、これまでに作成した RDS 関連リソースの 論理 ID
と リソース名
を変更しました。
前回までの表記と異なる部分がありますのでご注意ください。すみませんが 最新のソースコード を 正 とさせてください。
変更箇所は こちら です。
メインのプログラムはこちら。
ハイライト部分を追記しました。
~ 省略 ~ export class DevioStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); ~ 省略 ~ // RDS const rds = new Rds( subnet.db1a, subnet.db1c, securityGroup.rds, secretsManager.secretRdsCluster ); rds.createResources(this); } }
セキュリティグループと Secrets Manager の Cfn インスタンスを Rds クラスのコンストラクタに追加で渡しています。
テスト
テストコードはこちら。
ハイライト部分を追記しました。
import { expect, countResources, haveResource, anything } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; import * as Devio from '../../lib/devio-stack'; test('Rds', () => { const app = new cdk.App(); const stack = new Devio.DevioStack(app, 'DevioStack'); expect(stack).to(countResources('AWS::RDS::DBSubnetGroup', 1)); expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { DBSubnetGroupDescription: 'Subnet Group for RDS', SubnetIds: anything(), DBSubnetGroupName: 'undefined-undefined-rds-sng' })); expect(stack).to(countResources('AWS::RDS::DBClusterParameterGroup', 1)); expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { Description: 'Cluster Parameter Group for RDS', Family: 'aurora-mysql5.7', Parameters: { time_zone: 'UTC' } })); expect(stack).to(countResources('AWS::RDS::DBParameterGroup', 1)); expect(stack).to(haveResource('AWS::RDS::DBParameterGroup', { Description: 'Parameter Group for RDS', Family: 'aurora-mysql5.7' })); expect(stack).to(countResources('AWS::RDS::DBCluster', 1)); expect(stack).to(haveResource('AWS::RDS::DBCluster', { Engine: 'aurora-mysql', BackupRetentionPeriod: 7, DatabaseName: 'devio', DBClusterIdentifier: 'undefined-undefined-rds-cluster', DBClusterParameterGroupName: anything(), DBSubnetGroupName: anything(), EnableCloudwatchLogsExports: ['error'], EngineMode: 'provisioned', EngineVersion: '5.7.mysql_aurora.2.10.0', MasterUsername: anything(), MasterUserPassword: anything(), Port: 3306, PreferredBackupWindow: '19:00-19:30', PreferredMaintenanceWindow: 'sun:19:30-sun:20:00', StorageEncrypted: true, VpcSecurityGroupIds: anything() })); });
以下を確認しています。
- DB クラスターのリソースが 1 つあること
- リソースのプロパティが正しいこと
確認
マネジメントコンソール上でリソースを確認してみましょう。
クラスターが作成されております。
インスタンスが紐付いていないのでエンドポイントのステータスは 作成中
ですが、こちらはインスタンスを作成すれば 利用可能
になるはずです。
設定したプロパティも正しく反映されています。
Secrets Manager から取得した マスターユーザー名
と マスターパスワード
も問題ありません。
ヨシ!
CloudFormation 版
今回のコードを CFn で書くと以下のようになります。
RdsDbCluster: Type: AWS::RDS::DBCluster Properties: Engine: aurora-mysql BackupRetentionPeriod: 7 DatabaseName: devio DBClusterIdentifier: devio-stg-rds-cluster DBClusterParameterGroupName: Ref: RdsDbClusterParameterGroup DBSubnetGroupName: Ref: RdsDbSubnetGroup EnableCloudwatchLogsExports: - error EngineMode: provisioned EngineVersion: 5.7.mysql_aurora.2.10.0 MasterUsername: Fn::Join: - "" - - "{{resolve:secretsmanager:" - Ref: SecretRdsCluster - :SecretString:MasterUsername}} MasterUserPassword: Fn::Join: - "" - - "{{resolve:secretsmanager:" - Ref: SecretRdsCluster - :SecretString:MasterUserPassword}} Port: 3306 PreferredBackupWindow: 19:00-19:30 PreferredMaintenanceWindow: sun:19:30-sun:20:00 StorageEncrypted: true VpcSecurityGroupIds: - Fn::GetAtt: - SecurityGroupRds - GroupId
設定したプロパティが多めなのでちょいと長いですね。
GitHub
今回のソースコードは コチラ です。
おわりに
DB クラスターの作成が完了しました。
通常はクラスターのみという構成はなかなかないと思いますが、今回のような単体での作成もできるんですね。
次回はこのクラスターにインスタンスを紐付けていきましょう。