LoginSignup
23
20

More than 5 years have passed since last update.

Ansible dynamic inventory + Zabbix APIで監視対象を動的に構成管理

Last updated at Posted at 2014-12-16

Overview

普段Ansibleを使っているがinventory管理が思いのほか大変で、ホスト追加の度にinventoryファイルを編集とかしてた。
が、 dynamic inventory というものがあるのを最近知ったので使ってみる。
簡単にいうと、動的にAnsibleのinventoryホストを生成することが出来る機能で、一々マシンの追加の度にinventoryファイルを編集とかしなくていい。人間に優しい。
あと既にサーバ監視にZabbixを使っていたのでZabbixのホスト一覧からinventoryを生成し、Zabbix管理下のホストを構成管理ということもしてみる。

Requirements

  • Ansible (Tested on 1.8.1)
  • Zabbix (Tested on 2.0.8)
  • CentOS (Teted on 6.5)

Installation

dynamic inventoryを使うには-iオプションにansibleが認識可能なJSON形式の結果を吐く実行可能なスクリプトを渡してやればいい。
形式さえ合ってればいいのでシェルスクリプトでもrubyでも何でも好きな言語で書ける。

例えばローカルの/etc/hostsに存在するホスト名をinventoryとして使いたければ

inventory.sh
#!/bin/bash
HOSTS=$(cat /etc/hosts | grep -v ^# | awk '{print $2}')
HOSTS=$(echo "$HOSTS" | sed -e 's/^\(.*\)$/"\1"/g')
HOSTS=$(echo $HOSTS | sed -e 's/\s/,/g')
echo "{\"all\": {\"hosts\": [$HOSTS]}}"

のようなスクリプトを書いて渡してやるだけでいい。

ansibleで使うには

$ ansible -i inventory.sh all -m ping

のようにする。

さらに/etc/ansible/hostsにスクリプトを設置すればいちいち-iオプションを使う必要もなくなる。

$ cp inventory.sh /etc/ansible/hosts && chmod +x /etc/ansible/hosts

$ ansible all -m ping

web1 | success >> {
    "changed": false, 
    "ping": "pong"
}

web2 | success >> {
    "changed": false, 
    "ping": "pong"
}

...(中略)...

素晴らしい。

JSONの形式は以下のような形式ならなんでもいい。

{
    "databases"   : {
        "hosts"   : [ "host1.example.com", "host2.example.com" ],
        "vars"    : {
            "a"   : true
        }
    },
    "webservers"  : [ "host2.example.com", "host3.example.com" ],
    "atlanta"     : {
        "hosts"   : [ "host1.example.com", "host4.example.com", "host5.example.com" ],
        "vars"    : {
            "b"   : false
        },
        "children": [ "marietta", "5points" ]
    },
    "marietta"    : [ "host6.example.com" ],
    "5points"     : [ "host7.example.com" ],
    "_meta" : {
       "hostvars" : {
          "host1.example.com"     : { 
             "asdf" : 1234,
             "ansible_ssh_host": "host1.example.com" 
           },
          "host2.example.com"     : { 
             "asdf" : 5678,
             "ansible_ssh_host": "host2.example.com" 
           }
       }
    }
}

_meta内にはhostvarsを入れられるのでhostごとに異なる情報があればここに入れておく。(ansible_ssh_port, ansible_ssh_user, ansible_ssh_host等)

公式ドキュメント: Developing Dynamic Inventory Sources — Ansible Documentation

Zabbix連携

Ansibleが既に公式で配布しているZabbix用のdynamic inventoryスクリプトがあるのでこれを使います。

使ってみたがそのままでは動作しなかったのと、デフォルトではホストグループ単位でのグループ化しか出来なかったので少し修正して、
Zabbixのテンプレート単位でのinventory化も出来るようにします。
修正後のファイルはGistに公開してあります

@@ -71,19 +71,41 @@ class ZabbixInventory(object):
             'hosts': []
         }

+    def templatestub(self):
+        return {
+            'hosts': []
+        }
+
     def get_host(self, api, name):
         data = {}
         return data

     def get_list(self, api):
-        hostsData = api.host.get({'output': 'extend', 'selectGroups': 'extend'})
-
+        hostsData = api.host.get(
+          {
+            'output': 'extend', 
+            'selectGroups': 'extend', 
+            'selectInterfaces': 'extend',
+            'selectInventory': 'extend'
+          }
+        )
+        templateData = api.template.get(
+          {
+            'output': 'extend', 
+            'selectGroups': 'extend', 
+            'selectHosts': 'extend',
+          }
+        ) 
         data = {}
         data[self.defaultgroup] = self.hoststub()
+        data['_meta'] = {}
+        data['_meta']['hostvars'] = {}

         for host in hostsData:
             hostname = host['name']
             data[self.defaultgroup]['hosts'].append(hostname)
+            data['_meta']['hostvars'][hostname] = host
+            data['_meta']['hostvars'][hostname]['ansible_ssh_host'] = hostname

             for group in host['groups']:
                 groupname = group['name']
@@ -93,6 +115,18 @@ class ZabbixInventory(object):

                 data[groupname]['hosts'].append(hostname)

+        for template in templateData:
+            templatename = template['name']
+            
+            for host in template['hosts']:
+                hostname = host['name']
+
+                if not templatename in data:
+                    data[templatename] = self.templatestub()
+

  • 修正したものをansibleのconfディレクトリにコピー
cp zabbix.py /etc/ansible/hosts
chmod +x /etc/ansible/hosts
cp zabbix.ini /etc/ansible/
  • zabbixのpythonクライアントをインストール
pip install zabbix-api
  • 確認
# ホストグループベースのansible実行
$ ansible webservers -m ping

web1 | success >> {
    "changed": false, 
    "ping": "pong"
}

web2 | success >> {
    "changed": false, 
    "ping": "pong"
}

...(中略)...

# テンプレートベースのansible実行
$ ansible "Template OS Linux" -m ping

web1 | success >> {
    "changed": false, 
    "ping": "pong"
}

web2 | success >> {
    "changed": false, 
    "ping": "pong"
}

...(中略)...

これでZabbix上のホストグループベースでのinventoryの生成と、テンプレートベースでのinventoryの生成が出来ました。
テンプレートベースでの構成管理が出来るので、テンプレートと密接に関わるUserParameterやLow Level Discoveryの構成管理は楽になると思います。

またスクリプトのZabbix APIのhost.getを叩いてる箇所に

'selectInventory': 'extend'

をパラメータに追加してホストインベントリも取得しているので
Zabbixでラック管理やシリアル管理、タグ管理等の資産管理をしている場合は
hostvarsを見て特定のラックのみ更新、特定のタグのマシンのみ更新とか出来ます。
他にもZabbix API次第でinventoryの生成方法を色々工夫出来ると思います。

あとはZabbixのディスカバリチェックで監視対象のホストをホストグループに追加したり
テンプレートにリンクさせたりすれば動的にinventoryを増やしたり減らしたり出来ます。

dynamic inventory用のスクリプト自体は公式が配布しているものを少し修正すれば
十分実用的になるので各々の環境に合わせたdynamic inventoryプラグインを作るのがよいかと思います。

23
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
20