监控套件有三个脚本,一个是自动发现主机上的docker容器脚本,另一个是用python写的获取每个docker容器的系统状态,包括CPU使用率,内存使用率以及网络资源使用率,最后这个脚本添加了一些我公司常用的应用的状态监控,包括应用占用内存,cpu资源以及进程的存活状态,至于读者们需要监控其他docker里面的应用,可以依照我的脚本来进行修改。 # cat /usr/local/zabbix/scripts/docker_low_discovery.sh
: B" X$ B7 Q; E" ~, r9 n4 o$ Q#!/bin/bash 2 V- D" h# k7 X9 R- p" I# v' N
#Fucation:docker low-level discovery 0 o @ h3 y7 w- S' L& [# ?
docker() {
( o% ?2 D9 S/ P4 w& K& C; ~ port=($(sudo docker ps -a|grep -v "CONTAINER ID"|awk '{print $NF}')) * C* l) ~& U+ ~8 W, Q! b
printf '{\n' - k! Q9 n2 _# n# S- i8 g/ a4 r4 p
printf '\t"data":[\n'
3 c1 Z" [+ D1 T3 @ for key in ${!port[@]}
; E" d* F( i* D7 {1 G: \ do : D8 F7 j4 C, J. u& d& K ]% e
if [[ "${#port[@]}" -gt 1 && "${key}" -ne "$((${#port[@]}-1))" ]];then ) W. S3 ^( W+ t! F0 t. H" d; F7 o6 {
printf '\t {\n'
. H- ?" N, i3 h printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"},\n"
4 Q* Q& f8 S+ V& N9 K $ Z( D$ h) Q4 D0 w8 w$ f
else [[ "${key}" -eq "((${#port[@]}-1))" ]] ! h" [% m! l3 P
printf '\t {\n'
7 j8 [, ~) v- K8 u' p) |/ M printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"}\n" 0 p1 b0 p" T4 Z0 J! l! @: x. C) ]
9 k& V1 h* D) F: E3 h _
fi + v) K' x3 L" {' S6 p. H: u/ e
done & b0 ]1 ]. R2 w
, c" f4 r" o. ?+ G+ X& x+ G printf '\t ]\n' & e# W8 r- y( Y
printf '}\n' $ b+ }4 l3 N+ {0 ^ A
} 1 `% h; m6 a% N5 s
case $1 in ' Y1 M6 T$ Z! Q) u. R, U
docker)
3 F+ Y/ |) `! o0 K- ~docker 7 n' d6 A* \9 O( x) L+ d7 {% b
;;
1 o0 F' U! |- {9 m9 b*)
' H5 D5 ~ M0 j9 d) Jecho "Usage:`basename $0` {docker}" - u+ L2 I4 J7 ?( w: v
;;
9 q- q2 B/ b& Pesac 上面这个脚本是用来获取到docker里面应用的容器,并对其进行json化输出的,效果如下: ) @, t; J. p4 m
# sh /usr/local/zabbix/scripts/docker_low_discovery.sh docker
- E: I; L3 N2 z{ " P7 V! n# Z# Y9 I
"data":[
1 @9 u1 n, c& |" A. y" ~. ?' Q { 3 f% O" Z, s/ }( y4 G
"{#CONTAINERNAME}":"hopeful_brown"}, 9 @' _8 v5 f& \8 O8 q4 ]4 v
{ : G% ^# A1 x3 \
"{#CONTAINERNAME}":"happy_einstein"}
* H$ y# m; R( \8 o$ d0 r% V5 M9 ?) m
} C2 j b) V P- S1 ^
这样就能被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命令安装,扩展包我将会打包放在附件中。
9 K8 B& B F1 C( V& [6 [
- ^4 Q; x6 y- y; E5 U2 @4 h k6 e
# cat /usr/local/zabbix/scripts/docker_monitor.py ' u/ d% k& x- M" U$ h' D
#!/usr/bin/env python
6 _( J% H, x& `* D#-*- coding: utf-8 -*-
2 u! a n! _8 Z6 k8 ~#author:Xianglin Hu 0 ^2 f2 d @% p7 d8 I1 m
Y( x7 x# s& f9 l" ffrom docker import Client & j4 a: E5 D1 B/ i; S! j
import sys / k$ |( y. E# ?( ~# M7 \
import subprocess 7 D. b) B' c! E- e, G/ k/ Y3 G6 }
import os
, g7 u4 H* F o" \5 E
u' k6 D: h, x( s9 ?def check_container_stats(container_name,collect_item): ' T) |( G6 I0 r# A7 u9 C
container_collect=docker_client.stats(container_name)
+ t8 A$ Q- @" k0 k M q old_result=eval(container_collect.next())
+ c8 E( k; L5 ~ new_result=eval(container_collect.next())
* E- f: r! a7 }' _3 d8 q, g container_collect.close()
2 t2 `! w1 |% K if collect_item == 'cpu_total_usage':
! r% J( Q5 s. K2 D/ R, e0 p result=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
' K" C' s. _5 F1 {* p2 {8 | elif collect_item == 'cpu_system_usage': / K- T: f5 W: w4 W0 x
result=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
1 C; V1 U+ K! Y9 L3 a) h* \% G( ~ elif collect_item == 'cpu_percent':
; J4 d3 U" r0 P0 u( D f cpu_total_usage=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
' \7 w3 b5 u( m% p( } cpu_system_uasge=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
4 C2 D1 F4 c* A cpu_num=len(old_result['cpu_stats']['cpu_usage']['percpu_usage'])
0 j7 e" I3 F- ~& i9 c result=round((float(cpu_total_usage)/float(cpu_system_uasge))*cpu_num*100.0,2) % E- [1 `2 E: @) \. h
elif collect_item == 'mem_usage':
2 q/ V) c9 \- c: m: x result=new_result['memory_stats']['usage'] 4 k$ K6 t+ ]) e1 F1 c
elif collect_item == 'mem_limit': 8 N& {1 ?# y% ^' b+ a, }, ~
result=new_result['memory_stats']['limit']
/ U% w5 N. B5 Y4 j$ b q elif collect_item == 'mem_percent': ; A+ Z. D9 J! @4 D
mem_usage=new_result['memory_stats']['usage']
- Q# }: r' N+ ?$ I- ^1 K mem_limit=new_result['memory_stats']['limit'] $ P% n' l- z% P: Z/ T
result=round(float(mem_usage)/float(mem_limit)*100.0,2)
/ Y5 L/ v7 ]/ A% ^7 p3 d: B; q elif collect_item == 'network_rx_bytes':
9 O/ G- z2 Y3 ]6 l network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name S3 m2 W$ b' j' h8 a* |* k; i
result=os.popen(network_check_command).read().split()[0] * h5 A( R7 J" F. Q
elif collect_item == 'network_tx_bytes': + I) c+ I+ O) {- M: Z8 ~1 l
network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name ' I% w2 S5 t( ~. ~2 V. @3 T
result=os.popen(network_check_command).read().split()[1] 7 Z2 S& Q8 @" g2 x5 s
return result
/ D$ O; t& d; j- Wif __name__ == "__main__": / r7 ~1 ~1 u0 |! M' F6 K7 B
docker_client = Client(base_url='unix://var/run/docker.sock', version='1.17')
0 U3 Q4 b8 d2 l4 { container_name=sys.argv[1] 3 x. o& K* B7 M6 M' ~8 j8 f' g
collect_item=sys.argv[2] - l* a4 E3 a0 O T7 k/ b
print check_container_stats(container_name,collect_item)
) C/ p1 B$ ~9 ?9 q. C
这里面使用到了docker里面的Client类,获取到某个docker容器的当前状态信息,然后进行运算,返回运算结果。但是容器当前信息那个dict中的network的key获取到的信息不准确,于是我使用了docker exec命令来获取docker容器内部的网络流量信息。这也是我在大神的基础上进行改进的地方,这里的改进将python脚本的执行时间缩短了,将有助于server获取duocker容器信息时减少长连接的数量,提升zabbix_server的性能。这里的docker exec命令将会在下一个脚本中大量使用来获取docker容器中的应用状态信息。
" i$ ^- p3 u6 ^" I' A6 ]+ h
# cat docker_processmonitor.sh
! \% m; N4 ~7 M& U# o4 p3 x#!/bin/bash
; z7 K. E# J7 _: W0 i#license:GPL 2 l' G: U2 K) }9 w+ M3 N' Q
#mail:a714585725@qq.com . v; P% n& U ^2 ]2 Q
#date:2015.09.22
' I' M6 @% Z4 a9 P) U7 w" Cprocessmem(){ / D2 o y6 h- e) U+ W1 ]" }
sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$6}; END{print sum}'
, z/ i$ Q1 d G( u9 v7 m3 J0 v}
' v& f7 Y) ?. V2 O" |processcpu(){
% z6 Y& W& o; c7 f* @: q [ sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$3}; END{print sum}'
9 o0 _" O- Z. G}
/ P; R. h- u2 G ?9 ^6 ^1 V6 Oprocessport(){
' t- i9 F4 }7 W sudo /usr/bin/docker exec $1 ss -antlp|grep $2|grep LISTEN|wc -l
6 Z/ W' T2 x d2 H; k}
) u( _* i2 W9 c+ icase "$3" in $ u/ i& Y7 ^ g$ Z2 [# k" M
mem) ) H( W% Y/ w% `( b( T# Z. a
processmem $1 $2
/ w( H+ A4 ~6 O' U2 u! n0 O7 @7 ~;; * D# X# L2 J; }, i
cpu) 4 i( p1 D) g' n- `" l
processcpu $1 $2
2 i' Z( S8 L9 X% Q8 I& V6 M. D;; + d) l# I& W9 o \
port) 4 o6 v, |7 j; ?! P. o5 a
processport $1 $2
" N s. {" J6 Y4 }# S/ v;; * v1 _9 L8 D# `" y) r
*) 5 L+ x) R7 r( }" x0 _! w
echo "Usage: $0 {docker_containername}{processname}{mem|cpu|port}" 0 ]* {, f' m. a& G+ z% g# y
;;
) v# }$ |! C% @" ^! Oesac
, \3 i) q8 y/ L( b6 T5 t
" {: c; m9 x9 d, C$ E+ H+ B
这个脚本其实没啥说的,从我以前写的那个脚本上面修改来的,使用了一个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命令了。)
! C7 ~; j2 P5 }" q# tail -3 /usr/local/zabbix/etc/zabbix_agentd.conf
6 A! g p, ?* _6 w; c# zUserParameter=docker_low_discovery,/bin/bash /usr/local/zabbix/scripts/docker_low_discovery.sh $1
5 T9 V& `0 x% m& z0 DUserParameter=docker_stats,sudo /usr/bin/python /usr/local/zabbix/scripts/docker_monitor.py $1 $2
! B6 a# R4 h- T, W% [UserParameter=docker_process,/bin/bash /usr/local/zabbix/scripts/docker_processmonitor.sh $1 $2 $3
; M( N- U" o! J
% ~# p% B0 ?* W9 O9 b$ e保存配置并重启zabbix_agentd服务,然后修改脚本的属主属组以及权限: chown zabbix.zabbix /usr/local/zabbix/scripts/* chmod 755 /usr/local/zabbix/scripts/* 然后可以在zabbix_server端测试是否能够获取到相应的数据: [root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_low_discovery[docker]"
6 b- p- Y% Y- E6 y* `& O{ 3 H( v2 {4 r4 J: R2 ?$ u7 A
"data":[
* v. l+ ?3 n: B* a5 o' [ {
2 L5 Y0 i' g& D6 s' u$ w( l"{#CONTAINERNAME}":"hopeful_brown"}, , ~- N+ s1 a' B% @% [( }4 o
{
7 ~9 g: e x q9 o8 z"{#CONTAINERNAME}":"happy_einstein"} $ c+ h+ D( p6 v" m; C( `
; S- K% _4 q% B( t/ |- V% s
} 8 p3 h3 x3 O0 w% }6 H
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_stats[happy_einstein,network_tx_bytes]" ; z/ V0 B' X$ H8 L! }& t6 p7 ^8 u
9664252 8 o& }. [3 A3 S9 U
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_process[happy_einstein,nginx,port]" % ^( F' N% a3 U, a5 G
2 " f$ Q" b) f! _, O2 l
0 H% h6 E& J0 s6 Y( A* ?
|