標籤(空格分隔): Docker 監控 Monitoringpython
做者是 LE JOURNAL DE CHRISTOPHE,原文地址是 Simple Monitoring for Docker (Part I)docker
從 VM 遷移到 Docker 容器是很是容易的,除了監控部分。一個簡單的方法,運行一個數據收集客戶端(好比 Zabbix 客戶端),絕對不是一個好的解決方案,由於它與 Docker 的每一個容器中只有一個清楚明確任務的哲學相悖,而且也由於它要求使用定製的鏡像。從收集 LXC 和 Docker 容器的指標開始,我用一個基於系統的簡單腳原本收集來自於 Docker 容器的指標。shell
我使用 Zabbix 來彙總性能指標,所以該腳本將被設計成用在 Zabbix 客戶端的 user parameter。一個 user parameter 是一個被 Zabbix 運行而且返回某些信息的基本腳本。User parameters 不得不被定義在客戶端的配置文件中,但可能接收參數是爲了單個腳本的多個信息。bash
這些指標在 Docker 主機級別生成,而不是容器級別。這是一個熱身,一個概念驗證或者是一個冒煙測試用於斷言在個人監控系統,一切都是正確安裝的。目前是收集一些與容器相關的指標。網絡
如下是一個簡單的 shell 實現:性能
#!/bin/bash function countContainers() { docker ps -q $1 | wc -l } function countCrashedContainers() { docker ps -a | grep -v -F 'Exited (0)' | grep -c -F 'Exited (' } TYPE=${1-all} case $TYPE in running) COUNT_FUNCTION="countContainers"; shift;; crashed) COUNT_FUNCTION="countCrashedContainers"; shift;; all) COUNT_FUNCTION="countContainers -a"; shift;; esac $COUNT_FUNCTION
而後對 Zabbix 作一些配置後,會生成看起來像這樣的圖:測試
由於我有 9 個容器長期運行,3 個數據容器和一個容器以定時每小時啓動一次,這是符合我指望的。ui
一個相似的腳本能夠被寫的用於收集鏡像的指標,好比鏡像的總數量以及多少是 dangling 的。spa
首先我想收集每一個容器的如下指標:設計
這些能夠在 docker inspect <container-id>
發現。IP 地址被髮如今 NetworkSettings.IPAddress
以及我從如下獲取到的 State 計算狀態:
cpu 和 內存能夠在 /sys/fs/cgroup/docker
目錄下 cpuacct.stat
和 memory.stat
文件檢索到。
根據博客文章,目前檢索 network activity 比檢索 CPU 或 Memory 更復雜而且我不喜歡在文章中提到的方法。儘管如此,這些數據能夠十分容易的從容器中檢索到的,經過在容器實例運行一個簡單的 ifconfig eth0
命令或是從 /sys
層次結構中查看。感謝 Docker 1.3 中引進的 exec
命令,運行這個命令進入一個運行着的容器是十分容易的,不須要任何定製鏡像或者在啓動容器時指定任何命令。
#!/usr/bin/env python __author__ = 'Christophe Labouisse' import argparse import re import os from docker import Client from docker.utils import kwargs_from_env def display_cpu(args): detail = c.inspect_container(args.container) if bool(detail["State"]["Running"]): container_id = detail['Id'] cpu_usage = {} with open('/sys/fs/cgroup/cpuacct/docker/' + container_id + '/cpuacct.stat', 'r') as f: for line in f: m = re.search(r"(system|user)\s+(\d+)", line) if m: cpu_usage[m.group(1)] = int(m.group(2)) if args.type == "all": cpu = cpu_usage["system"] + cpu_usage["user"] else: cpu = cpu_usage[args.type] user_ticks = os.sysconf(os.sysconf_names['SC_CLK_TCK']) print(float(cpu) / user_ticks) else: print(0) def display_ip(args): detail = c.inspect_container(args.container) print(detail['NetworkSettings']['IPAddress']) def display_memory(args): detail = c.inspect_container(args.container) if bool(detail["State"]["Running"]): container_id = detail['Id'] with open('/sys/fs/cgroup/memory/docker/' + container_id + '/memory.stat', 'r') as f: for line in f: m = re.search(r"total_rss\s+(\d+)", line) if m: print(m.group(1)) return print(0) def display_network(args): detail = c.inspect_container(args.container) if bool(detail["State"]["Running"]): ifconfig = c.execute(args.container, "ifconfig eth0") m = re.search(("RX" if args.direction == "in" else "TX") + r" bytes:(\d+)", str(ifconfig)) if m: print(m.group(1)) else: b = c.execute(args.container, "cat /sys/devices/virtual/net/eth0/statistics/"+("rx" if args.direction == "in" else "tx")+"_bytes") if re.match(r"\s*\d+\s*", b): print(b) else: print(0) else: print(0) def display_status(args): detail = c.inspect_container(args.container) state = detail["State"] if bool(state["Paused"]): print(1) # Paused elif bool(state["Running"]): print(0) # Running elif int(state["ExitCode"]) == 0: print(2) # Stopped else: print(3) # Crashed parser = argparse.ArgumentParser() parser.add_argument("container", help="Container name") subparsers = parser.add_subparsers(title="Counters", description="Available counters", dest="dataType") cpu_parser = subparsers.add_parser("cpu", help="Display CPU usage") cpu_parser.add_argument("type", choices=["system", "user", "all"]) cpu_parser.set_defaults(func=display_cpu) ip_parser = subparsers.add_parser("ip", help="Display IP Address") ip_parser.set_defaults(func=display_ip) memory_parser = subparsers.add_parser("memory", help="Display memory usage") memory_parser.set_defaults(func=display_memory) network_parser = subparsers.add_parser("network", help="Display network usage") network_parser.add_argument("direction", choices=["in", "out"]) network_parser.set_defaults(func=display_network) status_parser = subparsers.add_parser("status", help="Display the container status") status_parser.set_defaults(func=display_status) c = Client(**(kwargs_from_env())) args = parser.parse_args() args.func(args)