• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Vpegasus
E-mail: pegasus.wenjia@foxmail.com
博客园    首页    新随笔    联系   管理    订阅  订阅
使用prometheus与企业微信群机器人搭建服务监控告警系统

服务监控与告警

目录
  • 服务监控与告警
    • 0 简介
    • 1 Supervisor
      • 1.1 安装supervisor
      • 1.2 初始化supervisor
      • 1.3 启动supervisor
      • 1.4配置supervisord.conf
      • 1.5可能的问题
    • 2 node_exporter
      • 2.1安装node_exporter
    • 3. prometheus
        • 3.1 安装prometheus
    • 4 alertmanager
      • 4.1 安装alertmanager
    • 5 grafana
      • 5.1 安装grafana
      • 5.2 grafana board
    • 6 新建企业微信机器人
    • 7 编写 bridge服务
    • 8 服务监控服务

0 简介

服务监控与告警保证对服务的实时或准实时监控

​ 监控系统整体架构

Supervisor是一套通用的进程管理工具,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。这里用来管理监控所需要的几大组件,保证监控系统持续良好运行。Prometheus是开源监控报警系统, 其基本原理是通过HTTP协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。Alertmanager是一个独立的告警模块,接收Prometheus等客户端发来的警报,之后通过分组、删除重复等处理,并将它们通过路由发送给正确的接收器;告警方式可以按照不同的规则发送给不同的模块负责人。node_exporter用来监控服务器CPU、内存、磁盘、I/O等信息。

构建一整套监控系统需要做以下事情:

  1. 安装supervisor 管理接下来的监控系统;
  2. 安装prometheus
  3. 安装node exporter
  4. 安装altermanager
  5. 安装grafana
  6. 新建企业微信机器人
  7. 搭建bridge服务
  8. 配置supervisor
  9. 配置prometheus
  10. 配置altermanager
  11. 配置grafana
  12. 在服务端编写监控服务
  13. 在prometheus中配置监控规则
  14. 在grafana中新建监控项目(与告警项)
  15. 解析告警信息
  16. 其他事项...

1 Supervisor

1.1 安装supervisor

pip3 install supervisor

supervisor安装后会生成三个执行程序:supervisord, supervisorctl 及echo_supervisord_conf:

  • supervisord 用于管理supervisor 本身服务
  • supervisorctl 用于管理我们需要委托给supervisor管理的服务
  • echo_supervisord_conf 用于生成supervisor的配置文件

1.2 初始化supervisor

mkdir /etc/supervisord.d
echo_supervisord_conf > /etc/supervisord.conf

1.3 启动supervisor

启动:supervisord -c /etc/supervisord.conf
关闭:supervisorctl shutdown

常用命令:
supervisorctl stop program_name  # 停止某一个进程,program_name 为 [program:x] 里的 x
supervisorctl start program_name  # 启动某个进程
supervisorctl restart program_name  # 重启某个进程
supervisorctl stop groupworker:  # 结束所有属于名为 groupworker 这个分组的进程 (start,restart 同理)
supervisorctl stop groupworker:name1  # 结束 groupworker:name1 这个进程 (start,restart 同理)
supervisorctl stop all  # 停止全部进程,注:start、restartUnlinking stale socket /tmp/supervisor.sock、stop 都不会载入最新的配置文件
supervisorctl reload  # 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl update  # 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启

1.4配置supervisord.conf

