亚马逊AWS官方博客

企业微信、钉钉接收 Amazon CloudWatch 告警

一、背景介绍

我们看到一些国内的 AWS 用户,在使用企业微信和钉钉作为内部工作沟通平台。他们希望将Amazon CloudWatch 接收到的监控、告警信息发送到企业微信和钉钉等即时通讯工具中,方便统一运维。 Amazon CloudWatch 能够直接以邮件、短信的形式发送告警通知,也可以与 AWS Lambda 结合,通过 Amazon Connect 以电话的形式发送告警通知。

在这篇文章中,我们将会介绍如何通过 Amazon SNS 和 AWS Lambda 来实现将 AWS CloudWatch 告警信息发送到微信和钉钉。

CloudWatch 与 SNS、Lambda 配合使用常见流程如下:

以上架构中, Amazon CloudWatch 作为事件触发器,当它收到告警信息、定时任务、特定事件发生等事件时,它可以直接触发 AWS Lambda 来执行函数内容。业务将消息推送到 SNS ,由 SNS 来触发后续的操作。如: SNS  触发 AWS Lambda 执行、 SNS  发送邮件/短信通知等。

二、方案架构

本方案中 CloudWatch 接收 EC2 运行指标并进行监控。当 EC2 指标超出设定阈值后,CloudWatch 触发告警事件,并将事件消息通过 SNS 发送到 Lambda 函数。Lambda函数执行用户自定义的代码,包括:解析告警消息并发送到企业微信、钉钉机器人、或者 Prometheus 等平台。

架构中 AWS 服务简介:

Amazon CloudWatch  可以用来收集 AWS  包括 EC2 、 RDS 、 EKS 等各种服务运行日志也可以收集用户应用程序日志,可以作为 AWS 上日志数据集散地。同时在 CloudWatch 上可以设置基于指标的告警、基于时间和事件的规则,它可以与 Amazon SNS 和 Lambda 等其他AWS服务进行使用。

AWS Lambda 是无服务器的函数计算服务。通过  AWS Lambda ,无需预置或管理服务器即可运行代码。借助  Lambda ,您几乎可以为任何类型的应用程序或后端服务运行代码,而且完全无需管理。您可以将您的代码设置为自动从其他  AWS  服务如: CloudWatch 、 SNS 等触发,或者直接从任何  Web 或移动应用程序调用。

Amazon SNS 是一项用于应用与应用之间以及应用与人之间通信的完全托管型消息收发服务。

三、使用企业微信接收 CloudWatch 告警

企业微信端设置

  1. 注册企业微信账号
  2. 在企业微信中创建应用



创建完成后记录应用 Secret

    1. 企业微信告警流程

a) 获取 access_token ,参考微信官方说明文档

示例代码:

tokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"

def get_token():
values = {'corpid': ''<corpid>'', 'corpsecret': '<'corpsecret'>'}
req = requests.post(tokenUrl, params=values)
data = json.loads(req.text)
return data["access_token"]

 

b) 缓存和刷新 access_token

c) 调用具体的业务接口

示例代码:

sendMsg = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="

def send_msg(msg):
    url = sendMsg + get_token()
    print(url)
    values = """{"touser" : "<成员ID列表>" ,
      "msgtype":"text",
      "agentid":"<企业应用ID>",
      "text":{
        "content": "发送的告警内容!"
      },
      "safe":"0"
      }"""
    requests.post(url, values)

 

创建 Amazon SNS






确认已订阅

创建AWS Lambda 函数

配置 Lambda 环境变量

新建 corpid 和 corpsecret 环境变量,根据从企业微信获取的值填充。

为Lambda添加触发器:选择上一步创建的SNS作为触发器


打包并上传 Lambda 函数代码:

新建函数文件 lambda_function.py,内容如下:

#from botocore.vendored import requests
import requests
import json
import os

tokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"

corpid = os.getenv('corpid')
corpsecret = os.getenv('corpsecret')

def get_token():
    values = {'corpid': corpid, 'corpsecret': corpsecret}
    req = requests.post(tokenUrl, params=values)
    data = json.loads(req.text)
    return data["access_token"]

sendMsg = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="

def send_msg(msg):
    url = sendMsg + get_token()
    print(url)
    values = """{"touser" : "@all" ,
      "msgtype":"text",
      "agentid":"<微信应用agentid 替换>",
      "text":{
        "content": "%s"
      },
      "safe":"0"
      }""" % msg
    requests.post(url, values)

def lambda_handler(event, context):
    Message = json.loads(event['Records'][0]['Sns']['Message'])
    OldStateValue = Message['OldStateValue']
    NewStateValue = Message['NewStateValue']
    Timestamp = event['Records'][0]['Sns']['Timestamp']
    NewStateReason = json.loads(event['Records'][0]['Sns']['Message'])['NewStateReason']

    msg = "Alarm Details:\n"+"State Change:"+OldStateValue + " -> " + NewStateValue + "\n" \
        "Timestamp:" + Timestamp +"\n" \
        "Reason for State Change:" + NewStateReason

    print(msg)
    send_msg(msg)

 

