もくじ
EC2のタグ
Key | Value |
Name | 任意の値 例) WP1 |
Backup-Generation | スナップショット世代数 例) 5 |
スナップショットを行いたいEC2のインスタンスにタグを設定します。
Lambda
(@see https://qiita.com/HorieH/items/66bb68d12bd8fdbbd076#select-metric-1)
import boto3 import collections import time from botocore.client import ClientError ec2 = boto3.client('ec2') def lambda_handler(event, context): descriptions = create_snapshots() delete_old_snapshots(descriptions) def create_snapshots(): instances = get_instances(['Backup-Generation']) descriptions = {} for i in instances: tags = {t['Key']: t['Value'] for t in i['Tags']} generation = int(tags.get('Backup-Generation', 0)) if generation < 1: continue for b in i['BlockDeviceMappings']: if b.get('Ebs') is None: continue volume_id = b['Ebs']['VolumeId'] description = volume_id if tags.get('Name') is '' else '%s(%s)' % (volume_id, tags['Name']) description = 'Auto Snapshot ' + description snapshot = _create_snapshot(volume_id, description) print 'create snapshot %s(%s)' % (snapshot['SnapshotId'], description) descriptions[description] = generation return descriptions def get_instances(tag_names): reservations = ec2.describe_instances( Filters=[ { 'Name': 'tag-key', 'Values': tag_names } ] )['Reservations'] return sum([ [i for i in r['Instances']] for r in reservations ], []) def delete_old_snapshots(descriptions): snapshots_descriptions = get_snapshots_descriptions(descriptions.keys()) for description, snapshots in snapshots_descriptions.items(): delete_count = len(snapshots) - descriptions[description] if delete_count <= 0: continue snapshots.sort(key=lambda x: x['StartTime']) old_snapshots = snapshots[0:delete_count] for s in old_snapshots: _delete_snapshot(s['SnapshotId']) print 'delete snapshot %s(%s)' % (s['SnapshotId'], s['Description']) def get_snapshots_descriptions(descriptions): snapshots = ec2.describe_snapshots( Filters=[ { 'Name': 'description', 'Values': descriptions, } ] )['Snapshots'] groups = collections.defaultdict(lambda: []) {groups[s['Description']].append(s) for s in snapshots} return groups def _create_snapshot(id, description): for i in range(1, 3): try: return ec2.create_snapshot(VolumeId=id, Description=description) except ClientError as e: print str(e) time.sleep(1) raise Exception('cannot create snapshot ' + description) def _delete_snapshot(id): for i in range(1, 3): try: return ec2.delete_snapshot(SnapshotId=id) except ClientError as e: print str(e) time.sleep(1) raise Exception('cannot delete snapshot ' + id)
- タイムアウト設定:Durationを20秒以上
※デフォルトは3秒、デフォルトだとエラーでこける場合があります。
Lambdaの実行ロールに下記のポリシーを設定する。
iam.json
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:*:*:*" ] }, { "Effect": "Allow", "Action": [ "ec2:DescribeInstances", "ec2:DescribeSnapshots", "ec2:CreateSnapshot", "ec2:DeleteSnapshot" ], "Resource": [ "*" ] } ] }
CloudWatch Events
cronの役割を設定します。
CloudWatch Eventsでスケジュール
- スケジュール:0 20 * * ? *
※”毎日、朝05時00分(JST)に実行する”という設定
※GMTとJSTの誤差は+9あるので、GMTに-9を行うとJSTで設定できる。GMTでしか設定できないのでこうするしかない。
世界標準時(経度0)より日本時間(経度135)は9時間速いと覚えておく。
Cloudwatchアラーム
- Whenever:Errors
- is: > 0
- for: 1 consecutive periods
- Period: 1 Day
- Statistic: Sum
○Action
Send notificationに
- topic name:任意の名前
- Email list:メールアドレス
Lambdaをテスト実行して、世代管理されていたらOK!
@see https://qiita.com/HorieH/items/66bb68d12bd8fdbbd076#select-metric-1