#概要
以下サイト内容を実施してみました。
簡単に言うと、RDSの障害時にLambdaを使って、
DRリージョンにスナップショットからRDSを復元します。
#前提条件
RDSはソースリージョンで作成しておきます。
ターゲットリージョンではDBサブネットグループのみ作成しておきます。
#目次
- Lambda用IAMロールの作成
-
【①RDSスナップショット取得】のLambda
- Lambda作成
- CloudWatch イベントでスケジュールの設定をする
-
【②DRリージョンにスナップショットコピー】のLambda
- Lambda作成
- SNSトピックを作成
- RDSイベントサブスクリプションを作成
-
【③DRリージョンにRDS復元】のLambda
- Lambda作成
- SNSトピックを作成
- RDSイベントサブスクリプションを作成
#手順
###1. Lambda用IAMロールの作成
まずはIAMロールを作っておきます。
今回は以下のポリシーを適用します。
(実際に使う場合は最小権限にしてください)
###2.【①RDSスナップショット取得】のLambda
それでは以下の部分を作っていきましょう。
####2-1.Lambda作成
Lambda作成の際は、1で作ったIAMロールを付与します。
コードは冒頭のサイト参照
import botocore
import datetime
import re
import logging
import boto3
#以下は自環境に合わせて書き換えてください
region='ap-northeast-1'
db_instance_class='db.t2.micro'
db_subnet='default-vpc-077737b0bf23840f2'
instances = ['irikura-db-1']
print('Loading function')
def lambda_handler(event, context):
source = boto3.client('rds', region_name=region)
for instance in instances:
try:
#timestamp1 = '{%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now())
timestamp1 = str(datetime.datetime.now().strftime('%Y-%m-%d-%H-%-M-%S')) + "lambda-snap"
snapshot = "{0}-{1}-{2}".format("mysnapshot", instance,timestamp1)
response = source.create_db_snapshot(DBSnapshotIdentifier=snapshot, DBInstanceIdentifier=instance)
print(response)
except botocore.exceptions.ClientError as e:
raise Exception("Could not create snapshot: %s" % e)
####2-2.CloudWatch イベントでスケジュールの設定をする
CloudWatchのイベント→ルールに移動します。
イベントソースはスケジュールにチェックを入れ、任意の間隔を指定します。
ターゲットは上記で作成したLambda関数を選択します。
ルールが作成できたら、
指定の間隔でRDSのスナップショットが作成されることを確認しておきます。
###3.【②DRリージョンにスナップショットコピー】のLambda
スナップショットが作成された際のRDSイベントから、
SNSでLambdaを起動してDRリージョンにスナップショットをコピーします。
####3-1.Lambda作成
Lambda作成の際は、1で作ったIAMロールを付与します。
コードは冒頭のサイト参照
import boto3
import botocore
import datetime
import re
import json
#以下は自環境に合わせて書き換えてください
SOURCE_REGION = 'ap-northeast-1'
TARGET_REGION = 'us-east-1'
iam = boto3.client('iam')
instances = ['irikura-db-1']
print('Loading function')
def byTimestamp(snap):
if 'SnapshotCreateTime' in snap:
return datetime.datetime.isoformat(snap['SnapshotCreateTime'])
else:
return datetime.datetime.isoformat(datetime.datetime.now())
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
account_ids = []
try:
iam.get_user()
except Exception as e:
account_ids.append(re.search(r'(arn:aws:sts::)([0-9]+)', str(e)).groups()[1])
account = account_ids[0]
source = boto3.client('rds', region_name=SOURCE_REGION)
for instance in instances:
source_instances = source.describe_db_instances(DBInstanceIdentifier= instance)
source_snaps = source.describe_db_snapshots(DBInstanceIdentifier=instance)['DBSnapshots']
source_snap = sorted(source_snaps, key=byTimestamp, reverse=True)[0]['DBSnapshotIdentifier']
source_snap_arn = 'arn:aws:rds:%s:%s:snapshot:%s' % (SOURCE_REGION, account, source_snap)
target_snap_id = (re.sub('rds:', '', source_snap))
print('Will Copy %s to %s' % (source_snap_arn, target_snap_id))
target = boto3.client('rds', region_name=TARGET_REGION)
try:
response = target.copy_db_snapshot(
SourceDBSnapshotIdentifier=source_snap_arn,
TargetDBSnapshotIdentifier=target_snap_id,
CopyTags = True)
print(response)
except botocore.exceptions.ClientError as e:
raise Exception("Could not issue copy command: %s" % e)
copied_snaps = target.describe_db_snapshots(SnapshotType='manual', DBInstanceIdentifier=instance)['DBSnapshots']
####3-2.SNSトピックを作成
サブスクリプションに3-1で作成したLambdaを指定します。
####3-3.RDSイベントサブスクリプションを作成
RDSに移動しイベントサブスクリプションを選択する。
イベントサブスクリプションの作成で名前を入力し、
ターゲットに3-2で作成したSNSトピックを指定する。
ソースは以下のように設定することで、スナップショット作成時に
SNSに通知がいき、SNSからLambdaを起動することができます。
###4.【③DRリージョンにRDS復元】のLambda
3の手順と同じように障害などのRDSイベントからSNSを利用してLambdaを起動させ、
DRリージョンでスナップショットからRDSを復元します。
####4-1.Lambda作成
Lambda作成の際は、1で作ったIAMロールを付与します。
コードは冒頭のサイト参照
import boto3
import botocore
import datetime
import re
import logging
#以下は自環境に合わせて書き換えてください
region='us-east-1'
db_instance_class='db.t2.micro'
db_subnet='test'
#db_subnet='subnet-12345d6a'
instances = ['irikura-db-1']
print('Loading function')
def byTimestamp(snap):
if 'SnapshotCreateTime' in snap:
return datetime.datetime.isoformat(snap['SnapshotCreateTime'])
else:
return datetime.datetime.isoformat(datetime.datetime.now())
def lambda_handler(event, context):
source = boto3.client('rds', region_name=region)
for instance in instances:
try:
source_snaps = source.describe_db_snapshots(DBInstanceIdentifier = instance)['DBSnapshots']
print ("DB_Snapshots:", source_snaps)
source_snap = sorted(source_snaps, key=byTimestamp, reverse=True)[0]['DBSnapshotIdentifier']
snap_id = (re.sub( '-\d\d-\d\d-\d\d\d\d ?', '', source_snap))
print('Will restore %s to %s' % (source_snap, snap_id))
response = source.restore_db_instance_from_db_snapshot(DBInstanceIdentifier=snap_id,DBSnapshotIdentifier=source_snap,DBInstanceClass=db_instance_class,DBSubnetGroupName=db_subnet,MultiAZ=False,PubliclyAccessible=False)
print(response)
except botocore.exceptions.ClientError as e:
raise Exception("Could not restore: %s" % e)
####4-2.SNSトピックを作成
以下のSNSトピックを作成し、
サブスクリプションに4-1で作成したLambdaを指定します。
####4-3.RDSイベントサブスクリプションを作成
RDSに移動しイベントサブスクリプションを選択する。
イベントサブスクリプションの作成で名前を入力し、
ターゲットに4-2で作成したSNSトピックを指定する。
ソースは以下のように設定することで、スナップショット作成時に
SNSに通知がいき、SNSからLambdaを起動することができます。
####詰まったところ
IAMロールはサービスリンクドロールをLambdaに使用すると、
CloudWatch logsにログが出力されていませんでした。
なので最初にIAMロールを作っておきましょう。
以下参照
####気になったところ
RDSのイベント通知が複数回くるので(例えばスナップショット取得開始・完了でそれぞれ)、その度にLambdaが起動している。
SNSサブスクリプションフィルターで指定の値のみ通知するようなフィルター機能はあるが、部分一致などの指定はできない。Lambda内に処理を加えた方がよいかも。