找回密码
 注册
查看: 4278|回复: 1

docker监控脚本

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2018-6-20 19:05:42 | 显示全部楼层 |阅读模式
监控套件有三个脚本,一个是自动发现主机上的docker容器脚本,另一个是用python写的获取每个docker容器的系统状态,包括CPU使用率,内存使用率以及网络资源使用率,最后这个脚本添加了一些我公司常用的应用的状态监控,包括应用占用内存,cpu资源以及进程的存活状态,至于读者们需要监控其他docker里面的应用,可以依照我的脚本来进行修改。
需要编辑自动发现docker中容器个数的脚本
# cat /usr/local/zabbix/scripts/docker_low_discovery.sh

/ w3 s$ Z6 \( ?% b  O& V8 k9 n; y2 }
#!/bin/bash
1 e* v( j) z+ L0 R
#Fucation:docker low-level discovery
' R# p. `; r) I4 G
docker() {
0 }1 ?: v1 o% K% t
            port=($(sudo docker ps -a|grep -v "CONTAINER ID"|awk '{print $NF}'))

$ i) Z/ x, K- f& T6 L
            printf '{\n'

% X  g- K. L4 O  [
            printf '\t"data":[\n'

" g: |4 w& l& @7 o' A7 R
               for key in ${!port[@]}
) [& m" a3 c9 ]( B
                   do
& ~/ B6 W7 K- p9 T- o1 |6 M+ l
                       if [[ "${#port[@]}" -gt 1 && "${key}" -ne "$((${#port[@]}-1))" ]];then
4 H# O* K. e. b9 Y
                          printf '\t {\n'

, T* t( P! [; }
                          printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"},\n"
$ |' ^2 `% Y& l' O5 [
  

  d& c. b5 Q" ~, Y, @; A, F9 Q, I
                     else [[ "${key}" -eq "((${#port[@]}-1))" ]]

  O( |7 {7 K$ I9 C/ ?$ r" X5 L
                          printf '\t {\n'
4 Z$ q1 u$ L" y3 L0 T: A! x- b
                          printf "\t\t\t\"{#CONTAINERNAME}\":\"${port[${key}]}\"}\n"

4 x. x* k8 v5 ?' K% O% R
  
0 w- N3 C0 _4 I% i$ ~
                       fi
1 p5 x# Z2 U# c6 }) x9 a% b
               done

; D- v9 U4 t7 L6 V; h  ?
  

/ a2 H7 w4 ~9 O' Q) u
                          printf '\t ]\n'
2 g! @& N- Y4 K4 j$ v9 c6 H4 `( r# Q
                          printf '}\n'

( w: v+ s! p& _- c
}

  H9 T# a. Y" _  h* T/ e, m
case $1 in

) f. Z7 a& g0 S+ J6 k. @5 d
docker)

/ {3 B2 P* R: p4 t. X$ I
docker

6 q* g! L! U8 J0 _0 F% o4 \! P- m
;;

: n* ^! v, z! x! W0 x
*)

6 K, t  H! @' y+ c
echo "Usage:`basename $0` {docker}"

3 o& A; i2 o* w) j1 k, f/ J& b  ]
;;
: B3 w4 Q3 r; U; L( d
esac
上面这个脚本是用来获取到docker里面应用的容器,并对其进行json化输出的,效果如下:
& v- f5 E+ \' @7 h
# sh /usr/local/zabbix/scripts/docker_low_discovery.sh docker
8 \8 E3 B' v' D+ p  r+ m
{

: C1 M. P5 |% x- s) j# C' r) M
"data":[
- i. }% m% v5 \) S2 ]  x) ~2 I2 L6 d
{

8 L# E; @* ]6 d
"{#CONTAINERNAME}":"hopeful_brown"},
! u, Q3 y* X" l+ i' ~
{

* E+ k- |7 l3 I$ q' n8 x# h
"{#CONTAINERNAME}":"happy_einstein"}
) \) J& x" d# g! O( O3 H1 d

6 r$ K! `4 x9 q
}
  Q- k3 I# o7 f/ C  d$ h3 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命令安装,扩展包我将会打包放在附件中。

) f, b& o: X$ ?! N3 B

' f  ?% q) q6 S3 p
# cat /usr/local/zabbix/scripts/docker_monitor.py

8 z% x6 ]6 M# n( ]; N5 b
#!/usr/bin/env python

- \- {: z. v" ~' e/ d0 ]* g; n
#-*- coding: utf-8 -*-

6 }  Y: w  B" N( s1 Y
#author:Xianglin Hu
! U9 x3 B2 [9 I. b3 R
3 d* z$ W# ^4 l8 Y
from docker import Client
) U  y5 {. ?  o9 y1 T4 X
import sys

; t, E. |3 @. R" ?5 ^, g
import subprocess
/ D' g! Q/ [* b5 w
import os

$ [2 u! B9 _2 S' x0 S/ e, a$ B! [6 a9 q! E5 R4 E6 K- k: X$ S
def check_container_stats(container_name,collect_item):

; r. R& M) j& S0 h* P+ x1 p
    container_collect=docker_client.stats(container_name)
, y& I$ ~* h, {& s( U$ O: L' e* t
    old_result=eval(container_collect.next())

/ T* T* p7 t8 U& t0 Q* M
    new_result=eval(container_collect.next())
! c3 Z* v) n4 m: h, \
    container_collect.close()
5 F5 A! I* P* Z0 \1 v
    if collect_item == 'cpu_total_usage':
7 R+ X$ c7 |! a( a: e2 H% \
        result=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
" e6 _/ K+ v& p8 \4 x( H" c! W
    elif collect_item == 'cpu_system_usage':

+ R0 \; D/ G' j) b) h" l4 L. S0 d
        result=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']

1 p" @' E& D# g2 n
    elif collect_item == 'cpu_percent':
3 H' i: t) F2 q/ P0 u' {2 r
        cpu_total_usage=new_result['cpu_stats']['cpu_usage']['total_usage'] - old_result['cpu_stats']['cpu_usage']['total_usage']
# G; m4 ^- v3 O4 c8 L& l1 B7 i0 r
        cpu_system_uasge=new_result['cpu_stats']['system_cpu_usage'] - old_result['cpu_stats']['system_cpu_usage']

8 ~) N+ M& K  X( s. f4 J
        cpu_num=len(old_result['cpu_stats']['cpu_usage']['percpu_usage'])
% c- e: |6 O% B
        result=round((float(cpu_total_usage)/float(cpu_system_uasge))*cpu_num*100.0,2)
. I) b, ]/ [4 D0 k2 a  m1 X( \
    elif collect_item == 'mem_usage':

5 r2 Q3 F: Y: ]
        result=new_result['memory_stats']['usage']
2 u9 }3 T+ V9 n4 O, Z' [
    elif collect_item == 'mem_limit':
5 S! f3 T% V0 O3 ]
        result=new_result['memory_stats']['limit']

( c5 X4 }7 N  t
    elif collect_item == 'mem_percent':
0 G; F( s( X) [( b& l- B$ B: H2 }
        mem_usage=new_result['memory_stats']['usage']
2 U7 w* ^0 \7 k6 I/ H5 e8 q
        mem_limit=new_result['memory_stats']['limit']

8 y. w8 J" ?2 U0 q. o
        result=round(float(mem_usage)/float(mem_limit)*100.0,2)

$ B, z* n9 {* O3 [$ C3 a3 \; d. m% V
    elif collect_item == 'network_rx_bytes':
! R  r$ Y9 a/ e  f# ~% V
        network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name

" m( F+ C* ]! t( k+ u7 G$ D
        result=os.popen(network_check_command).read().split()[0]
6 u; F% g% c' x7 B
    elif collect_item == 'network_tx_bytes':

/ H, S8 }: D2 z# \/ L
        network_check_command="""sudo /usr/bin/docker exec %s cat /proc/net/dev|sed -n 3p|awk '{print $2,$10}'"""%container_name
0 I! b& D  c3 I. r. R1 D: T
        result=os.popen(network_check_command).read().split()[1]

+ y+ h* F" g& _+ V; N3 e
    return result

% x# ?' q4 {$ b6 j3 A! ?
if __name__ == "__main__":

* R" B2 @% g/ B" m5 \) H9 y* r
    docker_client = Client(base_url='unix://var/run/docker.sock', version='1.17')
. D$ {1 C# \+ w( y8 g& v2 d
    container_name=sys.argv[1]

& ?2 R& W2 w% M; B% s9 J
    collect_item=sys.argv[2]

" C  ^+ f* A2 ?  X
    print check_container_stats(container_name,collect_item)

8 B4 \1 r. B2 x& ~0 |4 D
这里面使用到了docker里面的Client类,获取到某个docker容器的当前状态信息,然后进行运算,返回运算结果。但是容器当前信息那个dict中的network的key获取到的信息不准确,于是我使用了docker exec命令来获取docker容器内部的网络流量信息。这也是我在大神的基础上进行改进的地方,这里的改进将python脚本的执行时间缩短了,将有助于server获取duocker容器信息时减少长连接的数量,提升zabbix_server的性能。这里的docker exec命令将会在下一个脚本中大量使用来获取docker容器中的应用状态信息。

( c; ~  W; J9 u/ c1 O1 x! V4 A
下面是获取容器应用状态信息的脚本:
# cat docker_processmonitor.sh

, E5 q' u& ]) \8 j
#!/bin/bash

0 Y: x7 Y/ }+ g: _4 ^/ Y
#license:GPL

* [" w* q8 N4 l' J
#mail:a714585725@qq.com
8 x1 r6 R3 k* ?4 h; C$ d% y; y: g
#date:2015.09.22

, N" J9 f1 s6 s, T0 j
processmem(){
7 T1 p; q* F1 ^8 I
        sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$6}; END{print sum}'

) V, g* l! d, x" c/ f# {- p' i$ a
}
. P6 z3 H& }, k. Q
processcpu(){

; F8 f' H  |/ Y& s
        sudo /usr/bin/docker exec $1 ps aux|grep $2|grep -v "grep"|grep -v "processstatus.sh"|awk '{sum+=$3}; END{print sum}'
4 y: s" N$ [) g, F4 x. ]1 b
}
' b0 d0 @6 T8 r; c* U6 Z$ q% u
processport(){

" |, H$ S! B& T. k
        sudo /usr/bin/docker exec $1 ss -antlp|grep $2|grep LISTEN|wc -l

* v* s$ h- ]0 O* t- `. l
}

6 K# H* a0 _+ u7 Q# L
case "$3" in
9 ^' B. ^5 w# d7 ~0 w
mem)

0 [3 R5 `7 o4 y8 ]7 r4 X- w
processmem $1 $2

! ]3 O" E4 O5 J* U1 i: v
;;
; i8 _  i& y8 }& ~) z1 l. V* e* }0 a
cpu)
$ a, R5 O# w6 u% A2 L" S
processcpu $1 $2

