使用prometheus自定义监控

背景:

目的是监控tomcat的cpu和内存的,本来是打算是使用zabbix自发现去做,但感觉又要写模板,又要写脚本,还要用自动化工具推自发现脚本,而且还担心性能也不是很好。所以就打算换种新的监控工具,最终选择了prometheus.

实施:

1. 第一步就是要安装prometheus了,我这边为了保持可通用性和简洁,不污染机器环境,能用docker安装的都用docker进行安装(其他的工具也是这样的)。另外docker安装比较方便和省心。先上premoethus的docker-compose,安装docker-compose的可以移步docker-compose安装


version: '2'

services:

  prometheus:

    image: prom/prometheus:v2.0.0

    ports:

      - "9090:9090"

    volumes:

      - /data/compose_data/prometheus/prometheus:/prometheus   #prometheus数据目录

      - /data/compose_data/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml   #prometheus配置文件

      - /data/compose_data/prometheus/first_rules.yml:/etc/prometheus/first_rules.yml   #报警配置文件

    command: --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/prometheus --web.console.libraries=/usr/share/prometheus/console_libraries  --web.console.templates=/usr/share/prometheus/consoles --web.external-url=http://{ip或者域名}:9090    #重写了启动的配置参数,其中web.external-url配置问prometheus地址是为了在报警邮件里面点击直接到prometheus的web界面

这里需要注意我的配置文件都写好了,所以直接进行volumes映射的。如果是第一次创建容器环境,请先启动没有映射的容器将配置文件取出来,配置好进行映射。下面列出配置文件的内容:
prometheus.yml:

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.
alerting:
  alertmanagers:
  - static_configs:
    - targets:
       - altermanager:9093   #设置altermanager的地址,后文会写到安装altermanager
rule_files:
  - "first_rules.yml"   # 设置报警规则
  # - "second_rules.yml"
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']   #这个自带的默认监控prometheus所在机器的prometheus状态
#  - job_name: 'localhost'
#   static_configs:
#      - targets: ['192.168.98.73:9101']   #这部分是监控机器的状态,需要在机器节点启动[node_exporter](https://github.com/prometheus/node_exporter),需要监控机器的可以移步查看
#       labels:
#         instance: localhost
  - job_name: "uat-apps-status"      # 自己定义的监控的job_name
    static_configs:
      - targets: ['192.168.98.73:9091']   # 指向pushgateway.  我在每台机器上使用的是推的方式到pushgateway,所以采取了此种方式。
        labels:
          instance: uat    #新添加的标签,可以自定义
    scrape_interval: 60s

这里需要说明的是也可以使用metrics的方式让premetheus去各个节点去拉数据,因为这样我就需要在监控的每个节点运行web服务端,所以就改成了推到pushgateway的方式。

first_rules.yml:

groups:
- name: example   #报警规则的名字
  rules:

  # Alert for any instance that is unreachable for >5 minutes.
  - alert: InstanceDown     #检测job的状态,持续1分钟metrices不能访问会发给altermanager进行报警
    expr: up == 0
    for: 1m    #持续时间
    labels:
      serverity: page
    annotations:
      summary: "Instance {{ $labels.instance }} down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."


  - alert: "it's has problem"  #报警的名字
    expr: "test_tomcat{exported_instance="uat",exported_job="uat-app-status",host="test",instance="uat",job="uat-apps-status"} -  test_tomcat{exported_instance="uat",exported_job="uat-app-status",host="test",instance="uat",job="uat-apps-status"} offset 1w > 5"   # 这个意思是监控该表达式查询出来的值与一周前的值进行比较,大于5且持续10m钟就发送给altermanager进行报警
    for: 1m  #持续时间
    labels:
      serverity: warning
    annotations:
      summary: "{{ $labels.type }}趋势增高"
      description: "机器:{{ $labels.host }} tomcat_id:{{ $labels.id }} 类型:{{ $labels.type }} 与一周前的差值大于5,当前的差值为:{{ $value }}"    #自定义的报警内容

这些是自定义的基本报警内容,具体还可以使用模块功能,构建更详细的报警页面,具体可以参考模板使用方法,读者可以基于自己环境的情况进行配置。

2. 然后就需要安装上面配置文件用到了altermanger和pushgateway了,这边同样使用docker来安装。
altermanger的docker-compose:

version: '2'
services:
  altermanager:
    image: prom/alertmanager:master
    volumes:
      - /data/compose_data/prometheus_altermanager/conf/config.yml:/etc/alertmanager/config.yml  #altermanager配置文件
      - /data/compose_data/prometheus_altermanager/data:/altermanager  #altermanager数据目录
    ports:
      - "9093:9093"
    command: -config.file=/etc/alertmanager/config.yml -storage.path=/alertmanager -web.external-url=http://{ip或者域名}:9093   #重写了启动方式,添加了web.external参数,使报警邮件点击可以直接到altermanager web页面

这里的配置文件同样的需要从容器里面导出来配置好,放到对应的映射目录的。
confg.yml:

