【實踐】1.Docker環境部署Prometheus+Grafana監控系統

一、Prometheus簡介

Prometheus是由SoundCloud開發的開源監控報警系統和時序列數據庫(TSDB)。

圖片

Prometheus使用Go語言開發,是Google BorgMon監控系統的開源版本。2016年由Google發起Linux基金會旗下的原生云基金會(Cloud Native Computing Foundation), 將Prometheus納入其下第二大開源項目。Prometheus目前在開源社區相當活躍。Prometheus和Heapster(Heapster是K8S的一個子項目,用于獲取集群的性能數據。)相比功能更完善、更全面。Prometheus性能也足夠支撐上萬臺規模的集群。

1.系統架構圖

圖片

2.基本原理

Prometheus的基本原理是通過HTTP協議周期性抓取被監控組件的狀態,任意組件只要提供對應的HTTP接口就可以接入監控。不需要任何SDK或者其他的集成過程。這樣做非常適合做虛擬化環境監控系統,比如VM、Docker、Kubernetes等。輸出被監控組件信息的HTTP接口被叫做exporter 。目前互聯網公司常用的組件大部分都有exporter可以直接使用,比如Varnish、Haproxy、Nginx、MySQL、Linux系統信息(包括磁盤、內存、CPU、網絡等等)。

其大概的工作流程是:

  1. Prometheus server 定期從配置好的 jobs 或者 exporters 中拉 metrics,或者接收來自 Pushgateway 發過來的 metrics,或者從其他的 Prometheus server 中拉 metrics。
  2. Prometheus server 在本地存儲收集到的 metrics,并運行已定義好的 alert.rules,記錄新的時間序列或者向 Alertmanager 推送警報。
  3. Alertmanager 根據配置文件,對接收到的警報進行處理,發出告警。
  4. 在Grafana圖形界面中,可視化查看采集數據。

3.Prometheus的特性

  • 多維度數據模型。

  • 靈活的查詢語言。

  • 不依賴分布式存儲,單個服務器節點是自主的。

  • 通過基于HTTP的pull方式采集時序數據。

  • 可以通過中間網關進行時序列數據推送。

  • 通過服務發現或者靜態配置來發現目標服務對象。

  • 支持多種多樣的圖表和界面展示,比如Grafana等。

4.Prometheus的組件

  • Prometheus Server 主要負責數據采集和存儲,提供PromQL查詢語言的支持。

  • Alertmanager 警告管理器,用來進行報警。

  • Push Gateway 支持臨時性Job主動推送指標的中間網關。

  • Exporters 輸出被監控組件信息的HTTP接口。

  • Grafana 監控數據展示Web UI。

5.服務發現

由于 Prometheus 是通過 Pull 的方式主動獲取監控數據,也就是每隔幾秒鐘去各個target采集一次metric。所以需要手工指定監控節點的列表,當監控的節點增多之后,每次增加節點都需要更改配置文件,盡管可以使用接口去熱更新配置文件,但仍然非常麻煩,這個時候就需要通過服務發現(service discovery,SD)機制去解決。

Prometheus 支持多種服務發現機制,可以自動獲取要收集的 targets,包含的服務發現機制包括:azure、consul、dns、ec2、openstack、file、gce、kubernetes、marathon、triton、zookeeper(nerve、serverset),配置方法可以參考手冊的配置頁面。可以說 SD 機制是非常豐富的,但目前由于開發資源有限,已經不再開發新的 SD 機制,只對基于文件的 SD 機制進行維護。針對我們現有的系統情況,我們選擇了靜態配置方式。

二、部署PrometheusServer

1. 使用官方鏡像運行

由于Prometheus官方鏡像沒有開啟熱加載功能,而且時區相差八小時,所以我們選擇了自己制作鏡像,當然你也可以使用官方的鏡像,提前創建Prometheus配置文件prometheus.yml和Prometheus規則文件rules.yml,然后通過如下命令掛載到官方鏡像中運行:

$ docker run -d -p 9090:9090 --name=prometheus \
 -v  /root/prometheus/conf/:/etc/prometheus/  \
prom/prometheus 

使用官方鏡像部署可以參考我的這篇文章:Docker部署Prometheus實現微信郵件報警。

2. 制作鏡像

現在我們創建自己的Prometheus鏡像,當然你也可以直接使用我制作的鏡像

$ docker pull zhanganmin2017/prometheus:v2.9.0  

首先去Prometheus下載二進制文件安裝包解壓到package目錄下,我的Dockerfile目錄結構如下:

$ tree prometheus-2.9.0/
prometheus-2.9.0/
├── conf
│   ├── CentOS7-Base-163.repo
│   ├── container-entrypoint
│   ├── epel-7.repo
│   ├── prometheus-start.conf
│   ├── prometheus-start.sh
│   ├── prometheus.yml
│   ├── rules
│   │   └── service_down.yml
│   └── supervisord.conf
├── Dockerfile
└── package
    ├── console_libraries
    ├── consoles
    ├── LICENSE
    ├── NOTICE
    ├── prometheus
    ├── prometheus.yml
    └── promtool
