Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。
Prometheus使用Go语言开发,是Google BorgMon监控系统的开源版本。2016年由Google发起Linux基金会旗下的原生云基金会(Cloud Native Computing Foundation), 将Prometheus纳入其下第二大开源项目。Prometheus目前在开源社区相当活跃。Prometheus和Heapster(Heapster是K8S的一个子项目,用于获取集群的性能数据。)相比功能更完善、更全面。Prometheus性能也足够支撑上万台规模的集群。
Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做非常适合做虚拟化环境监控系统,比如VM、Docker、Kubernetes等。输出被监控组件信息的HTTP接口被叫做exporter 。目前互联网公司常用的组件大部分都有exporter可以直接使用,比如Varnish、Haproxy、Nginx、MySQL、Linux系统信息(包括磁盘、内存、CPU、网络等等)。
其大概的工作流程是:
由于 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 机制进行维护。针对我们现有的系统情况,我们选择了静态配置方式。
由于Prometheus官方镜像没有开启热加载功能,而且时区相差八小时,所以我们选择了自己制作镜像,当然你也可以使用官方的镜像,提前创建Prometheus配置文件prometheus.yml和Prometheus规则文件rules.yml,然后通过如下命令挂载到官方镜像中运行:
$ docker run -d -p 9090:9090 --name=prometheus -v /root/prometheus/conf/:/etc/prometheus/ prom/prometheus
现在我们创建自己的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=tru
制作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 Web页面 IP:9090
Prometheus 是使用 Pull 的方式来获取指标数据的,要让 Prometheus 从目标处获得数据,首先必须在目标上安装指标收集的程序,并暴露出 HTTP 接口供 Prometheus 查询,这个指标收集程序被称为 Exporter ,不同的指标需要不同的 Exporter 来收集,目前已经有大量的 Exporter 可供使用,几乎囊括了我们常用的各种系统和软件,官网列出了一份常用Exporter的清单 ,各个 Exporter 都遵循一份端口约定,避免端口冲突,即从 9100 开始依次递增,这里是完整的 Exporter端口列表 。另外值得注意的是,有些软件和系统无需安装 Exporter,这是因为他们本身就提供了暴露 Prometheus 格式的指标数据的功能,比如 Kubernetes、Grafana、Etcd、Ceph 等。
各节点主机使用主机网络模式部署主机监控组件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上会详细介绍。
各节点主机部署容器监控组件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,说明正常接收数据。
容器部署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
然后热加载更新,步骤同上。
中间件部署JVM监控组件jmx_exporter, 这种方式是适用于代码中没有暴露应用metrics信息的服务,无需进行代码改动,在应用启动时调用该jar包暴露jmx信息,然后在Prometheus分别指定应用的地址即可。
首先下载jar :https://github.com/prometheus...(jmx_prometheus_javaagent-0.11.0.jar )
下载配置文件,有tomcat和weblogic注意区分:https://github.com/prometheus...
然后在中间件启动参数添加以下内容,指定配置文件和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热加载更新即可。
因为我们容器是使用单独的网络部署的,相当于胖容器的方式,所以需要在监控的容器中部署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处理客户端应用程序(如Prometheus服务器)发送的告警。它负责对它们进行重复数据删除,分组和路由,以及正确的接收器集成,例如电子邮件,PagerDuty或OpsGenie。它还负责警报的静默和抑制。
以下描述了Alertmanager实现的核心概念。请参阅配置文档以了解如何更详细地使用它们。
设置警报和通知的主要步骤如下:
首先需要创建Alertmanager的报警通知文件,我这里使用企业微信报警,其中企业微信需要申请账号认证,方式如下:
新建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
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,如果你的容器守护进程直接就是应用的话,只需要监控容器的启停就可以了。
虽然 Prometheus 提供的 Web UI 也可以很好的查看不同指标的视图,但是这个功能非常简单,只适合用来调试。要实现一个强大的监控系统,还需要一个能定制展示不同指标的面板,能支持不同类型的展现方式(曲线图、饼状图、热点图、TopN 等),这就是仪表盘(Dashboard)功能。
Prometheus 开发了一套仪表盘系统PromDash,不过很快这套系统就被废弃了,官方开始推荐使用 Grafana 来对 Prometheus 的指标数据进行可视化,这不仅是因为 Grafana 的功能非常强大,而且它和 Prometheus 可以完美的无缝融合。
Grafana是一个用于可视化大型测量数据的开源系统,它的功能非常强大,界面也非常漂亮,使用它可以创建自定义的控制面板,你可以在面板中配置要显示的数据和显示方式,它支持很多不同的数据源,比如:Graphite、InfluxDB、OpenTSDB、Elasticsearch、Prometheus 等,而且它也支持众多的插件 。
$ 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
使用编号导入模板,Grafana服务需要联网,否则需要到Grafana模板下载JSON文件导入。
下面是我使用的几个模板,导入后可以根据自己的情况定义变量值
主机监控展示看板Node-exporter导入 8919 模板 容器监控展示看板cadvisor-exporter导入193 模板 应用监控展示看板jmx-exporter导入8563 模板 Redis监控展示看板Redis-exporter导入2751 模板 进程监控展示看板Process-exporter导入249 模板
一般是用服务发现需要应用需要服务注册,我们这边因为微服务改造还没完成,还有一些tomcat和weblogic中间件,而且选用的注册中心是Eurka,所以为了在代码不改动的情况下使用服务发现,选择了concul 作为注册中心,因为是consul是可以通过http方式注册的。
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/con...
启动第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端口:
使用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
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,具体方式查看https://www.jianshu.com/p/dfd...
启动应用后会启动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模板
来源:https://www.jianshu.com/p/dde...