global:
  # The smarthost and SMTP sender used for mail notifications.
  smtp_smarthost: 'smtp.exmail.qq.com:465'  #这里是指smtp的服务器
  smtp_from: 'test@qq.com'  # 邮箱from地址,一般写邮箱的用户名
  smtp_auth_username: 'test@qq.com'  #邮箱的用户名
  smtp_auth_password: '******'    #邮箱的密码
  smtp_require_tls: false   # 这个配置了true导致没有报错,最后我设置成了false正常了
  # The auth token for Hipchat.
  #hipchat_auth_token: '1234556789'
  # Alternative host for Hipchat.
  #hipchat_api_url: 'https://hipchat.foobar.org/'    #这是其他的报警方式
route:
  group_by: ['host','id','type']    #可以机器标签进行报警的分组
  group_wait: 30s   #分组等待时间
  group_interval: 30s    #分组的时间间隔 
  repeat_interval: 1h     #重复报警的时间间隔
  receiver: 'test-mails'    #发给定义的name
receivers:
- name: 'test-mails'
  email_configs:
  - to: "test@qq.com"  #收件人地址 想发送多个人可以这样写test1@qq.com,test2@qq.com

上面只是介绍简单的报警配置,具体可以依据分组做静默,分类发送,按级别发送等等,具体配置可以看看docker容器默认的配置文件配置方法。
3.接下来就是pushgateway的docker-compose:

version: '2'
services:
  pushgateway:
    image: prom/pushgateway:master
    ports:
      - "9091:9091"

这个比较简单,我们只是用这个做监控数据的中转。
4.配置完成之后依次启动这些容器:

docker-compose -f /data/compose/prometheus_pushgateway/docker-compose.yml up -d
docker-compose -f /data/compose/prometheus_altermanager/docker-compose.yml up -d
docker-compose -f /data/compose/prometheus/docker-compose.yml up -d
如果启动失败可以使用docker-compose -f 文件 logs 查看错误详情进行更正

5.启动完成后可以访问相应的web页面进行查看:
premetheus web页面:

访问 http://{premetheus_ip}:9090
premetheus.png

其中:

  • alters可以查看当前报警的状态
  • status->rules可以查看配置的报警规则.
  • status->targets可以查看配置的job及状态。

altermanger页面:

访问:http://altermanager:9093
altermanager.png

这里可以基于label设置告警的静默期,查看当前报警的内容等。邮件里面点击的连接就是到达这里。

pushgateway页面:

访问: http://pushgateway:9091
pushgateway.png

这里可以看到pushgateway的对应的job,已经对应job的key及上次收到数据的时间,也可以删除job的数据重新生成。

6.上述步骤都完成后接下来就需要写脚本取数据到pushgateway了。我这边给出个实例脚本,大家可以根据此进行更改以监控自己想要监控的数据

import requests,time
from get_application_status import get_app_status
# 这个get_app_status的模块是自己写的通过命令取得tomcat的cpu和内存,并返回字典。

def _submit_wrapper(url, job_name, value):
    headers = {'X-Requested-With': 'Python requests', 'Content-type': 'text/xml'}
    requests.post('http://%s/metrics/job/%s' % (url, job_name),
                      data='%s\n' % (value), headers=headers)


def push_metrics(job_name,hostid,instance,url):
    all_app_status = get_app_status()
    tomcat_status = all_app_status.tomcat_status()
    metrice_name = ""
    for tomcat in tomcat_status:
        metrice_name += '%s_tomcat{id="%s",host="%s",type="mem",instance="%s",job="%s"} %s\n'%(hostid,tomcat,hostid,instance,job_name,tomcat_status[tomcat]['mem'])
        metrice_name += '%s_tomcat{id="%s",host="%s",type="cpu",instance="%s",job="%s"} %s\n' % (hostid,tomcat,hostid,instance,job_name,tomcat_status[tomcat]['cpu'])
#重点是这块将取到的值组成一个字符串,字符串的格式要符合metrics的标准,可以选择target的一个metrics进行格式查看。这里给出个实例:
# uat_tomcat{id="tomcat_1018",host="uat",type="mem",instance="uat",job="uat-app-status"} 3.2
# uat_tomcat{id="tomcat_1018",host="uat",type="cpu",instance="uat",job="uat-app-status"} 2.4
    _submit_wrapper(url=url,job_name=job_name,value=metrice_name) 




if __name__ == "__main__":
    job_name = "{{ job_name }}"  #我这里使用的是ansible批量推的形式运行该脚本,所有用了jinja的变量,如果不需要可以直接加此设置成对应的值运行。
    hostid = "{{ hostid }}".replace("-","_")  #这里我发现type标签的值不支持-,所以就替换成_
    instance = "{{ instance }}"
    url = "{{ url }}"  #这里的地址填写的是altermanger的地址(algermanger:9091)
    while True:
        push_metrics(job_name=job_name,hostid=hostid,instance=instance,url=url)
        time.sleep(60)   #这里用的是死循环不断的取数据,其实也可以使用计划任务。