, H4 v% _( Y; u' B3 i" a
;;
) O; O9 k/ I/ s( Y1 |
port)
4 d" }7 E5 D' b) c
processport $1 $2
. R$ s. J. e1 K# f: k5 _/ d6 o0 Z
;;

" C7 N4 b# N* s  [$ t2 F- Y! A
*)
8 `( S9 J# H5 r( w9 k
echo "Usage: $0 {docker_containername}{processname}{mem|cpu|port}"
4 v6 J% f% E8 R: N) S" M
;;

; e3 B7 S2 J+ `9 A5 B
esac

: V9 a8 @# g1 r# _

& c$ T; {) }7 K; [  t5 [2 R
这个脚本其实没啥说的,从我以前写的那个脚本上面修改来的,使用了一个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命令了。)
/ d. ^2 A4 |. W3 x
# tail -3 /usr/local/zabbix/etc/zabbix_agentd.conf
; ]' H1 }, l- ^
UserParameter=docker_low_discovery
  • ,/bin/bash /usr/local/zabbix/scripts/docker_low_discovery.sh $1
  • 5 `" K8 {1 c) J+ O
    UserParameter=docker_stats
  • ,sudo /usr/bin/python /usr/local/zabbix/scripts/docker_monitor.py $1 $2
  • 8 q0 a9 P% U  G! q, g0 |' R6 x; {9 E
    UserParameter=docker_process
  • ,/bin/bash /usr/local/zabbix/scripts/docker_processmonitor.sh $1 $2  $3
  • ' G0 F4 h% e% T% F
    ; _: g# f$ \' V# U, w& _/ _6 f+ f
    保存配置并重启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]"

    ( o$ Q* \( C) L. d+ q7 o7 S
    {
    . \9 f8 p, S. \
    "data":[
    9 k3 G# C" N' N9 n1 b! Y6 S
    {

    2 p+ m6 r" `0 H+ b1 L% n- ^7 P. |
    "{#CONTAINERNAME}":"hopeful_brown"},
    ) f/ y5 f, Y) ~1 j3 u2 }) b; V
    {

    % B8 \5 s& W; N. {3 A+ C
    "{#CONTAINERNAME}":"happy_einstein"}

    / n9 K. V  O+ O  w& d0 `
    ( k0 l! c7 u  k: p* f( e
    }

    * |& a4 f  O5 }' |
    [root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_stats[happy_einstein,network_tx_bytes]"
    8 E8 O6 e7 _+ g6 k$ q7 ^& g
    9664252
    & [$ {! E: y, f' k( p( D  T' T
    [root@test1 ~]# /usr/local/zabbix-2.4.4/bin/zabbix_get -s x.x.x.x -k"docker_process[happy_einstein,nginx,port]"

    % u, g2 C# e" E' N6 i' Y* H' q/ {2 {$ u
    2
    7 C: Z; Y9 y  K& f, a
    ! l0 U1 e3 K/ _/ W

    1

    主题

    0

    回帖

    12

    积分

    管理员

    积分
    12
    QQ
     楼主| 发表于 2018-6-20 19:10:02 | 显示全部楼层
    这里的IP地址我就用x.x.x.x代替了,这里应该填写客户端的IP地址。如上所示,能够正确获取到agentd的数据以后,然后就需要在zabbix_server这边配置监控模版了,关于监控模版的配置我在之前的文章中提及了很多次,相信大家应该都不会陌生了,这回就不详细描述模板的建立了,稍后我会将模板打包一起上传至附件中,这个模板目前还是半成品,各位可以根据模板进行修改,可以根据你们的需求来做,下面,演示一下监控出来的效果(PS:只是在测试环境小规模的部署,项目还不错,于是没有做成筛选出来。)
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

    GMT+8, 2026-6-12 00:26 , Processed in 0.017887 second(s), 23 queries .

    Powered by Discuz! X5.0

    © 2001-2026 Discuz! Team.

    快速回复 返回顶部 返回列表