前言
Serverless架构在运维层面有着得天独厚的优势,不仅仅因为其事件触发可以有针对性的获取、响应一些事件,也因为其轻量化、低运维的特性让很多运维开发者甚是喜爱。
在实际生产中,如果可以将线上环境的变动以事件的形式触发函数,由函数进行系列的运维行为操作,那么Serverless将会在自动化运维的过程中发挥出更重要的作用和更大的价值,也会让传统服务的自动化运维变得更加简单,轻便。例如,当线上主机异常中止,此时可以触发函数,函数通过云厂商提供的API进行数据盘的备份,然后再对主机进行恢复;当服务器压力过大,可以通过云监控事件触发函数进行集群的扩容行为。当然,如果云厂商并没有为开发者们提供常见的云监控触发器等,将一些线上环境的变动以事件形式传递给函数,我们也可以考虑通过函数计算的定时触发器进行某些业务指标的轮训,进而实现对我们的传统业务进行部分自动化运维。
本文以阿里云函数计算与云监控触发器结合为例:假设一台云服务器ECS因系统错误而重启,传统情况下,运维人员或者ECS用户需要紧急响应,人工做验证,并需要创建快照等对服务进行一定的运维操作。本文将会站在Serverless架构的角度,通过云监控中的ECS重启事件触发函数执行,自动查找出ECS挂接的云盘,并给云盘自动创建了快照;同时本文也将会以腾讯云云函数与时间触发器结合为例,实现定时重启云主机的需求。
云盘自动快照
云盘自动快照这个功能是通过Serverless架构实现的自动化运维,整个项目将会分为两个主要部分:
- 业务逻辑
- 触发器配置
业务逻辑部分,主要是通过阿里云函数计算调用云盘相关的SDK,实现快照建立功能,触发器配置部分,则是通过云监控触发器,为对应的函数计算配置相关的触发条件。
在进行业务逻辑编写之前,我们需要清楚云监控触发器所产生的事件格式,即云监控在触发函数的时候,和函数计算所规约的事件数据结构(或者说是函数入口方法的event参数):
{
"product": "ECS",
"content": {
"executeFinishTime": "2018-06-08T01:25:37Z",
"executeStartTime": "2018-06-08T01:23:37Z",
"ecsInstanceName": "timewarp",
"eventId": "e-t4nhcpqcu8fqushpn3mm",
"eventType": "InstanceFailure.Reboot",
"ecsInstanceId": "i-bp18l0uopocfc98xxxx"
},
"resourceId": "acs:ecs:cn-hangzhou:12345678:instance/i-bp18l0uopocfc98xxxx",
"level": "CRITICAL",
"instanceName": "instanceName",
"status": "Executing",
"name": "Instance:SystemFailure.Reboot:Executing",
"regionId": "cn-hangzhou"
}
明确数据结构之后,可以进行核心业务逻辑的编写:
# -*- coding: utf-8 -*-
import logging
import json, random, string
from aliyunsdkcore import client
from aliyunsdkecs.request.v20140526.CreateSnapshotRequest import CreateSnapshotRequest
from aliyunsdkecs.request.v20140526.DescribeDisksRequest import DescribeDisksRequest
from aliyunsdkcore.auth.credentials import StsTokenCredential
LOGGER = logging.getLogger()
clt = None
def handler(event, context):
creds = context.credentials
sts_token_credential = StsTokenCredential(creds.access_key_id, creds.access_key_secret, creds.security_token)
evt = json.loads(event)
content = evt.get("content")
ecsInstanceId = content.get("ecsInstanceId")
regionId = evt.get("regionId")
global clt
clt = client.AcsClient(region_id=regionId, credential=sts_token_credential)
name = evt.get("name").lower()
if name in ['Instance:SystemFailure.Reboot:Executed'.lower(),
"Instance:InstanceFailure.Reboot:Executed".lower()]:
request = DescribeDisksRequest()
request.add_query_param("RegionId", regionId)
request.set_InstanceId(ecsInstanceId)
response = _send_request(request)
disks = response.get('Disks').get('Disk', [])
for disk in disks:
diskId = disk["DiskId"]
create_ecs_snap_by_id(diskId)
LOGGER.info("Create ecs snap success, ecs id = %s , disk id = %s ", ecsInstanceId, diskId)
def create_ecs_snap_by_id(disk_id):
LOGGER.info("Create ecs snap, disk id is %s ", disk_id)
request = CreateSnapshotRequest()
request.set_DiskId(disk_id)
request.set_SnapshotName("reboot_" + ''.join(random.choice(string.ascii_lowercase) for _ in range(6)))
response = _send_request(request)
return response.get("SnapshotId")
# send open api request
def _send_request(request):
request.set_accept_format('json')
try:
response_str = clt.do_action_with_exception(request)
LOGGER.info(response_str)
response_detail = json.loads(response_str)
return response_detail
except Exception as e:
LOGGER.error(e)
完成业务逻辑的核心代码之后,我们可以将代码部署到函数计算。然后再云监控的控制台,进行相关的触发设置,此时我们可以在阿里云云监控平台,选择事件监控,报警规则:
然后创建事件报警之后,我们可以选择事件报警规则:
完成配置之后,我们只需要将动作设置为函数计算即可,并选择我们刚刚部署的函数:
这样当ECS重启事件产生之后,云监控就会通过事件,触发指定的函数执行我们的自动化运维的业务逻辑:查找出ECS挂接的云盘,并给云盘自动创建快照。
服务器定时重启
当然,并不是所有的FaaS平台,都像阿里云函数计算一样拥有者云监控相关的触发器,可以非常简单、快速、轻松的感知到一些业务或者服务的变化,并以事件事发的形式,触发函数计算,实现自动化运维。当所使用的FaaS平台,本身不具备云监控类似的触发器,我们该如何来对服务器进行监控和自动化运维呢?
以作者在做的一个项目为例,项目有所使用的服务器需要每天凌晨对其进行初始化(即根据已有的镜像,重装系统)。在传统的架构下,需要有一个额外的服务来实现该功能,但是在Serverless架构下,只需要一个函数即可实现完整的业务逻辑,同时配置时间触发器,即可实现整个需求的开发:
# -*- coding: utf8 -*-
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.cvm.v20170312 import cvm_client, models
ImageId = ""
InstanceId = ""
secretId = ""
secretKey = ""
def main_handler(event, context):
try:
cred = credential.Credential(secretId, secretKey)
httpProfile = HttpProfile()
httpProfile.endpoint = "cvm.tencentcloudapi.com"
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
client = cvm_client.CvmClient(cred, "ap-shanghai", clientProfile)
req = models.ResetInstanceRequest()
params = '{"InstanceId":"%s","ImageId":"%s","LoginSettings":{"KeepImageLogin":"TRUE"}}' % (InstanceId, ImageId)
req.from_json_string(params)
resp = client.ResetInstance(req)
print(resp.to_json_string())
except Exception as err:
print(err)
完成业务逻辑的核心代码之后,可以将函数部署到线上,部署完成之后,还需要配置时间触发器(定时触发器),例如:
配置完成之后,就可以实现定时云主机的重装诉求,即每天凌晨,系统会根据我们指定的镜像,为我们重新初始化云主机。
总结
通过Serverless架构,可以将一些触发器和我们的业务逻辑非常友好的、简单的组合起来,无论是日志触发器、云监控触发器还是时间触发器,我们都可以通过与他们的结合,非常简单的、轻量化的定制自动化运维脚本。相对传统的自动化运维脚本而言,基于Serverless架构的会更加简单、更加轻量、更加稳定。
读者也可以发挥自己的想象,将更多的运维逻辑和Serverless架构进行结合,进一步拓展Serverless架构的应用场景。