一、背景
1.1 問題:
同事反饋有可以鑑於目前幾次大的公有云事故,騰訊雲/阿里雲兩大公有云廠商尚且存在這樣令人觸目驚心的時刻,更何況其他廠商和我們的日常操作,有人的地方就有誤操作,百分之一的風險但如果一旦發生就是100%的問題,雖SLA但或多或少存在影響,客戶反饋如果阿里的A地域發生故障,例如地質災害或不可控因素引發的ecs無法訪問,用戶數據都在雲上無法操作情況下該如何,但考慮到不同地域災備的高額度IT成本,想採用每天ecs的冷備。
1.2 思路:
在最大程度的降低IT成本,又想在不可控大規模地域性災難面前做些什麼,每天凌晨業務低峯期對ECS製作鏡像,同時複製到其他的不同地域,如北京的鏡像複製到上海,當北京整個region異常情況下,可利用複製在目標地域的ECS創建出來,在此拋磚引玉,後續可以將ecs在目標地域開出來並關機,歸檔刪除之前的鏡像,等等。同樣可以將RDS備份也同樣備份到異地OSS內,目前阿里已經有EBS非常方便的災難情況下恢復RDS。利用此思路同意的適用於其他場景下。
1.3 blog地址
二、代碼
2.1 結構
如果多個實例可同時寫入配置文件,用,進行分割。
2.2 核心代碼
配置文件
# 阿里雲ak配置,建議採用子賬戶只授權ecs鏡像操作
[common]
# 阿里雲acccesskeyid
accessKeyId = LTAIhfXxxxxxxxx
# 阿里雲accesssecret
accessSecret = GwfAMvR4K2ELxxxxxxxxxxxxx
# log目錄名稱
logdir_name = logdir
# log文件名稱
logfile_name = ecsoperlog.log
# ecs源地域配置信息段
#支持在華北 1、華北 2、華北 3、華北 5、華東 1、華東 2 和華南 1 地域之間複製鏡像。涉及其他國家和地區地域時,可以 提交工單 申請
[source]
# 源地域實例regionid,可以參考:https://help.aliyun.com/document_detail/40654.html?spm=a2c1g.8271268.10000.5.5f98df25B98bhJ
s_RegionId = cn-shanghai
# 源實例id,可指定多個用,進行分隔
s_InstanceId = i-uf661wb708uvqc9jyhem,i-uf661wb708uvqc9jyhel
# 源端製作鏡像name
s_ImageName = api-source-image
# 源鏡像描述信息
s_Description = api-source-image源鏡像描述信息
# 鏡像複製目的地域配置信息段
[destination]
# 目的地域實例regionid,
d_DestinationRegionId = cn-qingdao
# 複製過來的鏡像名稱
d_DestinationImageName = api-destination-image
# 複製過來的鏡像描述信息
d_DestinationDescription = api-destination-image目的鏡像描述信息
image操作(製作鏡像->查看鏡像製作狀態->複製鏡像)
# 創建實例生成器
def _get_Instance(self):
for Instance in self.s_InstanceId_list.split(','):
yield Instance
def _create_image(self):
"""
創建鏡像
:return:返回鏡像id
"""
s_timer = time.strftime("%Y-%m-%d-%H:%M", time.localtime(time.time()))
request = CreateImageRequest.CreateImageRequest()
request.set_accept_format('json')
request.add_query_param('RegionId', self.s_RegionId)
request.add_query_param('InstanceId', self.s_InstanceId)
request.add_query_param('ImageName', self.s_ImageName + s_timer)
request.add_query_param('Description', self.s_Description + s_timer)
response = self.ecshelper.do_action_with_exception(request)
self.logoper.info('創建鏡像任務已提交,鏡像id:%s' % json.loads(response)["ImageId"])
print('創建鏡像任務已提交,鏡像id:%s' % json.loads(response)["ImageId"])
return json.loads(response)["ImageId"]
def _describe_image(self,imageid):
"""
查詢image狀態
:param imageid:
:return:
"""
request = DescribeImagesRequest.DescribeImagesRequest()
request.set_accept_format('json')
request.add_query_param('RegionId', self.s_RegionId)
request.add_query_param('ImageId', imageid)
response = self.ecshelper.do_action_with_exception(request)
# 進度 json.loads(response)['Images']['Image'][0]['Progress']
self.logoper.info('鏡像創建進度:%s' %json.loads(response)['Images']['Image'][0]['Progress'])
# 鏡像狀態
return json.loads(response)['Images']['Image'][0]['Status']
#鏡像複製
def _copy_image(self,imageid):
"""
鏡像複製
:param imageid:源鏡像id
:return: 複製成功後的鏡像id
"""
flag = True
while flag:
try:
if self._describe_image(imageid) == 'Available':
flag = False
else:
time.sleep(300)
except Exception as e:
pass
print('鏡像已經創建完成')
d_timer = time.strftime("%Y-%m-%d-%H:%M", time.localtime(time.time()))
request = CopyImageRequest.CopyImageRequest()
request.set_accept_format('json')
request.add_query_param('RegionId', self.s_RegionId)
request.add_query_param('DestinationRegionId', self.d_DestinationRegionId)
request.add_query_param('DestinationImageName', self.d_DestinationImageName + d_timer)
request.add_query_param('DestinationDescription', self.d_DestinationDescription + d_timer)
request.add_query_param('ImageId', imageid)
response = self.ecshelper.do_action_with_exception(request)
self.logoper.info('複製鏡像任務已提交,鏡像id:%s' % json.loads(response)['ImageId'])
print('複製鏡像任務已提交,鏡像id:%s' % json.loads(response)['ImageId'])
return json.loads(response)['ImageId']
三、測試
3.1 查看運行結果
3.2 查看web控制檯
源鏡像
添加了時間戳,方便查看
目的地域鏡像
3.3 查看日誌
四、優化
- 可以後續增加對指定天數的鏡像進行歸檔刪除