Zabbix监控Bind(DNS)服务

一、Bind配置

Bind是目前使用最广泛的DNS服务器软件,安装完Bind后,可以使用其自带的zone-statistics统计功能接口进行服务监控。

  1. 在Bind配置文件/etc/named.conf中,先在options段中关闭全局统计功能,只针对我们需要统计的zone进行统计。
    options {
        ...
        zone-statistics no;   //关闭全局统计功能
        ...
    }
    
  2. 打开Bind的统计接口,在options {} 段外加入下面配置,开启http统计接口http://127.0.0.1:8653
    options {
        ...
    }
    statistics-channels {
          inet 127.0.0.1 port 8653 allow { 127.0.0.1; };
    };
    
  3. 对需要监控的zone加入zone-statistics yes打开统计功能
    zone "example.com" IN {
        type slave;
        masters { 10.33.83.243; };
        file "/var/named/slaves/example.com.zone";
        zone-statistics yes;
    };
    

二、Zabbix监控脚本和配置

  1. Zabbix Agent增加配置 /etc/zabbix/zabbix_agentd.d/bind.conf
    UserParameter=bind.check,/usr/local/zabbix-ztc/bin/bind.py -c /etc/zabbix/zabbix_agentd.conf --update-items
    UserParameter=bind.discovery,/usr/local/zabbix-ztc/bin/bind.py -c /etc/zabbix/zabbix_agentd.conf --discovery
    
  2. 监控脚本 /usr/local/zabbix-ztc/bin/bind.py,使用python库protobix,方法参考Hadoop集群监控
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import re
    import sys
    
    import protobix
    import requests
    from lxml import etree
    
    
    class BIND(protobix.SampleProbe):
        __version__ = '1.0.0'
    
        def _parse_probe_args(self, parser):
            pass
            return parser
    
        def _init_probe(self):
            j = {
                'zones': {},
                'counter': {},
                'zonemaintenancecounter': {},
                'resolvercounter': {},
                'socketcounter': {},
                'incounter': {},
                'outcounter': {},
                'cache': {},
                'memory': {}
            }
            url = 'http://127.0.0.1:8653/'
            with requests.get(url, timeout=2) as r:
                if r.status_code == 200:
                    data = r.text
                else:
                    raise RuntimeError
            root = etree.fromstring(data.encode('utf8'))
            # get the statistics version
            if root.tag == 'isc':
                version = root.find('./bind/statistics').attrib['version']
            elif root.tag == 'statistics':
                version = root.attrib['version']
            else:
                raise ValueError
            # check the statistics version
            if version.startswith('2.'):
                for view in root.iterfind('./bind/statistics/views/view'):
                    if view.findtext('./name') in ('_default',):
                        for zone in view.iterfind('./zones/zone'):
                            if zone.find('./counters') is not None:
                                counters = {}
                                for counter in zone.iterfind('./counters/*'):
                                    counters[counter.tag] = counter.text
                                j['zones'][zone.findtext('./name')] = counters
                for stat in root.iterfind('./bind/statistics/server/nsstat'):
                    j['counter'][stat.findtext('./name')] = stat.findtext('./counter')
                for stat in root.iterfind('./bind/statistics/server/zonestat'):
                    j['zonemaintenancecounter'][stat.findtext('./name')] = stat.findtext('./counter')
                for view in root.iterfind('./bind/statistics/views/view'):
                    if view.findtext('./name') in ('_default',):
                        for stat in view.iterfind('./resstat'):
                            j['resolvercounter'][stat.findtext('./name')] = stat.findtext('./counter')
                for stat in root.iterfind('./bind/statistics/server/sockstat'):
                    j['socketcounter'][stat.findtext('./name')] = stat.findtext('./counter')
                for stat in root.iterfind('./bind/statistics/server/queries-in/rdtype'):
                    j['incounter'][stat.findtext('./name')] = stat.findtext('./counter')
                for stat in root.iterfind('./bind/statistics/views/view/rdtype'):
                    j['outcounter'][stat.findtext('./name')] = stat.findtext('./counter')
                # Memory
                for child in root.iterfind('./bind/statistics/memory/summary/*'):
                    j['memory'][child.tag] = child.text
                # Cache for local
                for child in root.iterfind('./bind/statistics/views/view/cache'):
                    if child.attrib['name'] == 'localhost_resolver':
                        for stat in child.iterfind('./rrset'):
                            j['cache'][stat.findtext('./name')] = stat.findtext('./counter')
            elif version.startswith('3.'):
                for child in root.iterfind('./server/counters'):
                    # V2 ./bind/statistics/server/nsstat
                    if child.attrib['type'] == 'nsstat':
                        for stat in child.iterfind('./counter'):
                            j['counter'][stat.attrib['name']] = stat.text
                    # V2 ./bind/statistics/server/sockstat
                    if child.attrib['type'] == 'sockstat':
                        for stat in child.iterfind('./counter'):
                            j['socketcounter'][stat.attrib['name']] = stat.text
                    # V2 ./bind/statistics/server/zonestat
                    if child.attrib['type'] == 'zonestat':
                        for stat in child.iterfind('./counter'):
                            j['zonemaintenancecounter'][stat.attrib['name']] = stat.text
                    # V2 ./bind/statistics/server/queries-in/rdtype
                    if child.attrib['type'] == 'qtype':
                        for stat in child.iterfind('./counter'):
                            j['incounter'][stat.attrib['name']] = stat.text
                # they are only for block _default
                for child in root.iterfind('./views/view/counters'):
                    # V2 ./bind/statistics/views/view/rdtype
                    if child.attrib['type'] == 'resqtype':
                        for stat in child.iterfind('./counter'):
                            j['outcounter'][stat.attrib['name']] = stat.text
                    # V2 ./bind/statistics/views/view => _default name only
                    if child.attrib['type'] == 'resstats':
                        for stat in child.iterfind('./counter'):
                            j['resolvercounter'][stat.attrib['name']] = stat.text
                    # V2: no (only in memory detail stats)
                    if child.attrib['type'] == 'cachestats':
                        for stat in child.iterfind('./counter'):
                            j['cache'][stat.attrib['name']] = stat.text
                # V2 has @name = localhost_resolver, interal, external
                for child in root.iterfind('./views/view/cache'):
                    if (child.attrib['name'] == '_default'):
                        for stat in child.iterfind('./rrset'):
                            j['cache'][stat.findtext('./name')] = stat.findtext('./counter')
                            # for sets stating with !, we replace that with an _ (! is not allowed in zabbix)
                            if re.match('^!', stat.findtext('./name')):
                                j['cache'][stat.findtext('./name').replace('!', '_')] = stat.findtext('./counter')
                # for all the Zone stats only
                for child in root.iterfind('./views/view'):
                    # only for default
                    if (child.attrib['name'] == '_default'):
                        # V2 ./bind/statistics/views/view -> ./zones/zone => _default name only
                        for zone in child.iterfind('./zones/zone'):
                            counters = {}
                            for stat in zone.iterfind('./counters'):
                                if stat.attrib['type'] == 'rcode' or stat.attrib['type'] == 'qtype':
                                    for counter in stat.iterfind('./counter'):
                                        counters[counter.attrib['name']] = counter.text
                            j['zones'][zone.attrib['name']] = counters
                # V2 ./bind/statistics/memory/summary/*
                for child in root.iterfind('./memory/summary/*'):
                    j['memory'][child.tag] = child.text
            else:
                raise ValueError
            self.j = j
    
        def _get_discovery(self):
            data = {}
            key = 'bind.discoverzones'
            data[key] = [{'{#ZONE}': zone} for zone in self.j['zones'].keys()]
            return {self.hostname: data}
    
        def _get_metrics(self):
            data = {}
            for k, v in self.j.items():
                if k == 'zones':
                    for kk, vv in v.items():
                        for kkk, vvv in vv.items():
                            data['bind.zonecounter[{0},{1}]'.format(kk, kkk)] = vvv
                else:
                    for kk, vv in v.items():
                        data['bind.{0}[{1}]'.format(k, kk)] = vv
            return {self.hostname: data}
    
    
    if __name__ == '__main__':
        ret = BIND().run()
        print(ret)
        sys.exit(ret)
    
  3. Zabbix(版本3.2)模板下载
    下载:zbx_bind_templates.zip

订阅
提醒
0 评论
在线反馈
查看全部评论