共计 3472 个字符,预计需要花费 9 分钟才能阅读完成。
1、背景介绍
为了确保线上项目的稳定性,需要对 supervisor 多次重新拉启失败后的进程,进行钉钉告警,以便相关的技术人员能及时处理。
具体实现的效果如下:
2、基础知识
这里针对从没有接触过 supervisor 和钉钉机器人对读者的一个扫盲,如果你已经很熟悉了,可以直接跳过。
1、什么是 supervisor?
supervisor 是 python 编写的一个可靠的进程管理工具,它会对其管理的子进程进行监控,当进程出现意外 crash 的时候,它将会尝试重新拉起继续执行(可以设置最多拉起次数,一般也不会无限去拉起失败的进程)。我们只需要知道它的大概作用即可,具体可以参考 supervisor 官网
2、什么是钉钉机器人?
钉钉机器人,是基于钉钉软件的,对钉钉群功能对一种扩展。群机器人可以将第三方服务的信息聚合到群聊中,实现自动化的信息同步。机器人的种类有很多如 gitlab 机器人、github 机器人、cooding 机器人等,这里我们使用的是自定义机器人,具体可以参考官网介绍
3、配置自定义钉钉机器人
1、打开钉钉软件,找到机器人管理
2、单击机器人管理,出现机器人管理菜单,大概是这个样子
剩下的步骤在官网上已经有了很详细的说明,我就不再赘述了戳这里
到最后我们会得到一个带有 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