5 directories, 26 files

分別創建圖中的目錄,可以看到conf目錄中有一些名為supervisord的文件,這是因為在容器中的進程我們選擇使用supervisor進行管理,當然如果不想使用的化可以進行相應的修改。

制作prometheus-start.sh啟動腳本,Supervisor啟動Prometheus會調用該腳本

#!/bin/bash
/bin/prometheus \
 --config.file=/data/prometheus/prometheus.yml \
 --storage.tsdb.path=/data/prometheus/data \
 --web.console.libraries=/data/prometheus/console_libraries \
 --web.enable-lifecycle \
 --web.console.templates=/data/prometheus/consoles

制作Prometheus-start.conf啟動文件,Supervisord的配置文件

[program:prometheus]
command=sh /etc/supervisord.d/prometheus-start.sh   ; 程序啟動命令
autostart=false     ; 在supervisord啟動的時候不自動啟動
startsecs=10        ; 啟動10秒后沒有異常退出,就表示進程正常啟動了,默認1秒
autorestart=false   ; 關閉程序退出后自動重啟,可選值:[unexpected,true,false],默認為unexpected,表示進程意外殺死才重啟
startretries=0      ; 啟動失敗自動重試次數,默認是3
user=root            ; 用哪個用戶啟動進程,默認是root
redirect_stderr=true            ; 把stderr重定向到stdout,默認false
stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默認是50MB
stdout_logfile_backups=30        ; stdout 日志文件備份數,默認是10; 
# stdout 日志文件,需要注意當指定目錄不存在時無法正常啟動,所以需要手動創建目錄(supervisord 會自動創建日志文件)
stdout_logfile=/data/prometheus/prometheus.log
stopasgroup=true
killasgroup=true

制作supervisord.conf啟動文件

[unix_http_server]
file=/var/run/supervisor.sock   ; (the path to the socket file)
chmod=0700                       ; sockef file mode (default 0700)

[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)
user=root
minfds=10240
minprocs=200

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket

[program:sshd]
command=/usr/sbin/sshd -D
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/ssh_out.log
stderr_logfile=/var/log/supervisor/ssh_err.log

