监控套件有三个脚本,一个是自动发现主机上的docker容器脚本,另一个是用python写的获取每个docker容器的系统状态,包括CPU使用率,内存使用率以及网络资源使用率,最后这个脚本添加了一些我公司常用的应用的状态监控,包括应用占用内存,cpu资源以及进程的存活状态,至于读者们需要监控其他docker里面的应用,可以依照我的脚本来进行修改。 # cat /usr/local/zabbix/scripts/docker_low_discovery.sh
4 o- x0 y: g; U3 o6 k y5 D' P q#!/bin/bash 9 p$ \+ S, H7 L! g! u
#Fucation:docker low-level discovery
' h! [# ?0 w6 v9 t# ?/ e! t3 l3 m) hdocker() { . l) \, u% q7 l1 ?+ I# F
port=($(sudo docker ps -a|grep -v "CONTAINER ID"|awk '{print $NF}')) 9 m O: W. B! ^
printf '{\n'
0 p0 k. y K3 r printf '\t"data":[\n'
' t" y7 q, s% Q+ q; [ for key in ${!port[@]}
0 x! D) ]" Y7 L' G& N$ {& }9 r+ B7 A K do 9 p6 n' a* l; B8 U4 p( \
if [[ "${#port[@]}" -gt 1 && "${key}" -ne "$((${#port[@]}-1))" ]];then 5 O- N, B* l; R
printf '\t {\n'
! C3 O7 e( h6 {( W2 S2 u7 \ printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"},\n"
" @4 _ U6 B1 p& T % A; R' V- e) q: O
else [[ "${key}" -eq "((${#port[@]}-1))" ]] . j8 i$ E0 v# H; l' U( q
printf '\t {\n'
, U4 q! ^# K/ G) G8 J printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"}\n"
- v9 N" _1 ^3 ~8 ?$ k ]- r* X
6 J- z) [0 O/ X1 T fi
& s& F# u1 N$ Z) y& r done 4 K% f, \! W6 ^" G( D& R: Q6 F6 H
# ^' t4 l" {6 p5 K. C printf '\t ]\n'
; D8 y K; L. \" u printf '}\n'
' I7 H( Z0 h! W( l3 ~# n9 Z M- _}
- T, J5 p/ N \' kcase $1 in 7 {- Z; K! x7 M# m# m4 k
docker)
$ T8 \9 e/ h% u3 ydocker
7 Z& c8 f$ d( f;; ( H- |, N; ~' |6 z; `4 g
*)
9 C/ F) V* c( Y0 R. Fecho "Usage:`basename $0` {docker}" * {; x8 F! l3 w5 ?- m) a
;; / Z5 T6 B( i+ {/ P* E4 C/ J2 o0 [3 X, i
esac 上面这个脚本是用来获取到docker里面应用的容器,并对其进行json化输出的,效果如下: ' y# ~ g; g, V
# sh /usr/local/zabbix/scripts/docker_low_discovery.sh docker
6 l- h: ?0 ~" A4 R{ * R6 B, \) _6 G/ T3 o. U' D
"data":[
0 \: k6 {0 S& P2 N {
7 ]; W7 @0 ~( Q! I, f- k3 H"{#CONTAINERNAME}":"hopeful_brown"},
% f; F0 y7 e. ]7 F {
; M9 U: R, n7 [/ X$ ^"{#CONTAINERNAME}":"happy_einstein"} : z# f# @) Y" U5 `+ m- |
3 r/ f' _5 O2 x* {1 M- _5 R
}
/ I; _! y- o( v U, G这样就能被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命令安装,扩展包我将会打包放在附件中。
/ S' s( ~5 y$ t- B+ p3 v- o0 c/ V. w' y0 d, A4 I
# cat /usr/local/zabbix/scripts/docker_monitor.py 5 S) A: ^' L# ]- q; k8 e
#!/usr/bin/env python " \& n+ f7 u- M. {
#-*- coding: utf-8 -*- 4 @# K7 d6 I4 m) s) i
#author:Xianglin Hu 1 m4 X! D$ Y- n! @
7 J& S' p/ Y0 d3 i: f, l; X+ Afrom docker import Client
4 N8 l0 P5 b. B0 v t1 {import sys
8 U5 }) P& g0 @/ eimport subprocess % L8 M& c& N( n& u
import os
$ @" l: \ D1 k' i4 C C+ J5 A0 z. p/ _
def check_container_stats(container_name,collect_item): 8 n7 H! m: _! b
container_collect=docker_client.stats(container_name) 0 Q4 L% y; Y8 U: A& C3 d/ s# q/ Z: r
old_result=eval(container_collect.next()) * a- p# t8 Q1 i% A- R
new_result=eval(container_collect.next())
: ]+ \* i/ S( K& ?; e container_collect.close()
! a( A+ ]8 m4 k3 A6 }$ F7 L! R if collect_item == 'cpu_total_usage': 1 r5 ^2 S) k0 v& ^, T0 x
result=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
$ \7 F1 z0 f0 [1 R. n; p elif collect_item == 'cpu_system_usage': ; u, S+ W b& D1 `1 J
result=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
+ J+ W3 u1 E4 V$ j. K M elif collect_item == 'cpu_percent':
; x$ d; ~( l4 j0 |& P cpu_total_usage=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage'] % B6 m" C/ ?2 P5 @
cpu_system_uasge=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
2 X$ [5 _0 R" P, M/ } cpu_num=len(old_result['cpu_stats']['cpu_usage']['percpu_usage']) 8 e+ Q. {/ f9 j& C0 [' I
result=round((float(cpu_total_usage)/float(cpu_system_uasge))*cpu_num*100.0,2) 8 U: L& d! j" P+ ^( @2 H5 [
elif collect_item == 'mem_usage': : k2 H4 s# I* {" ^5 Q# H
result=new_result['memory_stats']['usage']
( y ]! i) g n+ L elif collect_item == 'mem_limit': 5 u& Q3 X( R' w- F, B
result=new_result['memory_stats']['limit'] , z2 Y; S8 m7 Q4 B V
elif collect_item == 'mem_percent':
- @" R' J& V7 ]0 S5 o& @! b mem_usage=new_result['memory_stats']['usage'] 1 P. r5 `* n3 D. k, m
mem_limit=new_result['memory_stats']['limit'] " O/ O% f6 T3 y+ M% g, r
result=round(float(mem_usage)/float(mem_limit)*100.0,2) / K; ^3 r: `! {$ j5 x
elif collect_item == 'network_rx_bytes': $ m2 r9 ^- u4 S7 ~# p6 ^
network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name % n$ w! h2 l+ ^) J- g f+ B7 S; C
result=os.popen(network_check_command).read().split()[0]
: H7 p! n, z& p elif collect_item == 'network_tx_bytes':
( ]5 p! s/ t6 t4 P network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name " j* A! P; V: G: P! Q3 K
result=os.popen(network_check_command).read().split()[1] , L- L* W' s3 N7 ^2 d$ J2 N+ _
return result ! a) e& g/ i$ k# e) M
if __name__ == "__main__": " r5 z( E' \0 J' N0 B- i8 b5 M
docker_client = Client(base_url='unix://var/run/docker.sock', version='1.17') ' q Q) v3 _3 k! o0 y8 c+ i
container_name=sys.argv[1]
. a9 N+ P, V! S6 k- u ?9 r6 w" E' V collect_item=sys.argv[2] / A9 H* F3 w' H" ^- }: T
print check_container_stats(container_name,collect_item) " t" U0 ]) p7 y
这里面使用到了docker里面的Client类,获取到某个docker容器的当前状态信息,然后进行运算,返回运算结果。但是容器当前信息那个dict中的network的key获取到的信息不准确,于是我使用了docker exec命令来获取docker容器内部的网络流量信息。这也是我在大神的基础上进行改进的地方,这里的改进将python脚本的执行时间缩短了,将有助于server获取duocker容器信息时减少长连接的数量,提升zabbix_server的性能。这里的docker exec命令将会在下一个脚本中大量使用来获取docker容器中的应用状态信息。
% A! t( L3 E6 m/ p6 M+ h7 L# w
# cat docker_processmonitor.sh 6 n7 Y4 O+ J) }7 W( Q+ c" J
#!/bin/bash 7 y, [/ q l$ d* Q/ e
#license:GPL " O) B6 N) o5 {1 V1 n9 ?
#mail:a714585725@qq.com
- g% A: I9 k* H% L( y#date:2015.09.22 3 [+ `" p/ K9 A* U
processmem(){ " m% k9 s, C: c% c C6 g
sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$6}; END{print sum}' ' j4 O- ]& E! P
} , ~& H$ b$ t$ [) Q& d/ v8 s
processcpu(){ + c @, j0 h# A! ?* \! }1 [* V
sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$3}; END{print sum}' : Y9 |& O9 i/ o2 x% N3 n, m% S* Q
} # ^3 P4 H& ^/ ^
processport(){
; h) d3 V; \, A: ]1 h8 M sudo /usr/bin/docker exec $1 ss -antlp|grep $2|grep LISTEN|wc -l
2 W2 o8 p: a1 T: c; r# A} " ?, X7 y1 j5 E. U
case "$3" in
' r: w6 ]+ H. e% M% y) N1 ^8 bmem) 7 A# ~/ W0 `8 D/ H* Y
processmem $1 $2 ' t3 w6 s* O- b: d. g
;; 3 x$ k$ O) N6 ~! C4 d
cpu) ) z. [: ]" l; s4 `% ]
processcpu $1 $2 `1 s: B9 N: l. G: U" H
;;
7 \8 Y1 ~7 ]- Y2 G* S7 b; oport)
& a: ]5 @6 j- J1 y% sprocessport $1 $2
6 {: [# E- b4 S4 _9 `+ n; t8 r/ e;; / q+ ?+ a- h M' x
*)
! V2 f2 @5 J" y9 g* Oecho "Usage: $0 {docker_containername}{processname}{mem|cpu|port}" " A" v) c5 X7 n7 ?, e) l8 f
;;
0 ?- K+ t* k7 e% Q; qesac
* [- \& r4 T/ M# D. ]0 {* V这个脚本其实没啥说的,从我以前写的那个脚本上面修改来的,使用了一个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命令了。)
7 V. g" n1 q6 p: F, ~4 y6 \& w) v# tail -3 /usr/local/zabbix/etc/zabbix_agentd.conf , O4 Y4 k2 S1 p8 {/ ?
UserParameter=docker_low_discovery,/bin/bash /usr/local/zabbix/scripts/docker_low_discovery.sh $1 + K" q1 C& P+ \
UserParameter=docker_stats,sudo /usr/bin/python /usr/local/zabbix/scripts/docker_monitor.py $1 $2 * \( t+ e! h% V# f' X$ J5 O$ e
UserParameter=docker_process,/bin/bash /usr/local/zabbix/scripts/docker_processmonitor.sh $1 $2 $3 : A x0 K9 J, b2 |1 q- J; E* C4 e
6 ?( m- {& n; C; p1 [% ~; p& y
保存配置并重启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]"
* b: h f# I0 w5 v! n& S{ , ?3 t/ G; y k2 S6 }
"data":[ 8 z7 c& h2 a, R2 F$ @
{ ; K6 w/ J V' q) G" m- Q
"{#CONTAINERNAME}":"hopeful_brown"},
) A! {$ K& S! M/ M* } { 3 f% e L5 g; V. }2 U
"{#CONTAINERNAME}":"happy_einstein"} 6 @2 c8 r" Q6 S J
) N2 J0 O3 t6 Y& p( Z
} 4 I: i5 ?; ]$ t
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_stats[happy_einstein,network_tx_bytes]" 3 r% m9 N. v' J q
9664252 9 d( B& x$ R/ b4 t" S
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_process[happy_einstein,nginx,port]" 4 Z# K# u5 I- {2 B4 n
2 E Q# F6 e' K" f& a& v' w+ _& J8 s
& w; M: h# f, g6 a6 M7 X |