7.接下来运行上面的脚本推到gateway,prometheus就可以取到数据了。我这边再补充下用ansible推的大致yml:
我用的anisible的roles功能:
tasks/main.yml:

---
# tasks file for premethous_client

- name: test dir is exits
  file: path=/root/scripts state=directory

- name: copy service_promethous
  copy: src=service_promethous.sh dest=/root/scripts/service_promethous.sh  #这是自己写的简单启动关闭该脚本的文件

- name: copy get_application_status
  template: src=get_application_status.py dest=/root/scripts/get_application_status.py   #这是那个模块,这个根据大家写的脚本内容,可用可不用的。这里就不说明了

- name: copy single_gateway
  template: src=single_gateway.py dest=/root/scripts/single_gateway.py  #这是推gateway的脚本,我写的是以死循环的方式运行,其实可以用计划任务
  notify:
    - restart prometheus

- name: start prometheus
  shell: sh /root/scripts/service_promethous.sh start
  ignore_errors: True

files/service_promethous.sh:

#!/bin/bash

start(){
  ps aux |grep single_gateway.py | grep python | grep -v grep > /dev/null
  if [ $? -eq 0 ];then
    echo "already start"
    exit 0
  else
    nohup python /root/scripts/single_gateway.py > /dev/null 2>&1 &
  fi
}

stop(){
  num=`ps aux |grep single_gateway.py | grep -v grep | awk  '{print $2}'`
  if [ $num ];then
    kill $num
    echo "stop success..."
  else
    echo "no starting..."
  fi
}

status(){
  ps aux |grep single_gateway.py | grep python | grep -v grep > /dev/null
  if [ $? -eq 0 ];then
    echo "starting...."
  else
    echo "stoping......"
  fi
}

case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                sleep 2
                start
                ;;
        status)
                status
                ;;
        *)
                echo "only suport start|stop|restart|status"
esac

# 偷懒写的简单的启动关闭文件,大家看下就好了。

handlers/main.yml:

---
# handlers file for premethous_client
#
- name: restart prometheus
  shell: sh /root/scripts/service_promethous.sh restart  #文件变化重启脚本的handles

premethous_client.yml:

- hosts: uat_env
  gather_facts: True
  roles:
    - premethous_client
  vars:
    job_name: uat-app-status
    hostid: "{{ ansible_hostname }}"
    instance: uat
    url: altermanager:9091
  tags:
    - uat-premethous

这是执行role的playbook,主要就是定义了全局变量替换role的templates。做到不同的机器推到pushgateway的值的key不一样。
8.配置完ansible

ansible-playbook premethous_client.yml

指定的机器就可以就行数据的推送了。

注:ansible只是为了方便才做的,其实可以不做。

9.现在其实prometheus的监控报警已经完成了,这边我再扩展下grafana结合prometheus展示的使用方法。
按照惯例依然使用docker-compose部署

version: '2'
services:
  grafana:
    image: grafana/grafana:4.6.3
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=123456   #设置管理员的密码
    volumes:
      - /data/compose_data/grafana:/var/lib/grafana  #设置数据目录
    command: cfg:default.smtp.enabled=true cfg:default.smtp.host=smtp.exmail.qq.com:25 cfg:default.smtp.user=test@qq.com cfg:default.smtp.password=***** cfg:default.smtp.from_address=test@qq.com cfg:default.server.root_url=http://{grafna_url或者域名}:3000
#重写了grafana启动的配置,添加了邮件发送的功能

启动grafna:

docker-compose -f /data/compose/grafana/docker-compose.yml up -d

访问:http://granfana:3000 输入用户名密码登录

grafana.png

这里有几个步骤,添加数据源及添加用户,我就不说了,根据提示可以很轻松的完成。我这里主要介绍dashboard templates的使用,点击到dashboard然后点击new,然后点击齿轮形状的图标,点击templating,新建variable
templating.png

这里需要注意的是从取到的数据顾虑出来单个的值要用()包括才能取所有的key值里面取到想要的appid,这里读者可以尝试用括号包裹不同的内容进行测试。然后还可以新建variables一个取相应的host。这里根据实际环境做适合自己的配置。我这边配置的整体效果是这个样子的。


status.png

注:在创建graph图形的时候,如果要引用templating设定的值,可以使用这样的格式[[]],比如引用appid就使用[[appid]],在legend format使用label的值可以使用{{}}将labels括起来.
下面给出大致配置的截图:


config.png

结语:

这里也就是用到了prometheus自定义监控的基本功能,实际上prometheus还支持其他好几种数据类型,各种丰富的算术表达式,报警聚合和抑制,以及自动发现等,这些需要大家慢慢发掘与学习了,真正业务有需求了就会驱动技术的进步。

这里有1个问题,就是推送端的监控问题,如果脚本意外出错停止,数据就不会更新了,这边我用的是zabbix监控了机器的这个进程,当然还有更好的方法,大家可以尝试尝试。

推荐阅读更多精彩内容