1. EBS 백업 방법
1-1. Data Lifecycle Manager
EBS 태그를 기반 12 또는 24 시간 기준으로 EBS의 Snapshot을 수행한다. 또한 Snapshot의 갯수를 조절할 수 있다. (예시 최근 7개)
1-2. CloudWatch Event - EC2 CreateSnapshot API call
CloudWatch Event를 통해서도 Snapshot이 가능하다. 그러나 문제는 아직 Delete Option은 존재하지 않는다.
일해라! 아마존!
2. EC2 Image 백업 방법
아직 AWS에서 EC2 AMI에 대한 자동 백업 서비스는 없음.
그러나 CloudWatch Event -> Lambda(aws sdk)를 통해서 아래와 같이 구현은 가능.
ec2List.json: AMI로 지정할 EC2 ID(ec2Id), AMI 저장 이름(name), 리부팅 옵션(noReboot), 만료일(expire)를 json 파일 생성
Lambda_main.py: ec2List.json에 담긴 List를 토대로 EC2 AMI를 백업
ec2List.json
{
"list":[
{"ec2Id":"i-0b4947ddfd80496ee", "name":"web", "noReboot":true, "expire":"7"},
{"ec2Id":"i-08bafac12c7892301", "name":"db", "noReboot":true, "expire":"3"},
{"ec2Id":"i-023ed8c9d4b97b14a", "name":"app", "noReboot":true, "expire":"1"}
]
}
Lambda_main.py
try:
import boto3
import json
import os
from collections import OrderedDict
from datetime import date, timedelta, datetime
from botocore.exceptions import ClientError
except ImportError:
HAS_BOTO = False
client = boto3.client('ec2')
sns = boto3.client('sns')
TODAY = date.today()
class Ec2List:
def __init__(self, ec2Id = None, name = None, noReboot = None, expire = None, createdDate = None, imageId = None):
self._ec2Id = ec2Id
self._name = name
self._noReboot = noReboot
self._expire = expire
self._createdDate = str(TODAY)
self._imageId = imageId
@classmethod
def get_json_file(cls):
result = []
try:
with open('./ec2List.json', 'r') as f:
createImageList = json.load(f)
for each in createImageList['list']:
createAmiManager = cls(each['ec2Id'], each['name'], each['noReboot'], each['expire'], TODAY)
result.append(createAmiManager)
return result
except IOError as e:
print('Exception - Failed EC2 List read file: {}'. format(e))
return None
def get_ec2_list(self):
return self
@property
def imageId(self):
return self._imageId
@imageId.setter
def imageId(self, imageId):
self._imageId = imageId
def create_amis(list):
for each in list:
ec2List = each.get_ec2_list()
try:
response = client.create_image(
Description='auto-backup-image',
DryRun=False,
InstanceId=ec2List._ec2Id,
Name=ec2List._name + '_' + ec2List._createdDate,
NoReboot=ec2List._noReboot
)
ec2List._imageId = response['ImageId']
except ClientError as e:
print('Exceptioin - Failed Create Image: {}'.format(e))
if ec2List._imageId != None:
try:
response = client.create_tags(
DryRun=False,
Resources=[
ec2List._imageId,
],
Tags=[
{
'Key': 'Name',
'Value': ec2List._name + '_' + ec2List._createdDate
},
{
'Key': 'ec2Id',
'Value': ec2List._ec2Id
},
{
'Key': 'createdDate',
'Value': ec2List._createdDate
},
{
'Key': 'expire',
'Value': ec2List._expire
},
{
'Key': 'backupManager',
'Value': 'auto'
},
{'Key': 'imageId',
'Value': ec2List._imageId
}
]
)
except ClientError as e:
print('Exceptioin - Failed Create Tag: {}'.format(e))
return None
def delete_amis():
createdDate = None
expire = None
imageId = None
convertDate = None
deleteImageList = []
try:
response = client.describe_images(
Filters=[
{
'Name': 'tag:backupManager',
'Values': [
'auto'
]
}
],
DryRun=False
)
except ClientError as e:
print('Exceptioin - Failed Describe Tag: {}'.format(e))
for each in response['Images']:
for tags in each['Tags']:
if tags['Key'] == 'createdDate':
createdDate = tags['Value']
if tags['Key'] == 'expire':
expire = tags['Value']
if tags['Key'] == 'imageId':
imageId = tags['Value']
convertDate = datetime.strptime(createdDate, '%Y-%m-%d').date()
compare = TODAY - convertDate
if (int(compare.days) >= int(expire)):
try:
client.deregister_image(
ImageId=imageId,
DryRun=False
)
except ClientError as e:
print('Exception: Failed Delete AMI {}'.format(e))
deleteImageList.append(each)
return deleteImageList
def sendMail(ec2InstanceList, deletedImageList):
createdImageList = []
failedImageList = []
for each in ec2InstanceList:
ec2List = each.get_ec2_list()
result = {
'ec2Id': ec2List._ec2Id,
'name': ec2List._name,
'noReboot': ec2List._noReboot,
'expire': ec2List._expire,
'createdDate': str(TODAY),
'imageId': ec2List._imageId
}
if ec2List._imageId != None:
createdImageList.append(result)
else:
failedImageList.append(result)
print('Created Image List: ' + json.dumps(createdImageList))
print('failed Image List: ' + json.dumps(failedImageList))
print('Deleted Image List: ' + json.dumps(deletedImageList))
try:
response = sns.publish(
TopicArn='arn:aws:sns:ap-northeast-2:557652101750:ec2_ami_managing',
Subject='EC2 AMI MANAGING',
Message='Created Image LIST: ' + json.dumps(createdImageList) + '\n\n\n' +
'Failed Image LIST: ' + json.dumps(failedImageList) + '\n\n\n'
'Deleted Image LIST: ' + json.dumps(
deletedImageList) + '\n\n\n'
)
except ClientError as e:
print('Exception: Failed Send Message {}'.format(e))
def main():
ec2list = Ec2List.get_json_file()
create_amis(ec2list)
delete_image_list = delete_amis()
sendMail(ec2list, delete_image_list)
if __name__ == '__main__':
main()
def handler(even, context):
main()
아래와 같이 CloudWatch Event에 Target을 Lambda로
그럼 매일 한 번 Image가 아래와 같이 백업되고 expire 기간이 지나면 삭제
백업이 실행된 후 결과 정보
Created Image List: [
{
"ec2Id": "i-0b4947ddfd80496ee",
"name": "web",
"noReboot": true,
"expire": "7",
"createdDate": "2018-09-22",
"imageId": "ami-0c04ec5874f1a4977"
},
...
{
"ec2Id": "i-023ed8c9d4b97b14a",
"name": "app",
"noReboot": true,
"expire": "1",
"createdDate": "2018-09-22",
"imageId": "ami-00a96d7622d7d3b29"
}
]
Failed Image List: [
{
"ec2Id": "i-0b4947ddfd80496ee",
"name": "web",
"noReboot": true,
"expire": "7",
"createdDate": "2018-09-22",
"imageId": null
},
...
{
"ec2Id": "i-023ed8c9d4b97b14a",
"name": "app",
"noReboot": true,
"expire": "1",
"createdDate": "2018-09-22",
"imageId": null
}
]
Deleted Image List: [
{
"Architecture": "x86_64",
"CreationDate": "2018-09-21T05:04:28.000Z",
"ImageId": "ami-0dffad17281f6ec89",
"ImageLocation": "557652101750/app_2018-09-21",
"ImageType": "machine",
...
"SriovNetSupport": "simple",
"Tags": [
{
"Key": "expire",
"Value": "1"
},
{
"Key": "backupManager",
"Value": "auto"
},
{
"Key": "Name",
"Value": "app_2018-09-21"
},
{
"Key": "createdDate",
"Value": "2018-09-21"
},
{
"Key": "ec2Id",
"Value": "i-023ed8c9d4b97b14a"
},
{
"Key": "imageId",
"Value": "ami-0dffad17281f6ec89"
}
],
"VirtualizationType": "hvm"
}
]
결과 정보를 AWS SNS를 사용하여 이메일로도 받을 수 있음!
그러나 언젠가... AMI life cycle도 나올 듯?
'Compute > EBS' 카테고리의 다른 글
AWS EBS Daily Snapshot (0) | 2016.02.24 |
---|---|
AWS EBS mount: unknown filesystem type ‘LVM2_member’ error (0) | 2016.01.28 |
AWS Elastic Block Store(EBS) 이해 (0) | 2015.11.18 |