Zabbix监控告警ELK
概述
Zabbix允许自定义监控项,使用ansible批量安装zabbix-agent,在部署有ansible工具的机器上编写监控ELK端口,ES集群状态,索引数量脚本,然后编写ansible-playbook发送脚本到所有agent机器上;当监控项被触发时,自动发送告警到钉钉机器人和企业微信号上;告警的次数是5次,告警的频率是每隔5分钟告警一次。
本文跳过ansible,zabbix和elk的部署操作,旨在呈现zabbix的相关功能!
准备环境
主机名 | 设备IP | 角色 | 系统版本 |
---|---|---|---|
es1 | 192.168.6.10 | es,zabbix-server,zabbix-agent | CentOS 7.6 |
es2 | 192.168.6.11 | es,logstash,zabbix-agent | CentOS 7.6 |
es3 | 192.168.6.12 | es,kibana,zabbix-agent | CentOS 7.6 |
本文的ELK全家桶版本为7.0.0
,Zabbix版本为4.2.5
修改zabbix服务端的配置文件
主要参数说明:
StartPollers 处理zabbix数据的进程数
StartPollersUnreachable recheck的进程数
StartTrappers 建立agent连接传输进程数
StartHTTPPollers http检测
startDBSyncers 写入db进程
CacheSize 增加主机,监控项等配置缓存
DBName 数据库名称
DBUser 数据库用户名
DBPassword 数据库密码
StartDiscoverers 自动发现功能的进程数
AlertScriptsPath 告警脚本的存放路径
ExternalScripts 外部脚本的存放路径
StatsAllowedIP 服务端IP地址
具体的优化配置,根据自身环境来决定:
[root@es1 zabbix]# cat > /etc/zabbix/zabbix_server.conf <<EOF
LogFile=/var/log/zabbix/zabbix_server.log
StartPollers=160
StartPollersUnreachable=80
StartTrappers=20
StartHTTPPollers=60
startDBSyncers=16
CacheSize=1024M
LogFileSize=0
PidFile=/var/run/zabbix/zabbix_server.pid
SocketDir=/var/run/zabbix
DBName=zabbix
DBUser=zabbix
DBPassword=123456
StartDiscoverers=30
SNMPTrapperFile=/var/log/snmptrap/snmptrap.log
Timeout=4
AlertScriptsPath=/usr/lib/zabbix/alertscripts
ExternalScripts=/usr/lib/zabbix/externalscripts
LogSlowQueries=3000
StatsAllowedIP=218.201.205.211
EOF
修改agent节点的配置文件
主要参数说明:
Server 开启被动模式,配置为zabbix-server的IP地址
ServerActive 开启主动模式,配置为zabbix-server的IP地址
Hostname 配置为本地主机名
UnsafeUserParameters 允许自定义监控项功能
所有agent节点上都需要修改:
[root@es1 zabbix]# cat > /etc/zabbix/zabbix_agentd.conf <<EOF
PidFile=/var/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
Server=192.168.6.10
ServerActive=192.168.6.10
Hostname=es1
Include=/etc/zabbix/zabbix_agentd.d/*.conf
UnsafeUserParameters=1
EOF
编写监控es端口脚本
脚本主要实现将端口json格式化,其他的服务端口监控脚本也类似,根据服务器来修改portarray
的端口号即可!
[root@es1 zabbix]# cat > /etc/zabbix/es_port_alert.sh <<EOF
#!/bin/bash
portarray=(9200 9300)
PortDiscovery(){
length=${#portarray[@]}
printf "{\n"
printf '\t'"\"data\":["
for ((i=0;i<$length;i++))
do
printf '\n\t\t{'
printf "\"{#TCP_PORT}\":\"${portarray[$i]}\"}"
if [ $i -lt $[$length-1] ];then
printf ','
fi
done
printf "\n\t]\n"
printf "}\n"
}
PortDiscovery
EOF
编写监控索引数据量脚本
使用python的elasticsearch模块编写dsl语句,得出每5分钟内指定索引的数据量,监控其他索引也类似,该脚本只需部署在一台服务器上即可!
[root@es1 zabbix]# cat > /etc/zabbix/index_alert.py <<EOF
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
import time
import pytz
from datetime import datetime
from tzlocal import get_localzone
from elasticsearch import Elasticsearch
tz = get_localzone()
utc = pytz.utc
now = datetime.today()
loc_dt = tz.localize(now)
utc_dt = loc_dt.astimezone(utc)
today = datetime.strftime(utc_dt,'%Y%m')
index_today=("index_%s" % today)
es = Elasticsearch("http://192.168.6.10:9200")
def get_indices_nums():
global index_today
global es
querybody_warn = {
"size": 0,
"query": {
"bool": {
"filter": {
"range": {
"@timestamp": {
"gte": "now-5m/m",
"lte": "now/m"
}
}
}
}
}
}
response_warn = es.search(index=index_today, body=querybody_warn)
reqsum = response_warn['hits']['total']['value']
print reqsum
if __name__ == '__main__':
get_indices_nums()
EOF
自定义key,将脚本定义为监控命令
除了事先定义好脚本的方式,还能用命令取值的方式来定义key!
[root@es1 zabbix]# cat > /etc/zabbix/zabbix_agentd.d/elk_alert.conf <<EOF
UserParameter=get_es_port,/etc/zabbix/es_port_alert.sh
UserParameter=get_index,/etc/zabbix/index_alert.py
UserParameter=get_es_status,curl -s -XGET 'http://localhost:9200/_cluster/health?pretty' | grep "status" | awk -F'"' '{print $4}' | grep -c 'red'
EOF
修改脚本相关权限,并重启服务
修改脚本的属主和组,赋予脚本执行权限,最后重启zabbix相关服务!
[root@es1 zabbix]# chown -R zabbix:zabbix /etc/zabbix/es_port_alert.sh
[root@es1 zabbix]# chown -R zabbix:zabbix /etc/zabbix/index_alert.py
[root@es1 zabbix]# chown -R zabbix:zabbix /etc/zabbix/zabbix_agentd.d/elk_alert.conf
[root@es1 zabbix]# chmod +x /etc/zabbix/es_port_alert.sh /etc/zabbix/index_alert.py
[root@es1 zabbix]# chmod +x /etc/zabbix/zabbix_agentd.d/elk_alert.conf
[root@es1 zabbix]# systemctl restart zabbix-server
[root@es1 zabbix]# systemctl restart zabbix-agent
测试自定义key
在zabbix服务器上操作,可测试所有客户端agent,-s
后指定客户端地址,-k
后指定自定义的key!
[root@es1 zabbix]# zabbix_get -s 192.168.6.10 -k get_es_port
配置ansible-playbook
通过编写ansible-playbook文件,完成其他agent节点的脚本批量部署!
[root@es1 zabbix]# cat > /etc/ansible/zabbix_agent.yml <<EOF
- hosts: elkservers
remote_user: root
tasks:
- name: copying zabbix_agentd.conf
copy:
src: /etc/zabbix/zabbix_agentd.conf
dest: /etc/zabbix/zabbix_agentd.conf
owner: root
group: root
mode: 0644
- name: copying es_port_alert.sh
copy:
src: /etc/zabbix/es_port_alert.sh
dest: /etc/zabbix/es_port_alert.sh
owner: zabbix
group: zabbix
mode: 0754
- name: copying elk_alert.conf
copy:
src: /etc/zabbix/zabbix_agentd.d/elk_alert.conf
dest: /etc/zabbix/zabbix_agentd.d/elk_alert.conf
owner: zabbix
group: zabbix
mode: 0644
EOF
[root@es1 zabbix]# ansible-playbook /etc/ansible/zabbix_agent.yml
编写相关告警脚本
在zabbix服务器上操作,脚本要放在指定路径下;本文主要呈现钉钉机器人和企业微信号告警功能,告警内容使用了markdown格式;企业微信告警需要先安装python3环境;钉钉告警需要先获取自定义机器人webhook,可参考 https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c
钉钉机器人告警
[root@es1 zabbix]# cat > /usr/lib/zabbix/alertscripts/dingding.py <<EOF
#!/usr/bin/env python2.7
# -*- coding:utf-8 -*-
import json
import requests
import sys
def send_msg(url, remiders, text):
headers = {'Content-Type': 'application/json; charset=utf-8'}
data = {
"msgtype": "markdown",
"markdown": {
"title": "ELK告警",
"text": text + "@13475333688 @18756668888" # @手机号码,指定接收人
},
"at": {
"atMobiles": remiders,
"isAtAll": False
}
}
r = requests.post(url, data=json.dumps(data), headers=headers).json()
return r
if __name__ == '__main__':
url = 'https://oapi.dingtalk.com/robot/send?access_token=bawfasaf8c023197526c29ddddd'
remiders = ['13475333688', '18756668888']
text = sys.argv[1]
print(send_msg(url, remiders, text))
EOF
企业微信号告警
[root@es1 zabbix]# cat > /usr/lib/zabbix/alertscripts/weixin.py <<EOF
#!/usr/bin/python3
# -*- coding:utf-8 -*-
import requests
import json
import sys
# 企业号及应用相关信息
corp_id = 'ww730dff80343abcdf'
corp_secret = 'iufX35rEGz4Q9qJezIhHCT4S-k_f331kP69D3abcdef'
agent_id = '1000001'
# 存放access_token文件路径
file_path = '/tmp/access_token.log'
# 读取文本里记录的token
def get_access_token_from_file():
try:
f = open(file_path, 'r+')
this_access_token = f.read()
print('get success %s' % this_access_token)
f.close()
return this_access_token
except Exception as e:
print(e)
# 获取token函数,文本里记录的token失效时调用
def get_access_token():
get_token_url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s' % (corp_id, corp_secret)
print(get_token_url)
r = requests.get(get_token_url)
request_json = r.json()
this_access_token = request_json['access_token']
print(this_access_token)
r.close()
# 把获取到的access_token写入文本
try:
f = open(file_path, 'w+')
f.write(this_access_token)
f.close()
except Exception as e:
print(e)
# 返回获取到的access_token值
return this_access_token
##发送消息
# 死循环,直到消息成功发送
flag = True
while(flag):
# 从文本获取access_token
access_token = get_access_token_from_file()
try:
to_user = '@all'
message = sys.argv[1]
send_message_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s' % access_token
print(send_message_url)
message_params = {
"touser": to_user,
"msgtype": "markdown",
"agentid": agent_id,
"markdown": {
"content": message
},
"safe": 0
}
r = requests.post(send_message_url, data=json.dumps(message_params))
print('post success %s' % r.text)
# 判断是否发送成功,如不成功则抛出异常,让其执行异常处理里的函数
request_json = r.json()
errmsg = request_json['errmsg']
if errmsg != 'ok': raise
# 消息成功发送,则停止死循环
flag = False
except Exception as e:
print(e)
access_token = get_access_token()
EOF
修改相关权限,并重启zabbix服务
[root@es1 zabbix]# chown -R zabbix:zabbix /usr/lib/zabbix/alertscripts/dingding.py
[root@es1 zabbix]# chown -R zabbix:zabbix /usr/lib/zabbix/alertscripts/weixin.py
[root@es1 zabbix]# chmod +x /usr/lib/zabbix/alertscripts/dingding.py
[root@es1 zabbix]# chmod +x /usr/lib/zabbix/alertscripts/weixin.py
[root@es1 zabbix]# systemctl restart zabbix-server
[root@es1 zabbix]# systemctl restart zabbix-agent
Zabbix中文界面操作
监控端口(以配置ES端口监控模板为例)
配置 --> 模板 --> 创建模板 --> 添加
模板名称 ES_Port_Alert
可见的名称 ES端口监控
群组 Linux server
[图片上传失败...(image-89f211-1595316084892)]
配置 --> 模板(ES端口监控) --> 自动发现规则 --> 创建发现规则 --> 添加
名称 ES_Port_Discovey
类型 Zabbix客户端(主动式)
键值 get_es_port # 该键值名称必须与自定义的key名一致
更新间隔 30s # 数据采集的频率,此处指30s采集一次
image
配置 --> 模板(ES端口监控) --> 自动发现规则 --> 监控项原型 --> 创建监控项原型 --> 添加
名称 {#TCP_PORT}端口
类型 Zabbix客户端(主动式)
键值 net.tcp.listen[{#TCP_PORT}]
信息类型 数字(无正负)
新的应用程序原型 port-alert
image
配置 --> 模板(ES端口监控) --> 自动发现规则 --> 触发器类型 --> 创建触发器原型 --> 添加
名称 端口{#TCP_PORT} down,请检查
严重性 严重
表达式 {ES_Port_Alert:net.tcp.listen[{#TCP_PORT}].last()}<>1 and {ES_Port_Alert:net.tcp.listen[{#TCP_PORT}].nodata(15m)}=1
允许手动关闭
描述 监控结果不等于1,并且端口断开持续15分钟,即表示es端口未被监控到!
image
配置ES集群状态监控模板
配置 --> 模板 --> 创建模板 --> 添加
模板名称 ES_Status_Alert
可见的名称 ES集群状态监控
群组 Linux servers
image
配置 --> 模板(ES集群状态监控) --> 应用集 --> 创建应用集 --> 添加
名称 ES_Health
image
配置 --> 模板(ES集群状态监控) --> 监控项 --> 创建监控项 --> 添加
名称 ES_Status_Check
类型 Zabbix客户端(主动式)
键值 get_es_status
信息类型 数字(无正负)
应用集 ES_Health
[图片上传失败...(image-454ef6-1595316084893)]
配置 --> 模板(ES集群状态监控) --> 触发器 --> 创建触发器 --> 添加
名称 ES_Cluster_Health
严重性 灾难
表达式 {ES_Status_Alert:get_es_status.last()}<>0 and {ES_Status_Alert:get_es_status.nodata(15m)}=1
允许手动关闭
描述 状态值不为0,并且持续15分钟,即表示集群状态为Red
image
配置ES索引监控模板
配置 --> 模板 --> 创建模板 --> 添加
模板名称 Indices_index_Alert
可见的名称 回填索引监控
群组 Linux servers
image
配置 --> 模板(回填索引监控) --> 应用集 --> 创建应用集 --> 添加
名称 index_*
image
配置 --> 模板(回填索引监控) --> 监控项 --> 创建监控项 --> 添加
名称 索引index_gz
类型 Zabbix客户端(主动式)
键值 get_index
信息类型 数字(无正负)
应用集 index_*
image
配置 --> 模板(回填索引监控) --> 触发器 --> 创建触发器 --> 添加
名称 回填索引入库数据=0
严重性 严重
表达式 {Indices_index_Alert:get_index.last(#1)}<=0 and {Indices_index_Alert:get_index.nodata(15m)}=1
允许手动关闭
描述 最近5分钟的回填索引 index_* 数量小于等于0,且持续15分钟
image
自动发现主机,添加发现主机,为主机关联模板
以下以主机es1为例
配置 --> 自动发现 --> 创建发现规则 --> 添加
名称 Local network
IP范围 192.168.6.0-254
更新间隔 1h
检查 新的(检查类型:Zabbix客户端,端口范围:10050,键值:system.uname) --> 添加
image
配置 --> 主机 --> 创建主机 --> 添加
主机名称 es1
群组 Linux servers
agent代理程序的接口 (IP地址:192.168.6.10,连接到:IP地址,端口:10050) --> 添加
image
配置 --> 主机(es1) --> 模板 --> 更新
链接指示器(选择对应模板)--> 添加
image
实现钉钉机器人告警功能
企业微信号告警配置与此雷同
管理--> 报警媒介类型 --> 创建媒体类型 --> 添加
名称 dingalert_script
类型 脚本
脚本名称 dingding.py # 该名称必须与服务端上创建的一致
脚本参数 {ALERT.MESSAGE} --> 添加
image
管理--> 用户(Admin) --> 报警媒介 --> 添加 --> 更新
类型 dingalert_script
收件人 Admin
image
配置 --> 动作 --> 创建动作 --> 添加
名称 alert_to_ding
操作 --> 新的 --> 添加
恢复操作 --> 新的 --> 添加(与操作类似)
image
image
测试钉钉机器人告警功能
管理 --> 报警媒介类型 --> 测试
收件人 Admin
主题 Test subject
消息 This is the test message from Zabbix
image
真实告警案例
image image
image