找回密码
 注册
查看: 4281|回复: 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
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 x
case $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$ L
echo "Usage:`basename $0` {docker}"
1 q9 T8 @# V5 h- z
;;

5 m+ s5 p% O6 n* X
esac
上面这个脚本是用来获取到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 f
import sys
7 v- f  ?  X0 [/ `7 R. U
import subprocess

* e- L0 Q' d' p6 q  G/ q# i
import os
- b1 O6 b; |6 J  g! n6 N3 b1 H6 I

/ R+ @" |# j2 W& y+ ~$ t
def 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$ o
if __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容器中的应用状态信息。
4 I1 ~" m% _# ]. l! B
下面是获取容器应用状态信息的脚本:
# 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  y
cpu)
3 u( r/ r2 s/ X0 A* c
processcpu $1 $2
5 s( d* D. ~0 q/ A  _
;;

3 q, E& ]4 |: T- U9 S
port)

0 ^1 X) U/ L8 {% H( ~$ U
processport $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

2 D. ?, T9 s. q
这个脚本其实没啥说的,从我以前写的那个脚本上面修改来的,使用了一个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 R
UserParameter=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. J
    9664252
    ; ]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 `! [

    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 02:22 , Processed in 0.016251 second(s), 23 queries .

    Powered by Discuz! X5.0

    © 2001-2026 Discuz! Team.

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