最近在搞zabbix监控docker以及docker内部应用状态信息,网上找的资料好少,只找到了一个大神的一篇文章,用的是python实现监控docker容器的基本状态,我在他给的脚本基础上进行修改,另外,增加了docker内部常用应用的状态监控,目前在测试环境上部署成功了,具体还需要在线上环境部署后才能检验出效果如何。
好了,根据惯例,废话讲完了,开始进入正题了。
首先,介绍下该监控套件有三个脚本,一个是自动发现主机上的docker容器脚本,另一个是用python写的获取每个docker容器的系统状态,包括CPU使用率,内存使用率以及网络资源使用率,最后这个脚本添加了一些我公司常用的应用的状态监控,包括应用占用内存,cpu资源以及进程的存活状态,至于读者们需要监控其他docker里面的应用,可以依照我的脚本来进行修改。
首先,需要编辑自动发现docker中容器个数的脚本,内容如下:
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化输出的,效果如下:
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命令安装,扩展包我将会打包放在附件中。
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: [email protected]
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容器中的应用状态信息。
下面是获取容器应用状态信息的脚本:
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:[email protected]
#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:只是在测试环境小规模的部署,项目还不错,于是没有做成筛选出来。)
上面这些显示的是监控的结果,各位也可以根据自己的需求来进行修改,总之一句话,zabbix可以做到任何你想做的监控,嘻嘻!!!
本文出自 “柠檬” 博客,请务必保留此出处http://xianglinhu.blog.51cto.com/5787032/1697427