[include]
files = /etc/supervisord.d/*.conf

制作container-entrypoint守護文件,容器啟動后執行的腳本

#!/bin/sh
set -x
if [ ! -d "/data/prometheus" ];then
    mkdir -p /data/prometheus/data
fi
mv /usr/local/src/* /data/prometheus/
exec /usr/bin/supervisord -n
exit

在conf目錄下新建Prometheus.yml配置文件,這個是Prometheus配置監控主機的文件

global:
  scrape_interval:   60s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 60s # Evaluate rules every 15 seconds. The default is every 1 minute.
alerting:
  alertmanagers:
  - static_configs:
    - targets: [ '192.168.133.110:9093']

rule_files:
  - "rules/host_sys.yml"

scrape_configs:
  - job_name: 'Host'
    static_configs:
      - targets: ['10.1.250.36:9100']
        labels:
          appname: 'DEV01_250.36'
  - job_name: 'prometheus'
    static_configs:
      - targets: [ '10.1.133.210:9090']
        labels:
          appname: 'Prometheus'

在conf目錄下新建rules目錄,編寫service_down.yml規則文件,這個也可以等到容器創建后再編寫,這里我們就直接寫好添加到鏡像中

groups:
- name: servicedown
  rules:
  - alert: InstanceDown
    expr: up == 0
    for: 1m
    labels:
      name: instance
      severity: Critical
    annotations:
      summary: " {{ $labels.appname }}"
      description: " 服務停止運行 "
      value: "{{ $value }}"

制作dockerfile 鏡像文件

FROM docker.io/centos:7
MAINTAINER from zhanmin@1an.com
# install repo
RUN  rm -rf  /etc/yum.repos.d/*.repo
ADD  conf/CentOS7-Base-163.repo /etc/yum.repos.d/
ADD  conf/epel-7.repo           /etc/yum.repos.d/
# yum install
RUN yum install -q -y  openssh-server openssh-clients  net-tools \
  vim  supervisor && yum clean all
# install sshd
RUN  ssh-keygen -q -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key \
  &&  ssh-keygen -q -N "" -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key \
  &&  ssh-keygen -q -N "" -t ed25519 -f /etc/ssh/ssh_host_ed25519_key \
  &&  sed -i 's/#UseDNS yes/UseDNS no/g' /etc/ssh/sshd_config
# UTF-8 and CST +0800
ENV  LANG=zh_CN.UTF-8 
RUN  echo "export LANG=zh_CN.UTF-8" >> /etc/profile.d/lang.sh \
    &&  ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
# install Prometheus
COPY  package/prometheus                            /bin/prometheus
COPY  package/promtool                              /bin/promtool
COPY  package/console_libraries/                    /usr/local/src/console_libraries/
COPY  package/consoles/                             /usr/local/src/consoles/
COPY  conf/prometheus.yml               /usr/local/src/prometheus.yml   
COPY  conf/rules/                                   /usr/local/src/rules/
# create user
RUN  echo "root:123456" | chpasswd 
# supervisord
ADD  conf/supervisord.conf                               /etc/supervisord.conf
ADD  conf/prometheus-start.conf                          /etc/supervisord.d/prometheus-start.conf
ADD  conf/container-entrypoint                         /container-entrypoint
ADD  conf/prometheus-start.sh                         /etc/supervisord.d/prometheus-start.sh
RUN  chmod +x /container-entrypoint
# cmd
CMD  ["/container-entrypoint"]

Dockerfile中安裝了supervisor進程管理工具和SSH服務,指定了字符集和時區。

生成鏡像并運行容器服務

$ docker build -t zhanganmin2017/prometheus:v2.9.0 .
$ docker run -itd  -h prometheus139-210 -m 8g  --cpuset-cpus=28-31  --name=prometheus139-210 --network trust139  --ip=10.1.133.28  -v /data/works/prometheus139-210:/data  192.168.166.229/1an/prometheus:v2.9.0
$ docker exec -it  prometheus139-210  /bin/bash
$ supervisorctl  start  prometheus首先去Prometheus

訪問prometheus Web頁面 IP:9090

圖片

三、部署監控組件Exporter

Prometheus 是使用 Pull 的方式來獲取指標數據的,要讓 Prometheus 從目標處獲得數據,首先必須在目標上安裝指標收集的程序,并暴露出 HTTP 接口供 Prometheus 查詢,這個指標收集程序被稱為 Exporter ,不同的指標需要不同的 Exporter 來收集,目前已經有大量的 Exporter 可供使用,幾乎囊括了我們常用的各種系統和軟件,官網列出了一份常用Exporter的清單 ,各個 Exporter 都遵循一份端口約定,避免端口沖突,即從 9100 開始依次遞增,這里是完整的 Exporter端口列表 。另外值得注意的是,有些軟件和系統無需安裝 Exporter,這是因為他們本身就提供了暴露 Prometheus 格式的指標數據的功能,比如 Kubernetes、Grafana、Etcd、Ceph 等。

1. 部署主機監控組件

各節點主機使用主機網絡模式部署主機監控組件node-exporter,官方不建議將其部署為Docker容器,因為該node_exporter設計用于監控主機系統。需要訪問主機系統,而且通過容器的方式部署發現磁盤數據不太準確。二進制部署就去看項目文檔吧

$ docker run -d \
  --net="host" \
  --pid="host" \
  -v "/:/host:ro,rslave" \
  quay.io/prometheus/node-exporter \
  --path.rootfs=/host

容器正常運行后,進入Prometheus容器,在Prometheus.yml 文件中添加node-exporter組件地址

$ docker exec -it  prometheus-133-210  /bin/bash
$ vim /data/prometheus/prometheus.yml
global:
  scrape_interval:   60s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 60s # Evaluate rules every 15 seconds. The default is every 1 minute.

rule_files:
  - "rules/service_down.yml"

scrape_configs:
  - job_name: 'Host'
    static_configs:
      - targets: ['10.1.250.36:9100']  #node-exporter地址
        labels:
          appname: 'DEV01_250.36' #添加的標簽
  - job_name: 'prometheus'
    static_configs:
      - targets: [ '10.2.139.210:9090']
        labels:
          appname: 'prometheus'

熱加載更新Prometheus

$  curl -X POST http://10.1.133.210:9090/-/reload

查看Prometheus的web頁面已經可以看到node-exporter,然后我們就可以定義報警規則和展示看板了,這部分內容在后面配置Alertmanager和Grafana上會詳細介紹。

圖片

2.部署容器監控組件

各節點主機部署容器監控組件cadvisor-exporter,我這邊Docker網絡使用的macvlan方式,所以直接給容器分配了IP地址。

# docker run -d  -h cadvisor139-216  --name=cadvisor139-216  --net=none -m 8g   --cpus=4   --ip=10.1.139.216   --volume=/:/rootfs:ro   --volume=/var/run:/var/run:rw --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro  --volume=/dev/disk/:/dev/disk:ro     google/cadvisor:latest

同樣的,容器正常運行后,我們訪問Cadvisor的Web頁面 IP+8080 端口

圖片

現在我們進入Prometheus容器,在prometheus.yml主機文件中添加cadvisor組件

-----------
  - job_name: 'Cadvisor'
    static_configs:
      - targets: [ '10.1.139.216:8080']
        labels:
          appname: 'DEV_Cadvisor01'

熱加載更新Prometheus

$  curl -X POST http://10.1.133.210:9090/-/reload

可以看到,Prometheus添加的cadvisor狀態為UP,說明正常接收數據。

圖片

3. 部署Redis監控組件

容器部署Redis服務監控組件redis_exporter,--redis.passwd指定認證口令,如果你的redis訪問沒有密碼那么就無需指定后面參數。

$ docker run -d  -h  redis_exporter139-218 --name redis_exporter139-218 --network trust139 --ip=10.1.139.218  -m 8g  --cpus=4  oliver006/redis_exporter --redis.passwd  123456

在prometheus.yml 添加redis-exporter

---------
- job_name: 'Redis-exporter'   #exporter地址
    static_configs:
      - targets: ['10.2.139.218:9121'']
        labels:
          appname: 'redis-exporter'
  - job_name: 'RedisProxy'   #需要監控的redis地址
    static_configs:
      - targets:
        - redis://10.2.139.70:6379
        - redis://10.2.139.71:6379
        labels:
          appname: RedisProxy
    metrics_path: /scrape
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 10.2.139.218:9121

然后熱加載更新,步驟同上。

4.部署應用監控組件

中間件部署JVM監控組件jmx_exporter, 這種方式是適用于代碼中沒有暴露應用metrics信息的服務,無需進行代碼改動,在應用啟動時調用該jar包暴露jmx信息,然后在Prometheus分別指定應用的地址即可。

  1. 首先下載jar :https://github.com/prometheus/jmx_exporter(jmx_prometheus_javaagent-0.11.0.jar )
  2. 下載配置文件,有tomcat和weblogic注意區分:https://github.com/prometheus/jmx_exporter/tree/master/example_configs
  3. 然后在中間件啟動參數添加以下內容,指定配置文件和jar包的路徑:
CATALINA_OPTS="-javaagent:/app/tomcat-8.5.23/lib/jmx_prometheus_javaagent-0.11.0.jar=12345:/app/tomcat-8.5.23/conf/config.yaml"

上面我指定暴露metrics信息的端口為12345,所以我們在prometheus.yml文件中添加即可:

---------
  - job_name: 'MIDL'
    static_configs:
      - targets: ['192.168.166.18:12345','192.168.166.19:12345']
        labels:
          appname: 'ORDER'
      - targets: ['10.2.139.111:12345','10.2.139.112:12345']
        labels:
          appname: 'WEB'

其他步驟同上,Prometheus熱加載更新即可。

5. 部署進程監控組件

因為我們容器是使用單獨的網絡部署的,相當于胖容器的方式,所以需要在監控的容器中部署process-exporter進程監控組件來監控容器的進程,

軟件包下載:

wget https://github.com/ncabatoff/process-exporter/releases/download/v0.5.0/process-exporter-0.5.0.linux-amd64.tar.gz

配置文件:process-name.yaml

process_names:

  - name: "{{.Matches}}"

    cmdline:

    - 'redis-shake'  #匹配進程,支持正則 

啟動參數:

$ nohup ./process-exporter -config.path process-name.yaml &

在Prometheus.yml 添加該容器的IP地址,端口號為9256

-----------
  - job_name: 'process'
    static_configs:
      - targets: [ '10.2.139.186:9256']
        labels:
          appname: 'Redis-shake'

ok,現在我們熱加載更新Prometheus的主機文件

$ curl -X POSThttp://10.2.139.210:9090/-/reload

四、部署Alertmanager報警組件

1. Alertmanager 概述

Alertmanager處理客戶端應用程序(如Prometheus服務器)發送的告警。它負責對它們進行重復數據刪除,分組和路由,以及正確的接收器集成,例如電子郵件,PagerDuty或OpsGenie。它還負責警報的靜默和抑制。

以下描述了Alertmanager實現的核心概念。請參閱配置文檔以了解如何更詳細地使用它們。

  • 分組(Grouping)
    分組將類似性質的告警分類為單個通知。這在大型中斷期間尤其有用,因為許多系統一次失敗,并且可能同時發射數百到數千個警報。
    示例:發生網絡分區時,群集中正在運行數十或數百個服務實例。一半的服務實例無法再訪問數據庫。Prometheus中的告警規則配置為在每個服務實例無法與數據庫通信時發送告警。結果,數百個告警被發送到Alertmanager。
    作為用戶,只能想要獲得單個頁面,同時仍能夠確切地看到哪些服務實例受到影響。因此,可以將Alertmanager配置為按群集和alertname對警報進行分組,以便發送單個緊湊通知。
    這些通知的接收器通過配置文件中的路由樹配置告警的分組,定時的進行分組通知。
  • 抑制(Inhibition)
    如果某些特定的告警已經觸發,則某些告警需要被抑制。
    示例:如果某個告警觸發,通知無法訪問整個集群。Alertmanager可以配置為在該特定告警觸發時將與該集群有關的所有其他告警靜音。這可以防止通知數百或數千個與實際問題無關的告警觸發。
  • 靜默(SILENCES)
    靜默是在給定時間內簡單地靜音告警的方法。基于匹配器配置靜默,就像路由樹一樣。檢查告警是否匹配或者正則表達式匹配靜默。如果匹配,則不會發送該告警的通知。在Alertmanager的Web界面中可以配置靜默。
  • 客戶端行為(Client behavior)
    Alertmanager對其客戶的行為有特殊要求。這些僅適用于不使用Prometheus發送警報的高級用例。#制作鏡像方式和Prometheus類似,稍作更改即可,此步省略。

設置警報和通知的主要步驟如下:

  1. 設置并配置Alertmanager;
  2. 配置Prometheus對Alertmanager訪問;
  3. 在普羅米修斯創建警報規則;

2. 部署Alertmanager組件

首先需要創建Alertmanager的報警通知文件,我這里使用企業微信報警,其中企業微信需要申請賬號認證,方式如下:

  1. 訪問網站注冊企業微信賬號(不需要企業認證)。

  2. 訪問apps創建第三方應用,點擊創建應用按鈕 -> 填寫應用信息:

  3. 創建報警組,獲取組ID:

圖片
圖片
圖片

新建alertmanager.yml報警通知文件

global:
  resolve_timeout: 2m
  smtp_smarthost: smtp.163.com:25
  smtp_from: 15xxx@163.com
  smtp_auth_username: 15xxxx@163.com
  smtp_auth_password: zxxx

templates:
  - '/data/alertmanager/conf/template/wechat.tmpl'
route:
  group_by: ['alertname_wechat']
  group_wait: 1s
  group_interval: 1s
  receiver: 'wechat'
  repeat_interval: 1h
  routes:
  - receiver: wechat
    match_re:
      serverity: wechat
receivers:
- name: 'email'
  email_configs:
  - to: '8xxxxx@qq.com'
    send_resolved: true
- name: 'wechat'
  wechat_configs:
  - corp_id: 'wwd402ce40b4720f24'
    to_party: '2'
    agent_id: '1000002'
    api_secret: '9nmYa4p12OkToCbh_oNc'
    send_resolved: true ## 發送已解決通知

參數說明:

  • corp_id: 企業微信賬號唯一 ID, 可以在我的企業中查看。

  • to_party: 需要發送的組。

  • agent_id: 第三方企業應用的 ID,可以在自己創建的第三方企業應用詳情頁面查看。

  • api_secret: 第三方企業應用的密鑰,可以在自己創建的第三方企業應用詳情頁面查看。

然后我們創建企業微信的消息模板,template/wechat.tmpl

{{ define "wechat.default.message" }}
{{ range $i, $alert :=.Alerts }}
【系統報警】
告警狀態:{{   .Status }}
告警級別:{{ $alert.Labels.severity }}
告警應用:{{ $alert.Annotations.summary }}
告警詳情:{{ $alert.Annotations.description }}
觸發閥值:{{ $alert.Annotations.value }}
告警主機:{{ $alert.Labels.instance }}
告警時間:{{ $alert.StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}
{{ end }}

這個報警的模板其中的值是在Prometheus觸發的報警信息中提取的,所以你可以根據自己的定義進行修改。

運行Alertmanager容器

$ docker run -d -p 9093:9093 --name alertmanager  -m 8g  --cpus=4 -v /opt/alertmanager.yml:/etc/alertmanager/alertmanager.yml -v /opt/template:/etc/alertmanager/template  docker.io/prom/alertmanager:latest

容器運行完成后查看web頁面 IP:9093

圖片

3. 配置報警規則

Prometheus的報警規則通過PromQL語句編寫

進入Prometheus容器的rules目錄,上面我們制作鏡像的時候已經創建好并掛載到了容器中,現在我們編寫其他的規則文件

編寫主機監控規則文件,rules/host_sys.yml

cat host_sys.yml
groups:
- name: Host
 rules:
 - alert: HostMemory Usage
   expr: (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemTotal_bytes * 100 >  90
   for: 1m
   labels:
     name: Memory
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: "宿主機內存使用率超過90%."
     value: "{{ $value }}"
 - alert: HostCPU Usage
   expr: sum(avg without (cpu)(irate(node_cpu_seconds_total{mode!='idle'}[5m]))) by (instance,appname) > 0.8
   for: 1m
   labels:
     name: CPU
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: "宿主機CPU使用率超過80%."
     value: "{{ $value }}"
 - alert: HostLoad
   expr: node_load5 > 20
   for: 1m
   labels:
     name: Load
     severity: Warning
   annotations:
     summary: "{{ $labels.appname }} "
     description: " 主機負載5分鐘超過20."
     value: "{{ $value }}"
 - alert: HostFilesystem Usage
   expr: (node_filesystem_size_bytes-node_filesystem_free_bytes)/node_filesystem_size_bytes*100>80
   for: 1m
   labels:
     name: Disk
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: " 宿主機 [ {{ $labels.mountpoint }} ]分區使用超過80%."
     value: "{{ $value }}%"
 - alert: HostDiskio writes
   expr: irate(node_disk_writes_completed_total{job=~"Host"}[1m]) > 10
   for: 1m
   labels:
     name: Diskio
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: " 宿主機 [{{ $labels.device }}]磁盤1分鐘平均寫入IO負載較高."
     value: "{{ $value }}iops"
 - alert: HostDiskio reads
   expr: irate(node_disk_reads_completed_total{job=~"Host"}[1m]) > 10
   for: 1m
   labels:
     name: Diskio
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: " 宿機 [{{ $labels.device }}]磁盤1分鐘平均讀取IO負載較高."
     value: "{{ $value }}iops"
 - alert: HostNetwork_receive
   expr: irate(node_network_receive_bytes_total{device!~"lo|bond[0-9]|cbr[0-9]|veth.*|virbr.*|ovs-system"}[5m]) / 1048576  > 10
   for: 1m
   labels:
     name: Network_receive
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: " 宿主機 [{{ $labels.device }}] 網卡5分鐘平均接收流量超過10Mbps."
     value: "{{ $value }}3Mbps"
 - alert: hostNetwork_transmit
   expr: irate(node_network_transmit_bytes_total{device!~"lo|bond[0-9]|cbr[0-9]|veth.*|virbr.*|ovs-system"}[5m]) / 1048576  > 10
   for: 1m
   labels:
     name: Network_transmit
     severity: Warning
   annotations:
     summary: " {{ $labels.appname }} "
     description: " 宿主機 [{{ $labels.device }}] 網卡5分鐘內平均發送流量超過10Mbps."
     value: "{{ $value }}3Mbps"

編寫容器監控規則文件,rules/container_sys.yml

groups:
- name: Container
  rules:
  - alert: ContainerCPU
    expr: (sum by(name,instance) (rate(container_cpu_usage_seconds_total{image!=""}[5m]))*100) > 200
    for: 1m
    labels:
      name: CPU_Usage
      severity: Warning
    annotations:
      summary: "{{ $labels.name }} "
      description: " 容器CPU使用超200%."
      value: "{{ $value }}%"
  - alert: Memory Usage
    expr: (container_memory_usage_bytes{name=~".+"} - container_memory_cache{name=~".+"})  / container_spec_memory_limit_bytes{name=~".+"}   * 100 > 200
    for: 1m
    labels:
      name: Memory
      severity: Warning
    annotations:
      summary: "{{ $labels.name }} "
      description: " 容器內存使用超過200%."
      value: "{{ $value }}%"
  - alert: Network_receive
    expr: irate(container_network_receive_bytes_total{name=~".+",interface=~"eth.+"}[5m]) / 1048576  > 10
    for: 1m
    labels:
      name: Network_receive
      severity: Warning
    annotations:
      summary: "{{ $labels.name }} "
      description: "容器 [{{ $labels.device }}] 網卡5分鐘平均接收流量超過10Mbps."
      value: "{{ $value }}Mbps"
  - alert: Network_transmit
    expr: irate(container_network_transmit_bytes_total{name=~".+",interface=~"eth.+"}[5m]) / 1048576  > 10
    for: 1m
    labels:
      name: Network_transmit
      severity: Warning
    annotations:
      summary: "{{ $labels.name }} "
      description: "容器 [{{ $labels.device }}] 網卡5分鐘平均發送流量超過10Mbps."
      value: "{{ $value }}Mbps"

編寫redis監控規則文件,redis_check.yml

groups:
- name: redisdown
  rules:
  - alert: RedisDown
    expr: redis_up == 0
    for: 1m
    labels:
      name: instance
      severity: Critical
    annotations:
      summary: " {{ $labels.alias }}"
      description: " 服務停止運行 "
      value: "{{ $value }}"
  - alert: Redis linked too many clients
    expr: redis_connected_clients / redis_config_maxclients * 100 > 80
    for: 1m
    labels:
      name: instance
      severity: Warning
    annotations:
      summary: " {{ $labels.alias }}"
      description: " Redis連接數超過最大連接數的80%. "
      value: "{{ $value }}"
  - alert: Redis linked
    expr: redis_connected_clients / redis_config_maxclients * 100 > 80
    for: 1m
    labels:
      name: instance
      severity: Warning
    annotations:
      summary: " {{ $labels.alias }}"
      description: " Redis連接數超過最大連接數的80%. "
      value: "{{ $value }}"

編寫服務停止監控規則,rules/service_down.yml

- alert: ProcessDown
    expr: namedprocess_namegroup_num_procs  == 0
    for: 1m
    labels:
      name: instance
      severity: Critical
    annotations:
      summary: " {{ $labels.appname }}"
      description: " 進程停止運行 "
      value: "{{ $value }}"
  - alert: Grafana down
    expr: absent(container_last_seen{name=~"grafana.+"} ) == 1
    for: 1m
    labels:
      name: grafana
      severity: Critical
    annotations:
      summary: "Grafana"
      description: "Grafana容器停止運行"
      value: "{{ $value }}"

編寫報警規則可以參考后面Grafana展示看板后的數據展示語句,需要注意的是,我們容器使用的是胖容器的方式,即當作虛擬機來使用,所以需要添加應用和服務停止的Exporter,如果你的容器守護進程直接就是應用的話,只需要監控容器的啟停就可以了。

測試微信報警

圖片

五、Grafana展示組件

雖然 Prometheus 提供的 Web UI 也可以很好的查看不同指標的視圖,但是這個功能非常簡單,只適合用來調試。要實現一個強大的監控系統,還需要一個能定制展示不同指標的面板,能支持不同類型的展現方式(曲線圖、餅狀圖、熱點圖、TopN 等),這就是儀表盤(Dashboard)功能。

Prometheus 開發了一套儀表盤系統PromDash,不過很快這套系統就被廢棄了,官方開始推薦使用 Grafana 來對 Prometheus 的指標數據進行可視化,這不僅是因為 Grafana 的功能非常強大,而且它和 Prometheus 可以完美的無縫融合。

Grafana是一個用于可視化大型測量數據的開源系統,它的功能非常強大,界面也非常漂亮,使用它可以創建自定義的控制面板,你可以在面板中配置要顯示的數據和顯示方式,它支持很多不同的數據源,比如:Graphite、InfluxDB、OpenTSDB、Elasticsearch、Prometheus 等,而且它也支持眾多的插件 。

1. 部署Grafana服務容器

$ docker run -d -h grafana139-211  -m 8g   --network trust139  --ip=10.2.139.211   --cpus=4 --name=grafana139-211 -e "GF_SERVER_ROOT_URL=http://10.2.139.211"   -e "GF_SECURITY_ADMIN_PASSWORD=passwd"    grafana/grafana

運行后訪問IP:3000,user:admin pass:passwd

圖片

2. 添加Prometheus數據源

圖片

3. 導入監控模板

使用編號導入模板,Grafana服務需要聯網,否則需要到Grafana模板下載JSON文件導入。

圖片

下面是我使用的幾個模板,導入后可以根據自己的情況定義變量值

圖片
  • 主機監控展示看板Node-exporter導入 8919 模板
  • 容器監控展示看板cadvisor-exporter導入193 模板
  • 應用監控展示看板jmx-exporter導入8563 模板
  • Redis監控展示看板Redis-exporter導入2751 模板
  • 進程監控展示看板Process-exporter導入249 模板

六、PromQL語句

七、使用Concul HTTP注冊方式實現服務發現

一般是用服務發現需要應用需要服務注冊,我們這邊因為微服務改造還沒完成,還有一些tomcat和weblogic中間件,而且選用的注冊中心是Eurka,所以為了在代碼不改動的情況下使用服務發現,選擇了concul 作為注冊中心,因為是consul是可以通過http方式注冊的。

1. consul 內部原理

圖片

Consul分為Client和Server兩種節點(所有的節點也被稱為Agent),Server節點保存數據,Client負責健康檢查及轉發數據請求到Server;Server節點有一個Leader和多個Follower,Leader節點會將數據同步到Follower,Server的數量推薦是3個或者5個,在Leader掛掉的時候會啟動選舉機制產生一個新的Leader。

集群內的Consul節點通過gossip協議(流言協議)維護成員關系,也就是說某個節點了解集群內現在還有哪些節點,這些節點是Client還是Server。單個數據中心的流言協議同時使用TCP和UDP通信,并且都使用8301端口。跨數據中心的流言協議也同時使用TCP和UDP通信,端口使用8302。

集群內數據的讀寫請求既可以直接發到Server,也可以通過Client使用RPC轉發到Server,請求最終會到達Leader節點,在允許數據輕微陳舊的情況下,讀請求也可以在普通的Server節點完成,集群內數據的讀寫和復制都是通過TCP的8300端口完成。

具體consul的原理及架構請訪問:http://blog.didispace.com/consul-service-discovery-exp/

2. 使用docker部署consul 集群

#啟動第1個Server節點,集群要求要有3個Server,將容器8500端口映射到主機8900端口,同時開啟管理界面
docker run -d --name=consul1 -p 8900:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui
 
#啟動第2個Server節點,并加入集群
docker run -d --name=consul2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.1
 
#啟動第3個Server節點,并加入集群
docker run -d --name=consul3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2
 
#啟動第4個Client節點,并加入集群
docker run -d --name=consul4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.2

瀏覽器訪問容器映射的8900端口:

圖片

3. 服務注冊到Consul

使用HTTP API 方式注冊node-exporter服務到Consul

curl -X PUT -d '{"id": "192.168.16.173","name": "node-exporter","address": "192.168.16.173","port": ''9100,"tags": ["DEV"], "checks": [{"http": "http://192.168.16.173:9100/","interval": "5s"}]}'     http://172.17.0.4:8500/v1/agent/service/register

解注冊:

curl --request PUT http://172.17.0.4:8500/v1/agent/service/deregister/192.168.166.14

注冊多個服務到consul,使用腳本:

#!/bin/bash 
all_IP=`cat  /opt/ip`
name=cadvisor
port=9100
for  I  in $all_IP
do
        curl -X PUT -d '{"id": "'$I'","name": "'$name'","address": "'$I'","port": '$port',"tags": ["cadvisor"], "checks": [{"http": "http://'$I':'$port'/","interval": "5s"}]}'     http://172.17.0.4:8500/v1/agent/service/register
done
圖片

4. Prometheus 配置consul 服務發現

consul 可以使用的元標簽:

__meta_consul_address:目標的地址
__meta_consul_dc:目標的數據中心名稱
__meta_consul_tagged_address_<key>:每個節點標記目標的地址鍵值
__meta_consul_metadata_<key>:目標的每個節點元數據鍵值
__meta_consul_node:為目標定義的節點名稱
__meta_consul_service_address:目標的服務地址
__meta_consul_service_id:目標的服務ID
__meta_consul_service_metadata_<key>:目標的每個服務元數據鍵值
__meta_consul_service_port:目標的服務端口
__meta_consul_service:目標所屬服務的名稱
__meta_consul_tags:標記分隔符連接的目標的標記列表

修改Prometheus.yml 文件,使用relabel將consul的元標簽重寫便于查看

- job_name: 'consul'
    consul_sd_configs:
      - server: '192.168.16.173:8900'
        services: []  #匹配所有service
    relabel_configs:
      - source_labels: [__meta_consul_service] #service 源標簽
        regex: "consul"  #匹配為"consul" 的service
        action: drop       # 執行的動作
      - source_labels: [__meta_consul_service]  # 將service 的label重寫為appname
        target_label: appname
      - source_labels: [__meta_consul_service_address]
        target_label: instance
      - source_labels: [__meta_consul_tags]
        target_label:  job

Prometheus 熱加載更新

curl -X POST http://192.168.16.173:9090/-/reload

訪問Prometheus web頁面

圖片

應用注冊到consul

在不需要開發修改代碼的前提下,我們可以使用Prometheus的jmx-exporter收集應用的相關指標,在應用中間件tomcat/weblogic等調用jmx-exporter,具體方式查看http://www.lxweimin.com/p/dfd6ba5206dc

啟動應用后會啟動12345端口暴露jvm數據,現在我們要做的就是將這個端口注冊到Consul上,然后Prometheus會從consul 拉取應用主機。

使用腳本實現

 $ cat     ip
TEST        192.168.166.10      192.168.166.11
UNMIN       192.168.166.12      192.168.166.13
---------------
       
$ cat consul.sh
#!/bin/bash
port=12345
while read app
do
    echo ${app}
    app_tmp=(${app})
    echo ${app_tmp[0]}
    length=${#app_tmp[@]}
    echo ${length}
    for((k=1;k<${length};k++));
    do
        echo ${app_tmp[k]}
    curl -X PUT -d '{"id": "'${app_tmp[k]}'","name": "'${app_tmp[0]}'","address": "'${app_tmp[k]}'","port": '$port',"tags": ["MIDL"],"checks": [{"http": "http://'${app_tmp[k]}':'$port'/","interval": "5s"}]}'     http://172.17.0.4:8500/v1/agent/service/register        
        done

done < ip

執行腳本注冊到consul

圖片

配置Grafana JVM 監控模板

Load 8563模板

圖片

八、參考

(1)Docker環境部署Prometheus+Grafana監控系統
http://www.lxweimin.com/p/dde0dc1761ec

(2)Docker部署Prometheus監控實踐
http://www.unmin.club/prometheus-book/

(3)Docker部署Prometheus實現微信郵件報警
http://www.lxweimin.com/p/dfd6ba5206dc

(4)Prometheus官網
https://prometheus.io/docs/introduction/overview/

(5)QUERYING PROMETHEUS語法
https://prometheus.io/docs/prometheus/latest/querying/basics/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容