🕛
CDK作成のグローバルデータベースリストア簡易化
CDK作成グローバルデータベースのSnapShotからのリストアを出来る限り簡易化してみた
背景、目的
- 開発や運用中に時折発生するデータベースのリストア。コンソール上にてぽちぽちする分に簡単ですが、CDK管理下に置いたまま作業をするのは時間が掛かるため、面倒な印象でした
- 同じような境遇の方がどの程度いるかわかりませんが出来る限り、SnapShotからのリストアを簡易化してみましたので、参考にしていただけますと幸いです
前提事項
- よくある(自分調べ)本番ワークロードの環境を踏まえた構成並びに設定を想定
- Aurora Postgres
- Aurora 関連リソース命名固定
- 削除保護設定
利用サービス
- VPC
- RDS
- CodeBuild(CDK実行用途)
- CloudFormation
リストア作業
- Snapshotの実行
- SnapshotIdentifierをCDKコードに指定
- CodeBuild(CDK)実行
CDKでのリソース操作の流れ
- Aurora の削除保護を解除(CDKコマンド#1)
- 大阪リージョン及び東京リージョン Auroraリソースを全て削除(CDKコマンド#2)
- 東京リージョン及び大阪リージョン Auroraリソース復元開始(CDKコマンド#3)
コード解説
全量は GitHub を参照ください。
ここではポイントとなる箇所をかいつまんで解説します。
appファイル
コンテキストにて削除フラグを受け付けられるように作成
const app = new cdk.App();
// VPC
const vpcApne1 = new NetworkStack(app, "NetworkApne1", {
env: { region: "ap-northeast-1" },
});
const vpcApne3 = new NetworkStack(app, "NetworkApne3", {
env: { region: "ap-northeast-3" },
});
// Database
const databaseApne1 = new DatabaseStack(app, "DatabaseApne1", {
env: { region: "ap-northeast-1" },
vpc: vpcApne1.vpc,
appName: "test",
enableDeleteProtection:
app.node.tryGetContext("protection") === "false" ? false : true,
snapshotIdentifier:
app.node.tryGetContext("protection") === "false"
? undefined
: "arn:aws:rds:ap-northeast-1:402803229964:cluster-snapshot:test",
});
const databaseApne3 = new DatabaseStack(app, "DatabaseApne3", {
env: { region: "ap-northeast-3" },
vpc: vpcApne3.vpc,
appName: "test",
enableDeleteProtection:
app.node.tryGetContext("protection") === "false" ? false : true,
});
// CodeBuild
const codeBuildApne1 = new CodeBuildStack(app, "CodeBuildApne1", {
env: { region: "ap-northeast-1" },
});
ネットワーク作成
L2 コンストラクトを使用し、極力値を指定せずに作成
const vpc = new ec2.Vpc(this, "Vpc", {
maxAzs: 2,
subnetConfiguration: [
{
cidrMask: 24,
name: "Public",
subnetType: ec2.SubnetType.PUBLIC,
},
{
cidrMask: 24,
name: "Private",
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
{
cidrMask: 24,
name: "Isolated",
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});
データベース作成
削除保護無効化がPropertyにて簡単に切り替え可能に作成
snapshotIdentifierを指定する際はいくつか削除すべきPropertyがあるため、エスケープハッチにて削除
const auroraCluster = new rds.DatabaseCluster(this, "AuroraCluster", {
clusterIdentifier: `test-${this.region}-cluster-${props.appName}`,
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_16_6,
}),
writer: rds.ClusterInstance.provisioned("writer", {
publiclyAccessible: false,
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.R5,
ec2.InstanceSize.LARGE
),
instanceIdentifier: `test-${this.region}-instance`,
}),
vpc: props.vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
storageEncrypted: true,
deletionProtection: props.enableDeleteProtection,
});
const cfnDbCluster = auroraCluster.node.defaultChild as rds.CfnDBCluster;
if (this.region === "ap-northeast-1") {
const globalCluster = new rds.CfnGlobalCluster(this, "GlobalCluster", {
globalClusterIdentifier: "global-cluster",
sourceDbClusterIdentifier: cfnDbCluster.ref,
deletionProtection: props.enableDeleteProtection,
});
if (props.snapshotIdentifier) {
cfnDbCluster.snapshotIdentifier = props.snapshotIdentifier;
// ドキュメント指定のSnapshotIdentifier指定時に削除すべきpropertyを削除
// https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbcluster.html#cfn-rds-dbcluster-snapshotidentifier
cfnDbCluster.addPropertyDeletionOverride("GlobalClusterIdentifier");
cfnDbCluster.addPropertyDeletionOverride("MasterUsername");
cfnDbCluster.addPropertyDeletionOverride("MasterUserPassword");
cfnDbCluster.addPropertyDeletionOverride("ReplicationSourceIdentifier");
cfnDbCluster.addPropertyDeletionOverride("RestoreType");
cfnDbCluster.addPropertyDeletionOverride("SourceDBClusterIdentifier");
cfnDbCluster.addPropertyDeletionOverride("SourceRegion");
cfnDbCluster.addPropertyDeletionOverride("StorageEncrypted");
cfnDbCluster.addPropertyDeletionOverride("UseLatestRestorableTime");
}
} else if (this.region === "ap-northeast-3") {
cfnDbCluster.globalClusterIdentifier = "global-cluster";
cfnDbCluster.addPropertyDeletionOverride("MasterUsername");
cfnDbCluster.addPropertyDeletionOverride("MasterUserPassword");
cfnDbCluster.kmsKeyId = kms.Alias.fromAliasName(
this,
"DefaultRdsKey",
"alias/aws/rds"
).keyId;
}
振り返り
- 最低限の設定かつBuildSpecの内容もベタ書きのため、そのままコードは利用不可かと思いますがひとまずCodeBuildを一度実行するのみで、CDK作成グローバルデータベースのSnapShotからのリストアが可能なことは検証済みのため、参考にいただけますと幸いです
Discussion