背景介绍
告警及事件通知是日常运维工作对系统状态进行实时感知的重要手段。在系统出现异常或问题时,监控或可观测平台应按照用户预设的故障条件和通知规则自动发送通知给到对应团队,使运维、研发团队快速发现和解决问题,减少停机时间,最大限度地提高用户满意度。
通常情况下,告警可以通过电子邮件、短信、电话或专用的通知工具发送给指定的接收者。对于不同SLA要求、不同基础设施架构、不同部署方式、不同运维目标要求的业务系统来说,告警通知策略的配置和触发应具备灵活性,适配不同的故障场景,满足各种故障通知要求。例如下面的一些可能导致告警触发的常见事件:
- 系统崩溃或关键服务停止运行。
- CPU、内存或磁盘空间超出预定阈值。
- 网络连接故障或数据传输速率下降。
- 用户错误或不正确的配置更改。
当这些事件发生时,告警功能会立即通知相关运维、研发人员,但不同的情况应提供不同的通知级别并综合考虑通知触达的时效性。例如发生了关键服务停止运行这种高等级故障,应以更加直接的通知方式触达相关人员,如语音电话通知。而非等待邮件、工单或短信等缺少强时效性保障的通知手段缓慢传递故障到运维团队。
在观测云的告警功能使用中,官方主要提供飞书、钉钉、微信机器人、邮件、短信等通知方式,同时预留了扩展接口功能(Webhook),允许客户自定义其他通知方式实现与观测云对接。本文介绍的就是如何借助观测云Function平台和Webhook扩展,实现电话告警通道功能的扩充。
方案简述
要实现电话告警,其一是观测云Studio告警通知对象的Webhook自定义功能。该功能允许用户自定义开发的Webhook接口与观测云Studio提供的Webhook自定义通知对象类型(如下图1所示)进行对接。当满足阈值条件的告警产生时,Studio可通过webhook调用户自定义逻辑,执行相关操作。
图1 观测云通知对象之Webhook自定义
其二,是观测云推出的DataFlux Func数据处理开发平台(以下简称Func)。该平台帮助用户快速搭建Python开发环境,开发相关处理逻辑代码。通过简单的步骤即可将这些逻辑发布为API接口,提供给Webhook调用来触发对应的处理。同时也将Webhook接收到的告警内容整理为电话告警接口所需字段结构。
最后需要用到电话告警的接口(该文使用阿里云语音服务中的语音验证码功能,其他服务商的语音服务类似),语音验证码的模版提供自定义变量,后续的Python脚本正是将观测云收到的告警字段文本内容填充到模版变量中,因此在电话播报验证码短信时,实现告警内容电话通知。
基于上述观测云的Webhook自定义、Func和阿里云提供的语音服务,我们便可实现观测云的告警升级。
接下来我们以一个场景来演示每个步骤如何落地。该场景假设我们监控的Kubernetes环境下的某namespace下pod的内存高于告警阈值,需要将指定的通知消息通过语音发送给某运维人员,以下是具体实现步骤。
实现步骤
1、资源准备
本例的语音服务以阿里云语音服务作为电话通知服务商,告警功能的配置使用观测云SaaS版申请的账号。在开始实施前需要准备相关的资源如下。
| 产品 | 功能模块 | 备注 |
|---|---|---|
| 观测云 | 通知对象管理-WebHook自定义 | 本文基于观测云SaaS环境实现 |
| DataFlux Func数据处理开发平台 | 授权链接 | 需开通Func托管版,或在独立的云主机/虚拟机上进行安装 |
| 语音服务(阿里云) | 语音验证码 | 接口SingleCallByTts |
2、实施过程
2.1 安装Function平台
在虚拟机/云主机/物理机上的Linux系统执行以下命令,下载Function平台资源包
/bin/bash -c "$(curl -fsSL func.guance.com/portable-download)" -- --for=GSE
进入下载好的安装包,执行下面的命令启动Function安装:
sudo /bin/bash {安装文件所在目录}/run-portable.sh
完成安装后,按照安装命令提示的地址,访问Function UI界面,进行配置数据库初始化并登录Function环境
2.2 开通语音服务
参考阿里云文档,开通语音服务并申请号码,申请模版并配置ACCESS_KEY_ID和ACCESS_KEY_SECRET。
本例中,我们使用专属号码和提供的默认语音模版:
配置语音模版,后续代码调用使用变量{product}和{code}。这里选用的模板内容以电话验证码举例,实际运维工作中,可更换为您所需的模板消息。
2.3 编写对接语音服务的Function功能脚本
下面是对接阿里云语音服务的完整脚本,注意以下字段的填写:
'ACCESS_KEY_ID', 'ACCESS_KEY_SECRET' 需要填写
'专属号码' '语音模版ID' '被呼叫人电话' 需要填写
注意:没有申请专属号码的,使用公用号码也可以,脚本处留为空。
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import os
import sys
import json
from typing import List
from alibabacloud_tea_openapi.client import Client as OpenApiClient
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_openapi_util.client import Client as OpenApiUtilClient
class Sample:
def __init__(self):
pass
@staticmethod
def create_client(
access_key_id: str,
access_key_secret: str,
) -> OpenApiClient:
"""
使用AK&SK初始化账号Client
@param access_key_id:
@param access_key_secret:
@return: Client
@throws Exception
"""
config = open_api_models.Config(
access_key_id=access_key_id,
access_key_secret=access_key_secret
)
# Endpoint 请参考 https://api.aliyun.com/product/Dyvmsapi
config.endpoint = f'dyvmsapi.aliyuncs.com'
return OpenApiClient(config)
@staticmethod
def create_api_info() -> open_api_models.Params:
"""
API 相关
@param path: params
@return: OpenApi.Params
"""
params = open_api_models.Params(
# 接口名称,
action='SingleCallByTts',
# 接口版本,
version='2017-05-25',
# 接口协议,
protocol='HTTPS',
# 接口 HTTP 方法,
method='POST',
auth_type='AK',
style='RPC',
# 接口 PATH,
pathname=f'/',
# 接口请求体内容格式,
req_body_type='json',
# 接口响应体内容格式,
body_type='json'
)
return params
@staticmethod
def main(
args: List[str],
) -> None:
#'ACCESS_KEY_ID', 'ACCESS_KEY_SECRET'需要填写
client = Sample.create_client('ACCESS_KEY_ID', 'ACCESS_KEY_SECRET')
params = Sample.create_api_info()
# query params
queries = {}
queries['CalledShowNumber'] = '专属号码'
queries['CalledNumber'] = '被呼叫人电话'
queries['TtsCode'] = '语音模版ID'
queries['TtsParam'] = args[0]
# runtime options
runtime = util_models.RuntimeOptions()
request = open_api_models.OpenApiRequest(
query=OpenApiUtilClient.query(queries)
)
# 复制代码运行请自行打印 API 的返回值
# 返回值为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
client.call_api(params, request, runtime)
rep = client.call_api(params, request, runtime)
print(queries)
print(rep)
@DFF.API('Webhook 对接')
def webhook_accept(**event):
namespace = json.loads(event['df_dimension_tags']).get('namespace')
mem_name = event.get('df_title')
mem_value = round(event.get('Result')/1000000)
tel_msg = {
"product":f'{namespace}的POD的{mem_name}',
"code":f'{mem_value}MB'
}
args = [str(tel_msg)]
Sample.main(args)
2.4 发布代码并配置授权链接
在Func平台完成脚本开发后,需要点击编辑界面的发布按钮,使脚本处在可引用的状态:
完成脚本发布后,点击「管理」-「授权链接」-「新建」,新建一个授权链接,即Func平台对外发布的API接口。授权链接配置时,在执行框中选择刚发布的脚本:
点击保存后,即可可在授权链接列表中看到对应的API接口。点击右边示例,获取WebHook地址:
复制该API,作为后续观测云Webhook通知对象的访问地址。
2.5 配置观测云自定义Webhook
登录观测云工作空间,点击「监控」-「通知对象管理」-「新建通知对象」,来创建一个自定义通知对象,类型选择Webhook自定义。将上面获取的Func API地址复制到Webhook地址,表示事件触发时调用这个地址触发相关操作。填写名称后保存该自定义对象,这里名称为“self”
2.6 配置观测云监控器
登录观测云工作空间,点击「监控」-「监控器」-「新建监控器」,创建一个内存监控的监控器实例。
其中,【事件标题】设定的事件内容留空,检测指标中,聚合条件by选择以namespace和pod_name聚合告警数据。后面可以作为参数,发送给Webhook以便在Func代码中引用这些变量。
新建告警策略,在通知配置中,选择通知对象为刚配置的“Self”
至此,电话通知通道的扩充操作已全部完成。当监控器配置的内存告警阈值达到告警条件时,观测云Studio会调用Webhook,通过阿里云语音服务,将相关的告警信息电话通知给指定接收号码,提升告警通知效率。
参考资料
云厂商语音模板
如何通过语音通知的功能,实现自身的系统、设备、服务器等相关的告警功能_语音服务-阿里云帮助中心
Function Webhook对接开发
接收观测云 Webhook 自定义告警 - DataFlux Func 文档库
Function安装要求
Function安装步骤