随着公司的业务规模不断扩大,运维纳管机器的数量也在增加,引入自动化手段为捉襟见肘的工作减压,已成为重中之重。本文分享笔者在企业DevOps过程中,是如何有效结合ZabbixAPI来实现批量监控的案例。
1. 前置条件
1.1. 接口分析
假若当前有个新的监控要求:业主希望快速将一批主机的某个监控项关联到一张图上来(非grpfunc叠加),即以CPU、MEM、DISK等维度纵向对比这批主机的资源使用情况。很显然,当主机数超过一定量时手工创建会非常枯燥和繁琐,所幸Zabbix提供了API。我们通过分析Zabbix Docs中的graph.create
图表接口,得知要提供的主机HostID、监控项键值ItemID,使用到的Zagbix Method主要有:User
Host
HostGroup
Item
Graph
等5种方法。
如上图,描述本次批量创建图表的主要脚本逻辑,即先获取Zabbix的身份验证令牌,然后查询主机或主机群获得其HOSTID,接着以HOSTID依次获取指定监控键值ID加入列表池,最后一次性请求graph.create
进行图表创建。
1.2. 环境约定
系统/工具 | 版本 |
---|---|
Zabbix | 5.0.1 |
CentOS | 7.6.1810 |
Python | 3.6.8 |
本自动化案例脚本在Zabbix5.0验证通过,理论上支持Zabbix5.4,主要版本内部具有向后兼容性。
2. 构建接口
2.1. 认证类(AUTH)
创建AUTH
类并声明一个私有函数__init__
,用来初始化Zabbix接口、Zabbix用户名,Zabbix密码。在条件允许的情况下,建议使用SuperAdmin
超管用户,跑通之后再进行权限精细化管理。
class AUTH(object):
def __init__(self):
self.zabbix_api = set.Zabbix["api"]
self.zabbix_user = set.Zabbix["user"]
self.zabbix_pass = set.Zabbix["pass"]
创建rcpResult
函数,作为桥接Zabbix API数据通道的桥梁。Zabbix API使用JSON-RPC 2.0协议,作为Web前端的一部分提供,支持HTTP POST协议。
def rpcResult(self, params):
headers = {"Content-Type": "application/json-rpc"}
rsp = requests.post(url=self.zabbix_api, headers=headers, data=json.dumps(params))
try:
return rsp.json()["result"]
except:
set.logger.error(rsp.json()["error"])
exit(1)
创建getToken
函数,在进入ZabbixAPI神秘世界之前,需申请一张身份验证令牌。官方提供了一个叫user.login
的method调用方法,其user
,password
参数为Web端账密信息,而id
作为请求的标识符,其支持整形、浮点型、字符串3种数据类型。
def getToken(self):
params = {
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"user": self.zabbix_user,
"password": self.zabbix_pass,
},
"id": "Chasii"
}
return self.rpcResult(params)
通过调用AUTH类的Get_Token函数AUTH().Get_Token()
,得到接口返回的result
,就是我们通往神秘世界的一把钥匙。
{
"jsonrpc": "2.0",
"result": "22e6f614a89ccc1c1226429c4b7b08a0",
"id": "Chasii"
}
值得注意的是,通过user.login
方法申请到的身份验证令牌其永久生效,不会被系统释放。频繁调度会产生大量opensession记录,从而占用系统资源。这里给出了三种解决方案:
- 1、在Web端将对应用户的
Auto-logout
选项勾上并设置时间使其自动失效。 - 2、将身份校验令牌缓存成文本或存入中间件,可重复调用,
- 3、使用
user.logout
方法,即用即销,安全绿色。
如下destroyToken
函数,提供了官网注销Token的方法。
def destroyToken(self, token):
params = {
"jsonrpc": "2.0",
"method": "user.logout",
"params": [],
"auth": token,
"id": "Chasii"
}
return self.rpcResult(params)
2.2. 主机类(HOST)
创建HOST
类并声明__init__
私有函数,通过入参zbx_token
获取ZabbixAPI身份令牌,供本类函数调用。
class HOST(object):
def __init__(self, zbx_token):
self.zbx_token = zbx_token
创建getGroupID
函数,通过查询指定groupid
群主ID,返回该组内所有主机ID及其主机名。
def getHostID(self, groupid):
params = {
"jsonrpc": "2.0",
"method": "host.get",
"params": {
"output": ["hostid","host"],
"groupids": groupid
},
"auth": self.zbx_token,
"id": "Chasii"
}
return AUTH().rpcResult(params)
2.3. 群组类(HOSTGROUP)
创建HOSTGROUP
类并声明__init__
私有函数,通过入参zbx_token
获取ZabbixAPI身份令牌,供本类函数调用。
class HOSTGROUP(object):
def __init__(self, zbx_token):
self.zbx_token = zbx_token
创建getGroupID
函数,通过查询指定群组名hostgroup
,返回群组ID。
def getGroupID(self, hostgroup):
params = {
"jsonrpc": "2.0",
"method": "hostgroup.get",
"params": {
"output": "groupid",
"filter": {"name": [hostgroup]}
},
"auth": self.zbx_token,
"id": "Chasii"
}
return AUTH().rpcResult(params)
2.4. 指标类(ITEM)
创建ITEM
指标类并声明一个私有函数,通过入参zbx_token
获取ZabbixAPI身份令牌,供本类函数调用。
class ITEM(object):
def __init__(self, zbx_token):
self.zbx_token = zbx_token
创建getItemID
函数,通过查询指定主机名host
和指标项key
,返回监控项ID。
def getItemID(self, host, key):
params = {
"jsonrpc": "2.0",
"method": "item.get",
"params": {
"output": "itemid",
"host": host,
"search": { "key_": key},
},
"auth": self.zbx_token,
"id": "Chasii"
}
return AUTH().rpcResult(params)
2.5. 图表类(GRAPH)
Zabbixgraph.create
接口参数说明:
必选参数 | 支持类型 | 示例 |
---|---|---|
name | 字符串 | 图表的名称、如Biz_Group001_CPU、Biz_Group001_MEM |
width | 整数型 | 图表的高度,如900像素,在config.py文件中指定 |
height | 整数型 | 图表的高度,如200像素,在config.py文件中指定 |
gitems | 列表型 | 图标的监控项列表,如[{"itemid":"22828","color":"00AA00"}] |
创建一个GRAPH
指标类并声明一个私有函数,通过入参zbx_token
获取ZabbixAPI身份令牌,供本类函数调用。
class GRAPH(object):
def __init__(self, zbx_token):
self.zbx_token = zbx_token
创建createGrapth
函数,指定图表名gname
,图表宽度gwidth
,图表高度gheigth
,图表监控项参数gitems
。
def createGrapth(self, gname, gwidth, gheight, gitems):
params = {
"jsonrpc": "2.0",
"method": "graph.create",
"params": {
"name": gname,"width": gwidth,"height": gheight,"gitems": gitems
},
"auth": self.zbx_token,
"id": "Chasii"
}
return AUTH().rpcResult(params)
3. 调用接口
3.1. 项目介绍
通过上面对官方API的解读,我们已经知道如何使用它了。那么接下来的任务就是如何将这些配件、模块组装起来,让它running起来。为更方便讲解本案例,笔者已将上述相关API脚本上传至Github。读者可关注和克隆到本地使用,未来会支持更多功能。
项目代码Git地址:https://github.com/Chasii/ZabbixCli.git
项目框架说明
代码语言:javascript复制ZabbixCli
├── app # Zabbix接口
│ └── api.py
├── conf # Zabbix配置
│ └── settings.py
├── docs # Zabbix说明
│ ├── Nginx-Established.png
│ └── Sequence-Diagram.png
├── logs # 程序日志
│ └── zbx.log
├── readme.md
└── zbxcli.py # 统一入口
3.2. 配置分离
通过配置分离,将易变的模块拎出来作为独立文件,增强项目稳定性和可塑性。config.py
文件定义了日志输出格式、日志输出方式(文件、控制台),同时指定Zabbix账号及图表的默认像素,读者可根据自身情况及需求进行调整,下面摘取部分代码进行展示。
# Log Set
...
log_fmt = '%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s:%(message)s'
# Export Console
....
logger.addHandler(rf_handler)
# Export Logfile
...
logger.addHandler(f_handler)
# Env Set
Zabbix = {
"api": "http://<your_ip>/api_jsonrpc.php",
"user": "<your_name>",
"pass": "<your_pass>",
...
}
3.3. 创建入口
创建ZBXCLI
入口类并声明一个私有函数,调用AUTH
类获得初始ZabbixAPI身份令牌,供本类函数调用。
class ZBXCLI(object):
def __init__(self):
self.zbx_token = zbx.AUTH().getToken()
如下函数主要处理CLI传来参数,其中函数randomColor
返回随机16进制颜色码、函数handleItem
根据主机名和监控指标获取ItemID、函数handleHost
、handleGroup
负责处理HostID,函数createGraph
请求接口创建图表。
def randomColor(self):
return ("".join(random.choice("0123456789ABCDEF") for i in range(6)))
def handleItem(self, key, hosts):
items = []
for host in hosts:
items.append(zbx.ITEM(self.zbx_token).getItemID(host, key)[0]["itemid"])
return items
def handleHost(self, hosts):
items = self.handleItem(args.key, hosts)
self.createGraph(items)
...
def handleGroup(self, groups):
for group in groups:
result = zbx.HOSTGROUP(self.zbx_token).getGroupID(group)
...
def createGraph(self, items):
gitems = []
...
3.4. 调用示例
ZabbixCli参数说明
参数 | 说明 |
---|---|
key | 监控键值(Key),注意不是监控的指标名 |
name | 图表名,需保持唯一性,支持中文 |
type | 支持类型指定主机群组or主机,有特殊字符请加上双引号 |
nargs | 主机群组/主机列表参数,多参数请使用空格分开,支持中文 |
$ python3 zbxcli.py -h
usage: zbxcli.py [-h] -key KEY -name NAME -type {hostgraph,groupgraph} -nargs
NARGS [NARGS ...]
=== Zabbix Cli ===
optional arguments:
-h, --help show this help message and exit
-key KEY Zabbix Item Key
-type {hostgraph,groupgraph}
-nargs NARGS [NARGS ...]
3.4.1. 主机模式
指定主机host1
,host2
,关联操作系统CPU负载的键值system.cpu.load[all,avg5]
,并将图表命名为RELATE_GRAPH.CPU.LOAD.AVG5
。
$ python3 zbxcli.py -key "system.cpu.load[all,avg5]"
-name "RELATE_GRAPH.CPU.LOAD.AVG5"
-type hostgraph
-nargs "host1" "host2"
2021-12-11 17:32:58,507 zbxcli.py [line:52] INFO:{'graphids': ['57138']}
打开任意指定主机的Graph
配置项,查找RELATE_GRAPH.CPU.LOAD.AVG5
图表名字可以看到,我们创建的主机键值已经关联到一张图表上了,通过Preview可正常显示。
3.4.2. 群组模式
指定群组BizGroup001主机群组
,BizGroup002主机群组
,关联所有主机的Nginx-Established链接数,键值为tcp_conn_established
自定义Key,图表命名为RELATE_GRAPH.TCP_CONN_ESTABLISH
。
$ python3 zbxcli.py -key "tcp_conn_established" -name "RELATE_GRAPH.TCP_CONN_ESTABLISH" -type groupgraph -nargs "BizGroup001主机群组" "BizGroup002主机群组"
2021-12-11 17:45:36,212 zbxcli.py [line:42] INFO:"BizGroup001主机群组" includes these hosts: host1,host2,...
2021-12-11 17:45:36,851 zbxcli.py [line:52] INFO:{'graphids': ['57139']}
2021-12-11 17:45:36,212 zbxcli.py [line:42] INFO:"BizGroup002主机群组" includes these hosts: host3,host4,...
2021-12-11 17:45:36,851 zbxcli.py [line:52] INFO:{'graphids': ['57140']}
通过指定单台/多台群组,自动将指标值关联到一张表上。我们通过控制台日志可以看到,ZabbixCli分别在BizGroup001主机群组
,BizGroup002主机群组
的主机里创建graphids
为57139和57140的图表,通过快速访问https://<your_ip>/chart2.php?graphid=<your_graphids>
得知它们展示的数据一样。
本文从监控需求分析入手,介绍了整个自动化思路、ZabbixAPI调用方法、图形接口构建与整合、统一Cli入口,相信对于Zabbix和Python入门的同学来说也能轻松理解。最后希望本案例能给各位朋友带来启发,如有疑问欢迎一起交流。