本例中使用 python requests 库发送 post 请求,目前有两种办法实现:

  • 直接使用 vendored 中的 requests ,但该方法2021年1月30日以后将不能使用。故不做推荐。
  • 独立安装 requests 库,需要将包和 lambda 代码一起上传到 AWS Lambda 执行环境。以使用虚拟环境来安装函数依赖为例。参考文档
  1. 创建虚拟环境

python3 -m venv v-env

  1. 激活环境。

source v-env/bin/activate

  1. 使用 pip 安装库

pip install requests

  1. 停用虚拟环境

deactivate

  1. 使用库内容创建一个 ZIP 存档

cd v-env/lib/python3.7/site-packages

  1. 将函数代码添加到存档中
zip -r9 ${OLDPWD}/function.zip .
cd $OLDPWD
zip -g function.zip lambda_function.py
  1. 将二进制 ZIP 部署包上传到Lambda 并更新函数代码

创建EC2 CloudWatch告警并与SNS关联

选择要监控的 EC2 监控选项卡,创建警报。(下图是中国区控制台界面, AWS Global 控制台界面略有不同)

选择前面步骤创建的 SNS 主题,并选择合适的监控告警指标

测试告警接收

给 EC2 增加负载观察 CloudWatch 指标变化和告警情况

如上图所示, CPU 利用率已经超过设定阈值, CloudWatch 发出告警。

在 CloudWatch 日志组中查看 Lambda 日志


收到告警邮件

企业微信收到告警信息

四、使用钉钉接收CloudWatch告警

钉钉群设置

在接收告警信息的钉钉群中添加机器人,以下设置内容同钉钉官方说明:

按照以下步骤添加自定义钉钉机器人并获取 Webhook 地址。

  1. 在PC版钉钉上打开您想要添加报警机器人的钉钉群,并单击右上角的群设置图标。
  2. 在群设置面板中单击智能群助手。
  3. 在智能群助手面板单击添加机器人。
  4. 在群机器人对话框单击添加机器人区域的+图标,然后选择添加自定义。

5. 在机器人详情对话框单击添加。

6. 在添加机器人对话框中编辑机器人头像和名称,选中必要的安全设置(至少选择一  种),选中我已阅读并同意《自定义机器人服务及免责条款》。单击完成。

  1. 在添加机器人对话框中复制生成的机器人 Webhook 地址。

创建Amazon SNS

同上述配置企业微信告警 SNS 过程。

创建AWS Lambda

创建Lambda与上述配置企业微信过程基本相同,建议独立安装 requests 包并上传。 Lambda函数内容略有区别。创建钉钉告警 Lambda 环境变量和代码如下:

import requests
import json

def send_msg(msg):
    token = '16a9f365c63bca077649fa06760b73123a9047e678a984926f433cdeec1292ab'
    #token = os.getenv('token')
    url = "https://oapi.dingtalk.com/robot/send?access_token="
    url = url + token
    headers = {'Content-Type': 'application/json'}
    print(url)
    values = """{
      "msgtype":"text",
      "text":{
        "content": "%s"
      }
      }""" %msg
    
    print(values)
    request = requests.post(url, values,headers=headers)
    return request.text

def lambda_handler(event, context):
    Message = json.loads(event['Records'][0]['Sns']['Message'])
    OldStateValue = Message['OldStateValue']
    NewStateValue = Message['NewStateValue']
    Timestamp = event['Records'][0]['Sns']['Timestamp']
    NewStateReason = json.loads(event['Records'][0]['Sns']['Message'])['NewStateReason']

    msg = "Alarm Details:\n"+"State Change:"+OldStateValue + " -> " + NewStateValue + "\n" \
        "Timestamp:" + Timestamp +"\n" \
        "Reason for State Change:" + NewStateReason

    print(msg)
    send_msg(msg)

 

告警测试

测试方法同微信告警。给 EC2 增加负载(可以参考命令进行测试:for i in `seq 1 $(cat /proc/cpuinfo | grep “processor” | wc -l)`; do dd if=/dev/zero of=/dev/null & done),观察CloudWatch指标是否超过告警阈值。以下分别是钉钉告警 CloudWatch 日志和钉钉 app 接收到的告警信息示例。

五、总结

Amazon CloudWatch  作为AWS平台上告警和监控信息的集散地,将它与 SNS 、 Lambda 配合,利用 AWS Lambda 函数计算服务灵活的特点,可以将 AWS 服务的监控和告警信息轻松发送到微信、钉钉、 Zabbix 等第三方系统,实现自定义监控告警。

本篇作者

马卫军

AWS中国团队的解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,同时致力于AWS云服务在国内教育行业的应用和推广。有丰富的数据仓库以及大数据开发和架构设计经验。马卫军平时热爱爬山和足球,同时也乐于和他人分享自己的各种经历。