#修改[include]
files=/etc/supervisord.d/*.ini
# 这句目的是让supervisor识别并管理(如启动、停止等)委托的服务

然后重启supervisor: supervisorctl reload.

1.5可能的问题

supervisor使用有时候会报如下错误:
unix:///tmp/supervisor.sock no such file
原因是supervisor默认配置会把socket文件和pid守护进程生成在/tmp/目录下,/tmp/目录是缓存目录,Linux会根据不同情况自动删除其下面的文件。
原因找到了,就好办了,将supervisor配置文件里的相应地方改掉就好了。

vi /etc/supervisord.conf

修改:

[unix_http_server]
;file=/tmp/supervisor.sock   ; (the path to the socket file)
file=/var/run/supervisor.sock   ; 修改为 /var/run 目录,避免被系统删除

[supervisord]
;logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile=/var/log/supervisor/supervisord.log ; 修改为 /var/log 目录,避免被系统删除
pidfile=/var/run/supervisord.pid ; 修改为 /var/run 目录,避免被系统删除
...

[supervisorctl]
; 必须和'unix_http_server'里面的设定匹配
;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
serverurl=unix:///var/run/supervisor.sock ; 修改为 /var/run 目录,避免被系统删除

supervisorctl update

2 node_exporter

2.1安装node_exporter

node_exporter监控服务器的运行状态(如cpu、内存、硬盘等),

# 进入目标目录如:/app
wget https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz
tar xvf node_exporter-0.18.1.linux-amd64.tar.gz
# 重命名目录
mv node_exporter-0.18.1.linux-amd64 node_exporter-0.18.1

然后在/etc/supervisord.d目录下生成node_exporter.ini.

然后添加如下内容:

[program:node_exporter]
directory=/app/node_exporter-0.18.1
command=/app/node_exporter-0.18.1/node_exporter
autostart=true
autorestart=true
startsecs=1
startretries=3
user=root
redirect_stderr=true
stdout_logfile=/tmp/node_exporter.log

启动组件:

备注:需要更新下:supervisorctl update, 然后node会自动启动

supervisorctl start node_exporte

3. prometheus

3.1 安装prometheus

cd /app
wget https://github.com/prometheus/prometheus/releases/download/v2.20.1/prometheus-2.20.1.linux-amd64.tar.gz
tar xvfz prometheus-*.tar.gz
mv prometheus-2.20.1.linux-amd64 prometheus-2.20.1

同样地,在/etc/supervisord.d中创建prometheus.ini,并在其中加入:

[program:prometheus]
directory=/data/app/prometheus-2.20.1
command=/app/prometheus-2.20.1/prometheus --config.file /app/prometheus-2.20.1/prometheus.yml --storage.tsdb.path=/app/prometheus-2.20.1/data
autostart=true
autorestart=true
startsecs=1
startretries=3
user=root
redirect_stderr=true
stdout_logfile=/tmp/prometheus.log

然后配置prometheus的配置文件:

cd /data/prometheus-2.20.1
vim prometheus.yml

添加:

# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets: ['localhost:9093']
      #- alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  - /data/marvin/pkg/app/prometheus-2.20.1/rules/node.yml #  "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node_exporter'
    static_configs:
      - targets: ['localhost:9100']

  - job_name: 'service1_job'
    static_configs:
      - targets: ['service1_address:8000']

  - job_name: 'service2_job'
    static_configs:
      - targets: ['service2_address:8003']

其中node_exporter是在上面部署的node_exporter, 其默认port为9100, 后面service1,service2是需要监控的服务

启动:

supervisorctl start prometheus

在浏览器输入:

http://server_ip_address:9090/graph

可以查看类似如下页面,可在其中输入promQL语句

4 alertmanager

4.1 安装alertmanager

cd /app
wget https://github.com/prometheus/alertmanager/releases/download/v0.23.0/alertmanager-0.23.0.linux-amd64.tar.gz
tar xvf alertmanager-0.23.0.linux-amd64.tar.gz
mv alertmanager-0.23.0.linux-amd64.tar.gz alertmanager-0.23.0

vi /etc/supervisord.d/alertmanager.ini

# 添加如下内容:
[program:altermanager]
directory=/app/alertmanager-0.23.0
command=./app/alertmanager-0.23.0
autostart=true
autorestart=true
startsecs=1
startretries=3
user=root
redirect_stderr=true
stdout_logfile=/tmp/altermanager.log

然后配置alertmanager配置文件:

cd /app/alertmanager-0.23.0
vim alertmanager.yml
# cat alertmanager.yml
route:
  group_by: ['alertname']
  group_wait: 5s
  group_interval: 20s
  repeat_interval: 1m
  receiver: 'web.hook'
receivers:
- name: 'web.hook'
  webhook_configs:
  - url: 'http://127.0.0.1:1111/' # 这个是下面bridge服务的地址,可按需修改
inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'dev', 'instance']

5 grafana

5.1 安装grafana

cd /app
wget https://dl.grafana.com/oss/release/grafana-7.1.3.linux-amd64.tar.gz
tar xvf grafana-7.1.3.linux-amd64.tar.gz
vi /etc/supervisord.d/grafana-server.ini

# 添加如下内容:
[program:grafana-server]
directory=/app/grafana-7.1.3
command=/app/grafana-7.1.3/bin/grafana-server -homepath /app/grafana-7.1.3
autostart=true
autorestart=true
startsecs=1
startretries=3
user=root
redirect_stderr=true
stdout_logfile=/tmp/grafana.log
supervisorctl start grafana-server

5.2 grafana board

在浏览器中输入

http://your_server_address:3000

点击左侧边栏上面的“+”加号可添加新的看版:

点击+ Add new panel 即可添加新的看版,在下图的metrics中编写promQL语句(本处示例为: prometheus_http_requests_total)即可生成统计图:

上图上面的Alert按钮可以为此统计数据设置告警,不过在这里设置告警之前需要先在Alerting页中添加告警通道:

然后点击New channel 即可新建:

这里我们选择的是webhook, 下面的url添加企业微信机器人的webhook地址.

6 新建企业微信机器人

在想要告警的群,右键->添加群机器人,按提示来后,会生成webhook 地址, 类似下面:

https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=b0221169-eg78-349i-87we-09ef4g4ctyu1

7 编写 bridge服务

  1. 编写请求转移程序

    alertmanage的将向此bridge服务发送请求,request的信息即为告警信息,然后,bridge服务将以此告警信息为数据请求企业微信机器人:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import os
    import sys
    
    sys.path.append(os.getcwd())
    import json
    from tornado.ioloop import IOLoop
    from tornado.httpserver import HTTPServer
    from tornado.web import RequestHandler, Application
    from alter_manager_info_format import parse_info
    import json
    import requests
    
    
    # 下面为企业微信机器人对应的webhook地址
    url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxxxxxxxxxxxxxxx"
    head = {"Content-type": "application/json", "Accept": "*/*"}
    
    class BaseHandler(RequestHandler):
        def set_default_headers(self):
            self.set_header("Access-Control-Allow-Origin", "*") 
            self.set_header("Access-Control-Allow-Headers", "x-requested-with")
            self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
    
        def post(self):
            jsonstr = str(self.request.body, encoding="utf8")
            jd = json.loads(jsonstr)
            res = grafana_extract(jd)
            data = json.dumps({"msgtype": "markdown", "markdown": {
                "content": res
            }})
    
            res = requests.post(url, data=data, headers=head)
    
        def get(self):
            self.write('some get')
    
        def options(self):
            # no body
            self.set_status(204)
            self.finish()
    
    
    if __name__ == '__main__':
        import time
    
        # 创建 APPlication对象,进行若干个对服务器的设置
        # 例如:路由列表,模版路径,静态资源路径等
        app = Application([('/', BaseHandler)])
        # 创建服务器程序
        server = HTTPServer(app)
        server.bind(1111)
        server.start(2)  # Forks multiple sub-processes
        IOLoop.instance().start()
    
    
  2. 编写告警信息解析程序

    企业微信机器人支持多种解析格式,比如文本、markdown等。

    def _parse(msg):
        tmp = ''
        if type(msg) is dict:
            for key, value in msg.items():
                if key == 'receiver' or key == 'status':
                    continue
                if type(value) is str or type(value) is int or type(value) is float:
                    color = 'comment'
                    if value == 'warning':
                        color = 'warning'
                    elif key in {'instance', 'job', 'description', 'summary','device','mountpoint'}:
                        color = 'info'
                    if key == "alertname":
                        tmp += f"# {value}\n"
                    elif color != 'comment':
                        tmp += f"**{key}:<font color=\"{color}\">{value}</font>**\n"
                    else:
                        tmp += f">{key}:<font color=\"{color}\">{value}</font>\n"
                else:
                    tmp += _parse(value)
        elif type(msg) is list:
            for ele in msg:
                tmp += _parse(ele)
        return tmp
    

8 服务监控服务

在python有prometheus_client 可以使用,助力监控服务构建。

from prometheus_client import start_http_server, Summary, Counter

class Monitor(object):
    def __init__(self, name, description=None, labels=None, port=8000):
        _ = start_http_server(port)
        self.Counter = Counter(name, description, labels)
        self.http_counter = Counter('xxx_http_request', 'descrtiption', ['business', 'code'])

    def info_inc(self, labels, value):
        self.Counter.labels(*labels).inc(value)

    def http_inc(self, labels):
        self.http_counter.labels(*labels).inc(1.)
posted on 2021-10-26 19:52  Vpegasus  阅读(1000)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3