监控套件有三个脚本,一个是自动发现主机上的docker容器脚本,另一个是用python写的获取每个docker容器的系统状态,包括CPU使用率,内存使用率以及网络资源使用率,最后这个脚本添加了一些我公司常用的应用的状态监控,包括应用占用内存,cpu资源以及进程的存活状态,至于读者们需要监控其他docker里面的应用,可以依照我的脚本来进行修改。 # cat /usr/local/zabbix/scripts/docker_low_discovery.sh 9 w ^% O3 D4 Q r/ a5 p/ g
#!/bin/bash
b3 e, R2 G/ i! O* I#Fucation:docker low-level discovery
0 B& P; O% R9 j& \. `docker() { ; Y( W& o3 }6 B% Q P3 _* e4 e
port=($(sudo docker ps -a|grep -v "CONTAINER ID"|awk '{print $NF}')) 8 c6 b) z1 l* j6 j1 O2 I) D
printf '{\n'
8 w. Q7 Y5 R; O* x. \! C/ A printf '\t"data":[\n' % \( h+ L& k! F. u
for key in ${!port[@]} % d$ @. V/ z, {. j
do 9 g* R/ E- ~& g( M$ f& Z M/ k( r
if [[ "${#port[@]}" -gt 1 && "${key}" -ne "$((${#port[@]}-1))" ]];then 5 [# T* g3 s7 B- B/ u; o
printf '\t {\n'
$ `3 Q: T4 {* I2 f7 g printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"},\n" & k, h9 B1 ]& ^
6 {$ a- K3 K" o4 l' D. O7 Q6 p
else [[ "${key}" -eq "((${#port[@]}-1))" ]]
; y1 n1 J) b4 p/ R3 H) v/ X printf '\t {\n' 4 v, m1 I4 k1 S$ s, W" ~ ^
printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"}\n"
L% s+ {6 u, N( V
. |4 {$ k( v2 I$ h5 u1 S% ? fi
* n9 t/ w: U# u1 q done : X; o" p. Z% T
. }. o& p/ p' {5 I Y% |
printf '\t ]\n' 7 Q) S9 {/ M4 G& X
printf '}\n' - ^1 D# m) [1 J$ Q/ Q% i
}
7 a @, [- \# V! D1 R1 [5 xcase $1 in & j7 w6 b7 t% S! w% v
docker) ) L( J" s. N( f/ X
docker
6 g9 V7 I, ]1 l5 G;;
6 m5 _ X) x# z- {6 u3 e8 v*)
1 M/ m8 q' e8 k. E5 B$ Lecho "Usage:`basename $0` {docker}" 1 q9 T8 @# V5 h- z
;;
5 m+ s5 p% O6 n* Xesac 上面这个脚本是用来获取到docker里面应用的容器,并对其进行json化输出的,效果如下: : h5 B' H3 G O% h$ G9 Q: Y
# sh /usr/local/zabbix/scripts/docker_low_discovery.sh docker % E! M9 B0 ?# L1 Z# @$ c
{ & P0 V2 \! U' J2 Y( J
"data":[ 8 S# S% t# ?3 K/ @* _/ b% X& L
{ ( n/ ~6 _( S3 i D3 A) H2 E1 ?
"{#CONTAINERNAME}":"hopeful_brown"},
% d; t' y; b! _; V( @ { 2 ^2 K( p" \9 A0 m3 R# P1 E2 T" K
"{#CONTAINERNAME}":"happy_einstein"}
" Y3 K3 W* O( a$ H# e0 [8 B
7 E6 n, q3 C) k, `4 {7 x: u# w6 V}
5 C0 R( f0 V7 }. ^ z* v6 M这样就能被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命令安装,扩展包我将会打包放在附件中。
. `* C {9 a4 y" W* z' c* a, M3 w; O% A9 n+ ?$ m# L
# cat /usr/local/zabbix/scripts/docker_monitor.py + H( z6 X. ^9 Y P6 E! n( W( v
#!/usr/bin/env python ' u, O. x( {% x; K/ |4 J0 n8 O3 b( l
#-*- coding: utf-8 -*-
1 y' z6 g$ q& j6 s8 i @; Z#author:Xianglin Hu
* }* J/ S5 I; D% s( ?5 L* n3 j+ V! f6 K, A
from docker import Client
) t4 b7 C! f4 w; k7 u6 fimport sys 7 v- f ? X0 [/ `7 R. U
import subprocess
* e- L0 Q' d' p6 q G/ q# iimport os - b1 O6 b; |6 J g! n6 N3 b1 H6 I
/ R+ @" |# j2 W& y+ ~$ tdef check_container_stats(container_name,collect_item):
' Z3 \& [* q& B7 z& ~, J/ k container_collect=docker_client.stats(container_name)
& G- I" U. I' H: y3 V7 j old_result=eval(container_collect.next()) 9 N# B. w% w5 ^8 k4 p) u- B: A/ k6 e
new_result=eval(container_collect.next())
' Q9 e" Z0 ^' k; p a% T; { container_collect.close() - y% k9 m8 ]. l7 y- x" y! @
if collect_item == 'cpu_total_usage': , Y2 @$ Z g2 \2 L+ W4 c! {" i( H
result=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage'] $ @6 @7 j9 {, U2 L3 |5 n* H: {5 L# Q5 H
elif collect_item == 'cpu_system_usage': 2 }, b3 f$ T9 {8 O3 T
result=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
5 Q) K; i- j4 L, z elif collect_item == 'cpu_percent':
% b' `1 e1 N; E3 i cpu_total_usage=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage'] % s0 Z6 T) M- S5 T+ ]! \
cpu_system_uasge=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']
* Z$ Q4 ^( e: c8 g& d! T0 f8 R cpu_num=len(old_result['cpu_stats']['cpu_usage']['percpu_usage']) * f( |" V: R8 u: z" a' l1 F
result=round((float(cpu_total_usage)/float(cpu_system_uasge))*cpu_num*100.0,2)
" X. g: z2 p8 s1 I7 n elif collect_item == 'mem_usage':
. i( K9 ^- B; ~; y result=new_result['memory_stats']['usage'] # w; I' \1 o4 x" V- J! _) t# X
elif collect_item == 'mem_limit':
j+ \( t: \. K. l( U; F3 k- P result=new_result['memory_stats']['limit'] 0 ^( l7 ?( ^6 \# d
elif collect_item == 'mem_percent':
' L4 j) p) ?5 ^2 L- | mem_usage=new_result['memory_stats']['usage']
N/ m' |- a5 ~# a$ C mem_limit=new_result['memory_stats']['limit']
% t( S `. h' A result=round(float(mem_usage)/float(mem_limit)*100.0,2)
6 ^4 ]" Y9 k: p( ^! l8 _: L elif collect_item == 'network_rx_bytes': * n8 k; u$ _2 F
network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name
* C4 K# c, j7 p7 a( @ result=os.popen(network_check_command).read().split()[0]
8 I! Z' Z# Y( P' p/ S& j4 R1 _9 y7 O elif collect_item == 'network_tx_bytes':
g. y3 s' D+ e3 }+ E# y network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name $ b2 G* t) K: m- G' @& }
result=os.popen(network_check_command).read().split()[1] 0 g/ K& w8 t2 V6 @ R# F$ B
return result
H7 L" u; V. W9 e0 U# v8 d$ oif __name__ == "__main__":
" P; |5 ]6 D4 ] docker_client = Client(base_url='unix://var/run/docker.sock', version='1.17') $ r( G9 J: o+ h) a6 }! T$ g7 r& V1 t0 H
container_name=sys.argv[1] * T: Y+ l3 Q1 e2 K! X1 o0 o
collect_item=sys.argv[2]
6 ?: P! Y7 r/ i& C print check_container_stats(container_name,collect_item)
! E% F8 N/ }" {$ C E Z2 c
这里面使用到了docker里面的Client类,获取到某个docker容器的当前状态信息,然后进行运算,返回运算结果。但是容器当前信息那个dict中的network的key获取到的信息不准确,于是我使用了docker exec命令来获取docker容器内部的网络流量信息。这也是我在大神的基础上进行改进的地方,这里的改进将python脚本的执行时间缩短了,将有助于server获取duocker容器信息时减少长连接的数量,提升zabbix_server的性能。这里的docker exec命令将会在下一个脚本中大量使用来获取docker容器中的应用状态信息。 # cat docker_processmonitor.sh
5 m! [7 g5 x) Z" M% G#!/bin/bash * Q; q7 j$ C3 K, `4 o8 ?* V/ a. X4 ^
#license:GPL " U. h- d6 U- {6 ^% X8 o& g
#mail:a714585725@qq.com
P0 @/ R4 A) P! {. O) ]#date:2015.09.22 6 q* b& u! F a) v) @! ~
processmem(){
8 M3 I7 K6 G+ }1 k9 C5 Q9 u/ Q1 U sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$6}; END{print sum}'
$ e4 c2 e. Q0 s} $ P) ]& p$ H/ r/ J
processcpu(){
' `! c6 h/ y p" X8 Y8 }* ]$ U0 R sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$3}; END{print sum}'
4 K* c1 d. I% ~- ^} 9 g! K( j5 b- O% }$ w+ S3 N; Y
processport(){
0 |! e* D7 [- P& y! c3 r sudo /usr/bin/docker exec $1 ss -antlp|grep $2|grep LISTEN|wc -l
9 {$ g0 X* \/ X0 k2 u+ K2 c* W1 c} $ T: t, M- m, H! ?
case "$3" in $ M' ^$ B4 T4 k. e* t
mem) 0 L6 _* G ~: t; O: `- y& P- ^
processmem $1 $2
6 _4 l5 A+ J8 k/ g) w5 O;;
! }9 h0 M0 x/ s8 T ycpu) 3 u( r/ r2 s/ X0 A* c
processcpu $1 $2 5 s( d* D. ~0 q/ A _
;;
3 q, E& ]4 |: T- U9 Sport)
0 ^1 X) U/ L8 {% H( ~$ Uprocessport $1 $2
2 A3 C( l/ s. z; H;; ; V: N* B/ x+ @5 R O- B
*) ' B. [4 T9 b( J* E5 h
echo "Usage: $0 {docker_containername}{processname}{mem|cpu|port}" ; t# ^4 m1 p* v6 c5 z( U& T
;;
5 n: m- ?( A# Q5 D; [esac
0 \& f# d* B, D4 S4 i这个脚本其实没啥说的,从我以前写的那个脚本上面修改来的,使用了一个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命令了。) ! }5 V6 g6 r6 m; O
# tail -3 /usr/local/zabbix/etc/zabbix_agentd.conf
, u D' V1 A8 RUserParameter=docker_low_discovery,/bin/bash /usr/local/zabbix/scripts/docker_low_discovery.sh $1
3 {; i, x8 N8 I& W# ~0 ^UserParameter=docker_stats,sudo /usr/bin/python /usr/local/zabbix/scripts/docker_monitor.py $1 $2 7 {& a+ Q' D r) B! `! h
UserParameter=docker_process,/bin/bash /usr/local/zabbix/scripts/docker_processmonitor.sh $1 $2 $3
0 R' } H, @! k3 ]: P& W, O0 o; G) \% Z# k; L
保存配置并重启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! N& z% T( f8 j1 H5 _9 E( k
{ ( c. k( Z0 n" L1 m
"data":[ # e$ W/ o$ M$ Q9 U3 w' v
{
. C' j1 I1 |. M5 I! `2 B8 m, {"{#CONTAINERNAME}":"hopeful_brown"}, 3 m: F7 m0 w( {
{
( T0 `1 ~, m! H! K& d"{#CONTAINERNAME}":"happy_einstein"} # Y& [3 G' ~5 a
& ?' }% \' e0 l2 E$ `" k} 1 c3 d \9 X4 V0 P2 {# u
[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 b7 R1 `0 G) n2 z2 d. J9664252 ; ]8 E; n& k8 W% R9 S6 L- ^9 W
[root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_process[happy_einstein,nginx,port]" ( S- f r! k# X7 T9 ]
2
0 Q3 g e4 i4 ^% C
) a1 O# P* \$ ]8 D7 E2 y& a0 `! [ |