RDS自動再起動保護
抄録
目次
🚀 Pulumiの概観
pulumi new aws-typescript
pulumi stack init
the Pulumi.<stack-name>.yaml
が設定されていないので、configpulumi config set aws:region ap-northeast-2
pulumi config set aws:profile myprofile
pulumi gen-completion bash > /etc/bash_completion.d/pulumi
.bashrc
エイリアス# add Pulumi to the PATH
export PATH=$PATH:$HOME/.pulumi/bin
alias plm='/home/vudao/.pulumi/bin/pulumi'
complete -F __start_pulumi plm
pulumi import aws:ec2/securityGroup:SecurityGroup vpc_sg sg-13a02c7a
pulumi refresh
🚀 解決概要
sns-rds-event
. ラムダ関数
start-step-func-rds
SNSトピックを購読しますsns-rds-event
RDS-EVENT-0153
( DBクラスタは最大許容時間を超えて起動しています).さらに、関数は、RDSインスタンスがタグ付けされていることを検証しますauto-restart-protection
そして、タグ値がyes
. AWSステップ関数ステートマシンは、インスタンスの状態を取得するためだけでなく、RDSインスタンスを停止しようとすると、2つのラムダ関数を統合します.
RDS-EVENT-0154
: DBインスタンスは、最大許容時間を超えたために開始されます.Pulumiを使ってIACを書き始めましょう
🚀 複数のインスタンスを持つRDSクラスタを作成する
- Create RDS cluster with one or more instances
- Using the imported existing VPC (optional)
rds.ts
import * as aws from "@pulumi/aws";
const vpc_sg = new aws.ec2.SecurityGroup("vpc_sg",
{
description: "Allows inbound and outbound traffic for all instances in the VPC",
name: "vpc-sec",
revokeRulesOnDelete: false,
tags: {
Name: "vpc-sec",
}
},
{
protect: true,
}
);
export const rds_cluster = new aws.rds.Cluster('SelTestRdsEventSub', {
//availabilityZones: ['ap-northeast-2a', 'ap-northeast-2c'],
clusterIdentifier: 'my-test-rds-sub',
engine: 'aurora-postgresql',
masterUsername: 'postgres',
masterPassword: '*****',
dbSubnetGroupName: 'aws-test',
databaseName: "mydb",
skipFinalSnapshot: true,
vpcSecurityGroupIds: [vpc_sg.id],
tags: {
'Name': 'my-test-rds-sub',
'stack': 'pulumi-rds',
'auto-restart-protection': 'yes'
}
});
export const clusterInstances: aws.rds.ClusterInstance[] = [];
for (const range = {value: 0}; range.value < 1; range.value++) {
clusterInstances.push(new aws.rds.ClusterInstance(`SelRdsClusterInstance-${range.value}`, {
identifier: `my-test-rds-sub-${range.value}`,
clusterIdentifier: rds_cluster.id,
instanceClass: aws.rds.InstanceType.T3_Medium,
engine: 'aurora-postgresql',
engineVersion: rds_cluster.engineVersion,
dbSubnetGroupName: 'aws-test',
tags: {
'Name': `my-test-rds-sub-${range.value}`,
'stack': 'pulumi-rds-instance',
'auto-restart-protection': 'yes'
}
}))
}
🚀 SNSトピックを作成し、RDSクラスタにイベントを購読する
- Create a SNS topic to receive events from RDS cluster
- Create event subscription:
- Target: the SNS topic
- Source Type: Clusters (and point to the cluster which created from above step)
- Specific event categories:
notification
index.ts
import * as aws from "@pulumi/aws";
import { state_machine_handler } from "./stepFunc";
import { rds_cluster } from "./rds";
const sns_rds_event = new aws.sns.Topic('SnsRdsEvent', {
displayName: 'sns-rds-event',
name: 'sns-rds-event',
tags: {
'Name': 'sns-rds-event',
'stack': 'plumi-sns'
}
});
const rds_event_sub = new aws.rds.EventSubscription('RdsEventSub', {
enabled: true,
name: 'rds-event-sub',
eventCategories: ['notification'],
sourceType: 'db-cluster',
sourceIds: [rds_cluster.id],
snsTopic: sns_rds_event.arn,
tags: {
'Name': 'rds-event-sub',
'stack': 'pulumi-event'
}
});
const sns_sub = new aws.sns.TopicSubscription('sns-topic-event-sub', {
endpoint: state_machine_handler.arn,
protocol: 'lambda',
topic: sns_rds_event.arn
});
sns_rds_event.onEvent('sns-lambda-trigger', state_machine_handler, sns_sub)
🚀 SNSトピックを購読するラムダ関数を作成する
- The lambda function will be triggerd by SNS topic whenever there's event
The lambda function parses the event message to filter event ID
RDS-EVENT-0153
and checks the RDS cluster tag for key:valueauto-restart-protection: yes
. If all conditions match, then the lambda function execute Step Functions state machineCreate IAM role which is consumed by lambda function
iam-role
export const allowRdsClusterRole = new aws.iam.Role("allow-stop-rds-cluster-role", {
name: 'lambda-stop-rds-cluster',
description: 'Role to stop rds cluster base on event',
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Sid: "",
Principal: {
Service: "lambda.amazonaws.com",
},
}],
}),
tags: {
'Name': 'lambda-stop-rds-cluster',
'stack': 'pulumi-iam'
},
});
const rds_policy = new aws.iam.RolePolicy("allow-stop-rds-cluster", {
role: allowRdsClusterRole,
policy: {
Version: "2012-10-17",
Statement: [
{
Sid: "AllowRdsStatement",
Effect: "Allow",
Resource: "*",
Action: [
"rds:AddTagsToResource",
"rds:ListTagsForResource",
"rds:DescribeDB*",
"rds:StopDB*"
]
},
{
Sid: "AllowSfnStatement",
Effect: "Allow",
Resource: "*",
Action: "states:StartExecution"
},
{
Sid: 'AllowLog',
Effect: 'Allow',
Resource: "arn:aws:logs:*:*:*",
Action: [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
}
]
},
}, {parent: allowRdsClusterRole});
- Create lambda function which is subscription of the SNS topic
start-step-func-lambda
export const state_machine_handler = new aws.lambda.Function('RdsSNSEvent',
{
code: new pulumi.asset.FileArchive('lambda-code/start-statemachine-execution-lambda/handler.tar.gz'),
description: 'Lambda function listen to RDS SNS event topic to trigger step function',
name: 'start-step-func-rds',
handler: 'app.handler',
runtime: aws.lambda.Runtime.Python3d8,
role: handler.allowRdsClusterRole.arn,
environment: {
variables: {
'STEPFUNCTION_ARN': stepFunction.arn
}
},
tags: {
'Name': 'start-step-func-rds',
'stack': 'pulumi-lambda'
}
},
{
dependsOn: [handler.allowRdsClusterRole]
}
);
- Create step function state machine with flowing definitions
StepfuncTS
import * as aws from '@pulumi/aws';
import * as pulumi from '@pulumi/pulumi';
import * as handler from './handler';
export const stepFunction = new aws.sfn.StateMachine('SfnRdsEvent', {
name: 'sfn-rds-event',
roleArn: handler.sfn_role.arn,
tags: {
'Name': 'sfn-rds-event',
'stack': 'pulumi-sfn'
},
definition: pulumi.all([handler.retrieve_rds_status_handler.arn, handler.stop_rds_cluster_handler.arn, handler.send_slack_handler.arn])
.apply(([retrieveArn, stopRdsArn, sendSlackArn]) => {
return JSON.stringify({
"Comment": "RdsAutoRestartWorkFlow: Automatically shutting down RDS instance after a forced Auto-Restart",
"StartAt": "retrieveRdsClustertate",
"States": {
"retrieveRdsClustertate": {
"Type": "Task",
"Resource": retrieveArn,
"TimeoutSeconds": 5,
"Retry": [
{
"ErrorEquals": [
"Lambda.Unknown",
"States.TaskFailed"
],
"IntervalSeconds": 3,
"MaxAttempts": 2,
"BackoffRate": 1.5
}
],
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "fallback"
}
],
"Next": "isRdsClusterAvailable"
},
"isRdsClusterAvailable": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.readyToStop",
"StringEquals": "yes",
"Next": "stopRdsCluster"
}
],
"Default": "waitFiveMinutes"
},
"waitFiveMinutes": {
"Type": "Wait",
"Seconds": 300,
"Next": "retrieveRdsClustertate"
},
"stopRdsCluster": {
"Type": "Task",
"Resource": stopRdsArn,
"TimeoutSeconds": 5,
"Retry": [
{
"ErrorEquals": [
"States.Timeout"
],
"IntervalSeconds": 3,
"MaxAttempts": 2,
"BackoffRate": 1.5
}
],
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "fallback"
}
],
"Next": "retrieveRdsClustertateStopping"
},
"retrieveRdsClustertateStopping": {
"Type": "Task",
"Resource": retrieveArn,
"TimeoutSeconds": 5,
"Retry": [
{
"ErrorEquals": [
"States.Timeout"
],
"IntervalSeconds": 3,
"MaxAttempts": 2,
"BackoffRate": 1.5
}
],
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "fallback"
}
],
"Next": "isRdsClusterStopped"
},
"isRdsClusterStopped": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.rdsClusterStatus",
"StringEquals": "stopped",
"Next": "sendSlack"
}
],
"Default": "waitFiveMinutesStopping"
},
"waitFiveMinutesStopping": {
"Type": "Wait",
"Seconds": 300,
"Next": "retrieveRdsClustertateStopping"
},
"sendSlack": {
"Type": "Task",
"Resource": sendSlackArn,
"TimeoutSeconds": 5,
"End": true
},
"fallback": {
"Type": "Task",
"Resource": sendSlackArn,
"TimeoutSeconds": 5,
"End": true
}
}
});
})
});
🚀 RDSクラスタとインスタンスのステータスを取得するラムダ関数を作成する
retrieve-rds-status.ts
export const retrieve_rds_status_handler = new aws.lambda.Function('RetrieveRdsStateFunc', {
code: new pulumi.asset.FileArchive('lambda-code/retrieve-rds-instance-state-lambda/handler.tar.gz'),
description: 'Lambda function to retrieve rds instance status',
name: 'get-rds-status',
handler: 'app.handler',
runtime: aws.lambda.Runtime.Python3d8,
role: allowRdsClusterRole.arn,
tags: {
'Name': 'get-rds-status',
'stack': 'pulumi-lambda'
}
});
🚀 RDSクラスタを停止するラムダ関数を作成する
stop-rds.ts
export const stop_rds_cluster_handler = new aws.lambda.Function('StopRdsClusterFunc', {
code: new pulumi.asset.FileArchive('lambda-code/stop-rds-instance-lambda/handler.tar.gz'),
description: 'Lambda function to retrieve rds instance status',
name: 'stop-rds-cluster',
handler: 'app.handler',
runtime: aws.lambda.Runtime.Python3d8,
role: allowRdsClusterRole.arn,
tags: {
'Name': 'stop-rds-cluster',
'stack': 'pulumi-lambda'
}
});
🚀 ラムダ送信機能
send-slack.ts
export const send_slack_handler = new aws.lambda.Function('SendSlackFunc', {
code: new pulumi.asset.FileArchive('lambda-code/send-slack/handler.tar.gz'),
description: 'Lambda function to send slack',
name: 'rds-send-slack',
handler: 'app.handler',
runtime: aws.lambda.Runtime.Python3d8,
role: allowRdsClusterRole.arn,
tags: {
'Name': 'rds-send-slack',
'stack': 'pulumi-lambda'
}
});
🚀 ラムダ関数をトリガーするSFN IAMロール
sfn-role.ts
export const sfn_role = new aws.iam.Role('SfnRdsRole', {
name: 'sfn-rds',
description: 'Role to trigger lambda functions',
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Sid: "",
Principal: {
Service: "states.ap-northeast-2.amazonaws.com",
},
}],
}),
tags: {
'Name': 'sfn-rds',
'stack': 'pulumi-iam'
}
});
🚀 Pulumiスタックを展開する
🚀 結論
We now can save time and save money with this solution. Plus, we will receive slack message when there're events
Although Pulumi Supports Many Clouds and provisioner and can visulize the resources chart within the stack but there're more options such as AWS Cloud Development Kit (CDK)
Ref: Field Notes: Stopping an Automatically Started Database Instance with Amazon RDS
.ltag__user__id__512906 .アクションボタン
背景色:こっち重要
色:168度62 df 88!重要
ボーダーカラー:こっち重要
}
🚀 Vu Dao 🚀 フォロー
🚀 AWSome Devops | AWS Community Builder | AWS SA || ☁️ CloudOpz ☁️
vumdao / vumdao
Reference
この問題について(RDS自動再起動保護), 我々は、より多くの情報をここで見つけました https://dev.to/aws-builders/rds-auto-restart-protection-1bd9テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol