zabbix自动发现实现批量监控docker状态

最近在搞zabbix监控docker以及docker内部应用状态信息,网上找的资料好少,只找到了一个大神的一篇文章,用的是python实现监控docker容器的基本状态,我在他给的脚本基础上进行修改,另外,增长了docker内部经常使用应用的状态监控,目前在测试环境上部署成功了,具体还须要在线上环境部署后才能检验出效果如何。python

好了,根据惯例,废话讲完了,开始进入正题了。nginx

首先,介绍下该监控套件有三个脚本,一个是自动发现主机上的docker容器脚本,另外一个是用python写的获取每一个docker容器的系统状态,包括CPU使用率,内存使用率以及网络资源使用率,最后这个脚本添加了一些我公司经常使用的应用的状态监控,包括应用占用内存,cpu资源以及进程的存活状态,至于读者们须要监控其余docker里面的应用,能够依照个人脚原本进行修改。docker

首先,须要编辑自动发现docker中容器个数的脚本,内容以下:json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# cat /usr/local/zabbix/scripts/docker_low_discovery.sh 
#!/bin/bash
#Fucation:docker low-level discovery
docker() {
            port=($(sudo docker ps -a|grep -v "CONTAINER ID"|awk '{print $NF}'))
            printf '{\n'
            printf '\t"data":[\n'
               for key in ${!port[@]}
                   do
                       if [[ "${#port[@]}" -gt 1 && "${key}" -ne "$((${#port[@]}-1))" ]];then
                          printf '\t {\n'
                          printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"},\n"
  
                     else [[ "${key}" -eq "((${#port[@]}-1))" ]]
                          printf '\t {\n'
                          printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"}\n"
  
                       fi
               done
  
                          printf '\t ]\n'
                          printf '}\n'
}
case $1 in
docker)
docker
;;
*)
echo "Usage:`basename $0` {docker}"
;;
esac

上面这个脚本是用来获取到docker里面应用的容器,并对其进行json化输出的,效果以下:bash

1
2
3
4
5
6
7
8
9
# sh /usr/local/zabbix/scripts/docker_low_discovery.sh docker
{
"data":[
 {
"{#CONTAINERNAME}":"hopeful_brown"},
 {
"{#CONTAINERNAME}":"happy_einstein"}
 ]
}

这样就能被zabbix_server获取到了,而后是python脚本,使用python获取docker的参数须要使用一个扩展包,能够经过pip或者easy_install安装docker-py扩展:网络

pip install docker-py或者easy_install docker-py或者不想这样安装的话能够去python官网下载docker-py的安装包,解压后使用docker docker-py-1.4.0/setup.py install命令安装,扩展包我将会打包放在附件中。app

1
下面是python脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# cat /usr/local/zabbix/scripts/docker_monitor.py 
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#author:Xianglin Hu
#email: a714585725@qq.com
from docker import Client
import sys
import subprocess
import os
 
def check_container_stats(container_name,collect_item):
    container_collect=docker_client.stats(container_name)
    old_result=eval(container_collect.next())
    new_result=eval(container_collect.next())
    container_collect.close()
    if collect_item == 'cpu_total_usage':
        result=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
    elif collect_item == 'cpu_system_usage':
        result=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
    elif collect_item == 'cpu_percent':
        cpu_total_usage=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
        cpu_system_uasge=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
        cpu_num=len(old_result['cpu_stats']['cpu_usage']['percpu_usage'])
        result=round((float(cpu_total_usage)/float(cpu_system_uasge))*cpu_num*100.0,2)
    elif collect_item == 'mem_usage':
        result=new_result['memory_stats']['usage']
    elif collect_item == 'mem_limit':
        result=new_result['memory_stats']['limit']
    elif collect_item == 'mem_percent':
        mem_usage=new_result['memory_stats']['usage']
        mem_limit=new_result['memory_stats']['limit']
        result=round(float(mem_usage)/float(mem_limit)*100.0,2)
    elif collect_item == 'network_rx_bytes':
        network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name
        result=os.popen(network_check_command).read().split()[0]
    elif collect_item == 'network_tx_bytes':
        network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name
        result=os.popen(network_check_command).read().split()[1]
    return result
if __name__ == "__main__":
    docker_client = Client(base_url='unix://var/run/docker.sock', version='1.17')
    container_name=sys.argv[1]
    collect_item=sys.argv[2]
    print check_container_stats(container_name,collect_item)

这里面使用到了docker里面的Client类,获取到某个docker容器的当前状态信息,而后进行运算,返回运算结果。可是容器当前信息那个dict中的network的key获取到的信息不许确,因而我使用了docker exec命令来获取docker容器内部的网络流量信息。这也是我在大神的基础上进行改进的地方,这里的改进将python脚本的执行时间缩短了,将有助于server获取duocker容器信息时减小长链接的数量,提高zabbix_server的性能。这里的docker exec命令将会在下一个脚本中大量使用来获取docker容器中的应用状态信息。ide

下面是获取容器应用状态信息的脚本:性能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# cat docker_processmonitor.sh 
#!/bin/bash
#license:GPL
#mail:a714585725@qq.com
#date:2015.09.22
processmem(){
        sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$6}; END{print sum}'
}
processcpu(){
        sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$3}; END{print sum}'
}
processport(){
        sudo /usr/bin/docker exec $1 ss -antlp|grep $2|grep LISTEN|wc -l
}
case "$3" in
mem)
processmem $1 $2
;;
cpu)
processcpu $1 $2
;;
port)
processport $1 $2
;;
*)
echo "Usage: $0 {docker_containername}{processname}{mem|cpu|port}"
;;
esac

这个脚本其实没啥说的,从我之前写的那个脚本上面修改来的,使用了一个case来判断须要获取的docker容器的名称以及该容器中应用的状态信息,只不过这里获取docker容器状态信息使用的是docker exec命令来进行获取。另外这里面添加了对于应用是否存活的状态监测,那就是检测该应用是否侦听了网络端口,假如该应用侦听的网络端口个数为0的话,能够认为该应用存在异常。这些应用只是我公司使用比较多的应用,各位读者能够根据本身需求修改相应应用的监控。测试

因为docker是以root权限来启用的,而zabbix监控是使用zabbix用户来执行的,因此须要给予zabbix用户相应的权限,须要编辑visudo:

echo "zabbix ALL=(root) NOPASSWD:/bin/docker,/usr/bin/python,/usr/local/zabbix/scripts/docker_monitor.py,/usr/local/zabbix/scripts/docker_low_discovery.sh,/usr/local/zabbix/scripts/docker_processmonitor.sh">>/etc/sudoers

而且还须要注释掉这条记录:#Defaults    requiretty(PS:注意,这条记录是要求使用sudo命令时须要有终端界面,注释掉这一条以后就能够不须要终端执行sudo命令了。)

而后就是编辑zabbix_agentd.conf文件,添加下面几行:

1
2
3
4
# tail -3 /usr/local/zabbix/etc/zabbix_agentd.conf
UserParameter=docker_low_discovery[*],/bin/bash /usr/local/zabbix/scripts/docker_low_discovery.sh $1
UserParameter=docker_stats[*],sudo /usr/bin/python /usr/local/zabbix/scripts/docker_monitor.py $1 $2
UserParameter=docker_process[*],/bin/bash /usr/local/zabbix/scripts/docker_processmonitor.sh $1 $2  $3

保存配置并重启zabbix_agentd服务,而后修改脚本的属主属组以及权限:

chown zabbix.zabbix /usr/local/zabbix/scripts/*

chmod 755 /usr/local/zabbix/scripts/*

而后能够在zabbix_server端测试是否可以获取到相应的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_low_discovery[docker]"
{
"data":[
 {
"{#CONTAINERNAME}":"hopeful_brown"},
 {
"{#CONTAINERNAME}":"happy_einstein"}
 ]
}
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_stats[happy_einstein,network_tx_bytes]"
9664252
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_process[happy_einstein,nginx,port]"
2

这里的IP地址我就用x.x.x.x代替了,这里应该填写客户端的IP地址。如上所示,可以正确获取到agentd的数据之后,而后就须要在zabbix_server这边配置监控模版了,关于监控模版的配置我在以前的文章中说起了不少次,相信你们应该都不会陌生了,这回就不详细描述模板的创建了,稍后我会将模板打包一块儿上传至附件中,这个模板目前仍是半成品,各位能够根据模板进行修改,能够根据大家的需求来作,下面,演示一下监控出来的效果(PS:只是在测试环境小规模的部署,项目还不错,因而没有作成筛选出来。)

wKiom1YCNKijPnKqAARGQVkQrkU379.jpg

wKioL1YCNKmANky3AAQUhMCh3uI528.jpg

wKiom1YCNKnz_z-oAAZv7Th1Pg4991.jpg

wKioL1YCNKryA4TpAAQWnWd663M845.jpg

wKiom1YCNKmCCLXnAAGm1pwS55M476.jpg

上面这些显示的是监控的结果,各位也能够根据本身的需求来进行修改,总之一句话,zabbix能够作到任何你想作的监控,嘻嘻!!!

本文出自 “柠檬” 博客,请务必保留此出处http://xianglinhu.blog.51cto.com/5787032/1697427