11

1、背景介绍

为了确保线上项目的稳定性,需要对supervisor多次重新拉启失败后的进程,进行钉钉告警,以便相关的技术人员能及时处理。
具体实现的效果如下:
image.png

2、基础知识

这里针对从没有接触过supervisor和钉钉机器人对读者的一个扫盲,如果你已经很熟悉了,可以直接跳过。
1、什么是supervisor?
supervisor是python编写的一个可靠的进程管理工具,它会对其管理的子进程进行监控,当进程出现意外crash的时候,它将会尝试重新拉起继续执行(可以设置最多拉起次数,一般也不会无限去拉起失败的进程)。我们只需要知道它的大概作用即可,具体可以参考supervisor官网

2、什么是钉钉机器人?
钉钉机器人,是基于钉钉软件的,对钉钉群功能对一种扩展。群机器人可以将第三方服务的信息聚合到群聊中,实现自动化的信息同步。机器人的种类有很多如gitlab机器人、github机器人、cooding机器人等,这里我们使用的是自定义机器人,具体可以参考官网介绍

3、配置自定义钉钉机器人

1、打开钉钉软件,找到机器人管理
image.png

2、单击机器人管理,出现机器人管理菜单,大概是这个样子
image.png

剩下的步骤在官网上已经有了很详细的说明,我就不再赘述了戳这里

到最后我们会得到一个带有access_token的url链接,我们就是通过对这个url发起post请求进行告警,它大概是下面这个样子:

https://oapi.dingtalk.com/robot/send?access_token=XXXXXX

(ps:本文采用了ip限制的策略)

4、配置supervisor 的 eventlistener

首先,先看下supervisor eventlistner的配置文件内容:

[eventlistener:monitor]
command=/home/zero/supervisord.d/monitor.py
events=PROCESS_STATE_FATAL
stdout_logfile=/var/log/supervisor/script_log/monitor.log
stderr_logfile=/var/log/supervisor/script_log/monitor@error.log

简单的分析一下上面的配置
第一行:[eventlistener:monitor],接触过supervisor的同学都知道,一般情况下supervisor的子进程的配置第一行一般都是[program:进程名称], 而这里是 [eventlistener:监听者名称] 的形式,表明这个是一个关于事件监听者的配置,监听者的进程名称叫做monitor。
第二行:command=/home/zero/supervisord.d/monitor.py ,代表执行该进程的命令,下面会详细介绍一下,这里暂时忽略。
第三行:events=PROCESS_STATE_FATAL,代表监听者监听的事件。截止supervisor 4.1 这个版本,目前支持23个事件,它们分别是:

PROCESS_STATE
PROCESS_STATE_STARTING
PROCESS_STATE_RUNNING
PROCESS_STATE_BACKOFF
PROCESS_STATE_STOPPING
PROCESS_STATE_EXITED
PROCESS_STATE_STOPPED
PROCESS_STATE_FATAL
PROCESS_STATE_UNKNOWN
REMOTE_COMMUNICATION
PROCESS_LOG_STDOUT
PROCESS_LOG_STDERR
PROCESS_COMMUNICATION_STDOUT
PROCESS_COMMUNICATION_STDERR
SUPERVISOR_STATE_CHANGE
SUPERVISOR_STATE_CHANGE_RUNNING
SUPERVISOR_STATE_CHANGE_STOPPING
TICK_5
TICK_60
TICK_3600
PROCESS_GROUP
PROCESS_GROUP_ADDED
PROCESS_GROUP_REMOVED

详细的介绍可以查看这里
这里我们关注的是 PROCESS_STATE_FATAL 事件,这个事件是什么意思呢?下面是官网的洋文:

Indicates a process has moved from the BACKOFF state to the FATAL state. 
This means that Supervisor tried startretries number of times unsuccessfully to start the process, and gave up attempting to restart it.

当这个事件发生的时候,意味着supervisor的子进程从BACKOFF 变为了 FATAL状态。
意味着supervisor多次(重起次数,看自己的配置)尝试重启子进程,依然失败,决定放弃

第四行、第五行:代表着监听者在监听过程中 标准输出日志、错误日志的输出位置

5、编写eventlistener监听脚本

这里我们承接上面提到的command配置项,command配置的是eventlistener的真正监听的真正执行者,也就是上文提到的/home/zero/supervisord.d/monitor.py 脚本。理论上监听脚本可以用任何语言编写,但是由于supervisor本身是用python编写的,并且提供了一个名字叫做supervisor.childutils 的模块。这样一来使用python脚本去编写监听者将会异常的简单。官网上提供了一个简单的👇demo👇,而我们需要做的就是针对demo进行一个二次的开发,代码如下:

#!/usr/bin/env python
import sys
import urllib2
import json


def write_stdout(s):
    # only eventlistener protocol messages may be sent to stdout
    sys.stdout.write(s)
    sys.stdout.flush()

def write_stderr(s):
    sys.stderr.write(s)
    sys.stderr.flush()

def main():
    while 1:
        # transition from ACKNOWLEDGED to READY
        write_stdout('READY\n')

        # read header line and print it to stderr
        line = sys.stdin.readline()

        # read event payload and print it to stderr
        headers = dict([ x.split(':') for x in line.split() ])
        notifyData = sys.stdin.read(int(headers['len']))

        title = "warning online"
        content = "### supervisor sub process failed\n" + "> ![screenshot](一张图片的url地址)\n" + "> " + notifyData +"\n"

        url = "设置自定义机器人时得到的链接"
        headers = {'Content-Type':'application/json'}

        body = {'msgtype':'markdown', 'markdown':{'title':title, 'text':content, 'at':{'isAtAll':'true'}}}
        request = urllib2.Request(url,headers=headers,data=json.dumps(body))
        response = urllib2.urlopen(request)

        # transition from READY to ACKNOWLEDGED
        write_stdout('RESULT 2\nOK')

if __name__ == '__main__':
    main()

(ps:这里使用的是支持markdown 格式的告警内容)

好了,配置完毕,enjoy!!!由于个人能力有限,如有纰漏,不吝赐教!

6、参考资料

supervisor官网 http://www.supervisord.org/index.html
钉钉文档机器人的官网文档 https://ding-doc.dingtalk.com/doc#/serverapi2/krgddi


maweibinguo
783 声望36 粉丝

后端开发工程师一枚, keep moving