この記事の概要
Zabbixの設定もgitで管理したい・・・
その想いから Zabbicook という Zabbixの設定をファイルで記述するためのツール を作りました。
単独での利用例と、Ansibleと一緒に利用する例を紹介しています。
ユーザーの設定のみ、とか1テンプレートのみに使う、といったこともできるのですぐに導入できます!
Zabbix As Code
皆さんはZabbixの設定をどのように管理していますか?
必要になったらGUIでぽちぽち設定するというのが普通だと思いますが、いくつか運用で困ることもあります。
- 設定の変更履歴が分からない(誰がいつ変えたのか)
- 設定の変更をレビューする方法
- 開発環境ごとにzabbixのインスタンスを立てていると、環境ごとに似たような設定をしないといけない
Zabbixの設定もファイル化してgitで管理したい、設定ファイルで一括設定したい、そう思ったことはないでしょうか。
Zabbixには Export / Import の機能が用意されているので、エクスポートしたXMLやJSONで管理することができます。
しかしこの方法は少し難があります。例えばテンプレートアイテムにログファイルを1つ設定した場合、管理したいのは設定したアイテムのkeyや、intervalなど、いくつかの設定だけなのに、エクスポートされたファイルのアイテムの項目には アイテムのすべてのプロパティ の情報が含まれており、関心のない情報まで扱わなければなりません。また、ユーザーやアクションの設定は今の所まだ対応していないようです。
エクスポート・インポート用のファイルは、一括で設定を移行するのにはとても便利なものですが、レビューや履歴管理には今ひとつむかなそうです。
そこで、もう少しスマートな Zabbix as Code を目指して、 Zabbicook というツールを作りました。
Zabbicookとは
Zabbixの設定をコード化(設定ファイル化)して管理するためのツールです。設定ファイルの内容に従って Zabbix API を使い、Zabbixの設定変更を行います。以下のような特徴があります。
- Scala製のコマンドラインツール
- HOCONフォーマットによる設定(HOCONフォーマットについては後述します。)
- ある程度の冪等性
- ユーザーやアクションの設定も可能
- 一部の設定の管理だけでも利用可能
以下の条件で利用できます。
- 実行環境に Java 8 以上が必要です
- Zabbix 3.0 以上に対応しています。〜2.x では動作確認していません。
Zabbicookを試してみる
インストール
Githubの最新リリースのzip をダウンロードし、好きなところに解凍すれば、準備は完了です。
解凍されたファイル内にある zabbicook(Mac/Linux) または zabbicook.cmd(Windows) をコマンドラインから叩いて実行します。
zabbicook -v
Zabbixサーバーを用意する
Zabbicookを試すにはZabbixサーバーが必要です。
バージョン3.0以上の適当なZabbixサーバーを用意する必要があります。(すでに用意できている場合はこの手順は飛ばしてください。)
[Dockerized Zabbix] (https://www.zabbix.org/wiki/Dockerized_Zabbix) と称してdockerイメージが提供されており、簡単にdockerインスタンスが立てられるので、今回はこれを利用してみます。
docker run \
    -d \
    --name zabbix-db \
    --env="MARIADB_USER=zabbix" \
    --env="MARIADB_PASS=my_password" \
    monitoringartist/zabbix-db-mariadb
docker run \
    -d \
    --name zabbix \
    -p 8080:80 \
    -p 10051:10051 \
    -v /etc/localtime:/etc/localtime:ro \
    --link zabbix-db:zabbix.db \
    --env="ZS_DBHost=zabbix.db" \
    --env="ZS_DBUser=zabbix" \
    --env="ZS_DBPassword=my_password" \
    --env="XXL_zapix=true" \
    --env="XXL_grapher=true" \
    monitoringartist/zabbix-xxl:latest
ここでは 8080 ポートで動かしています。http://localhost:8080/ をブラウザで開くとZabbixが起動しているのが確認できます。
ユーザーを追加してみる
最初にユーザーを追加する設定を書いてみます。
エディターで以下のような内容で、zabbicook.confという設定ファイルを作成します。ファイル名は特に決まりはありません。
場所もどこでも良いのですが、ここではZabbicookと同じディレクトリに作成することにします。
users: [
  {
    user {
      alias: Alice
      type: admin
    }
    groups: [ "Zabbix administrators" ]
    password: pass1234
    // 'password' を暫定的なパスワードとして利用するかどうか
    // initialPassword=false の場合は、この設定ファイルで設定を行うたびにAliceのパスワードを'pass1234'に設定しようとします
    initialPassword: false
  }
  {
    user {
      alias: Bob
      type: user
    }
    groups: [ Guests ]
    password: bob
    // 'password' を暫定的なパスワードとして利用するかどうか
    // initialPassword=true の場合は、Bobユーザーが新たに作成される場合にだけパスワードを設定します
    // 初期パスワードを設定しておいて、Bob自身にWebからログインしてパスワードを変更してもらう、といった運用での利用を想定しています。
    initialPassword: true
  }
]
$ zabbicook -f ./zabbicook.conf -i http://localhost:8080/ -u Admin -p zabbix
presenting 2 users ...
User entities modified(created=2)
Succeed: Total changes = 2
http://localhost:8080/users.php をブラウザで開くと、AliceとBobがユーザーに追加されていることがわかります。
users という名前の Object Array を定義すると、それに従いユーザーを作成します。user Object には以下のようなプロパティがあります
- 
user: 名前を示すaliasや、ユーザータイプを指定するtypeなどのユーザー属性を含むObjectです。全てのプロパティは こちらを参照してください。
- 
groups: ユーザーグループ名を指定します。独自のユーザーグループを作成するには、別途userGroupsを定義してください。
- 
password: ユーザーのパスワードです。
- 
initialPassword:passwordを初期パスワードとするかどうかのフラグです。
Zabbicookではこのように、各設定を決められたスキーマのObjectとして、設定ファイルに記述していき、zabbicookコマンドに渡すことで設定の適用を行います。
zabbicookコマンドに渡す各オプションの説明は以下の通りです。
- 
-f: 設定ファイルのパスを指定します。
- 
-i: zabbix apiのエンドポイントURLを指定します。
- 
-u: zabbix設定を行うZabbixの管理者ユーザーを指定します。
- 
-p:-uで指定したユーザーのパスワードを指定します。Admin:zabbixはZabbixの初期状態で存在する管理者ユーザー名とパスワードです。
テンプレートを追加してみる
次にテンプレートを追加してみます。
テンプレートの各プロパティについては こちら を参照してください。
templates: [
  {
    template: { name: "My Template"}
    groups: [ Templates ]
    items: [
      {
        name: "Check sum of /var/log/maillog"
        key: "vfs.file.cksum[/var/log/maillog]"
        type: ZabbixAgent
        valueType: unsigned
        interval: 60
        history: 30
      }
    ]
  }
]
$ zabbicook -f ./templates.conf -i http://localhost:8080/ -u Admin -p zabbix
presenting 1 templates ...
Template entities modified(created=1)
Item entities modified(created=1)
Succeed: Total changes = 2
ブラウザで http://localhost:8080/templates.php にアクセスすると、My Template という名前で、アイテムが1つだけ登録されているテンプレートが作成されているかと思います。
冪等性に関する注意点
たった今実行したテンプレート設定を、もう一度同じコマンドで実行してみます。
$ zabbicook -f ./templates.conf -i http://localhost:8080/ -u Admin -p zabbix
presenting 1 templates ...
Succeed: Total changes = 0
changes = 0となり、今度は何も変更を行わなかったことを示しています。
Zabbicookは設定ファイルに基づいて、ある程度の冪等性を保ちます。
ただし削除される条件については注意が必要です。
Zabbicookでは、テンプレートに属するアイテムやトリガーの削除については冪等性がありますが、テンプレートそのものの削除には冪等性がありません。
例えば、テンプレートに属するアイテムをZabbicookの設定ファイルから1つ消して実行した場合、そのアイテムは消えます。
しかし、1つのテンプレートを丸々設定ファイルから消した場合、Zabbicookはそのテンプレートを消すことはしません(何も変更しません)。
テンプレート以外でも、users、userGroups、actions 等にも同じことが言えます。
また、今の所Zabbicookはホストに直接アイテムやトリガーなどを設定することはできません。
アイテム、トリガー、グラフなどはテンプレートごとに冪等性を持っており、ホストはそれらのテンプレートをリンクして利用することを前提としています。
HOCONって何?
[HOCON (Human-Optimized Config Object Notation)] (https://github.com/typesafehub/config/blob/master/HOCON.md)
Zabbicookでは設定ファイルをHOCONというフォーマットで記述します。HOCONはあまりメジャーではなさそうなので簡単に触れておきます。
「人類が編集しやすい(?)」をモットーに、JSONのスーパーセットとして作られた設定ファイル用のフォーマットです。
「新しいフォーマットなんて覚えられない!」という方は、JSONをそのまま使うこともできます。
HOCONを採用した理由としては、読みやすいことやZabbicook自体の実装言語(Scala)で利用しやすかった、ということもありますが、それ以外に以下の二点が大きな理由として挙げられます。
1. 変数のように定義した値を利用できる
同じようなアイテムをたくさん設定したい場合に便利です。たとえば特定のSNMPコミュニティから複数の値を登録したい場合、共通の設定を一つのObjectで定義しておき、使い回すことができます。
// SNMP共通の設定
SNMPItemBase {
  type: SNMPv1agent
  valueType: float
  port: 8161
  SNMPCommunity: test_community
  interval: 30
  history: 30
  units: ""
}
templates: [
  {
     template: { name: "Test template" }
     groups: [ "Templates" ]
     items: [
       ${SNMPItemBase} {
         name: SNMPItem1
         key: item1
         OID: "1.3.6.1.4.1.99999.1"
       }
       ${SNMPItemBase} {
         name: SNMPItem2
         key: item2
         OID: "1.3.6.1.4.1.99999.2"
       }
       // 〜 以下略 〜
     ]
  }
]
2. includeで簡単にファイルを分けられる
設定項目が増えてくると1つのファイルで管理するのは苦しくなりますが、include "templates.conf" と書くと別のHOCONファイルをインクルードできるため、簡単にファイルを分割して管理することができます。
Zabbcookの設定を書いているとすぐに設定ファイルが肥大化したり、冗長な記述が多くなりがちなので、HOCONのこういった機能は非常に助かります。
HOCONの詳細な仕様は 冒頭のリンク で確認するとよいでしょう。
設定できる項目
Zabbicookで設定できる全ての項目はこちらを参照してください。
また、コマンドラインから--docオプションで同じ情報を表示することもできます。
$ zabbicook --doc
そのままだと出力が長すぎるので、-rでパスを、-Lでツリーの深さを指定することができます。
$ zabbicook --doc -r templates.items -L 1
現在Zabbicookで設定できる項目はわずかです。開発者が私しかいないため、自分が必要なものを随時追加していく感じで進めていますが、Issueを立てれば対応するかもしれません
Ansibleで利用する
Zabbicookは独立したコマンドラインツールであり、30億のデバイスで走るJavaさえあれば動かすことができるので、AnsibleやChefなどから利用したり、docker buildの際に走らせるといったこともできます。
私は主にAnsibleから利用しているので、ここではAnsibleで利用する例を紹介します。
サンプルPlaybook
サンプルは以下に置いています。
https://github.com/rerorero/zabbicook-ansible-example
# ansible インストール
pip install ansible
git clone git@github.com:rerorero/zabbicook-ansible-example.git
cd zabbicook-ansible-example
# 今までの手順で localhost:8080 でzabbixサーバーが動いていればそのままプレイブックを流せます。
# もし動いていなければ https://github.com/rerorero/zabbicook-ansible-example/blob/master/README.md を参考にしてください。
ansible-playbook playbook.yml
以下簡単に補足します。
管理者ユーザーのパスワード
Ansibleから利用する際に若干面倒なのが、Zabbicookを実行する管理者ユーザーのパスワードの管理です。
ユーザーのパスワードは、Zabbicook設定ファイルでは users で設定できますが、Zabbicookを実行するためのAdministratorユーザーは、設定ファイルに記述できません。
初期設定のユーザーとパスワード(Admin/zabbix)を使うか、あらかじめZabbix GUIで設定しておく必要があります。しかし商用環境でデフォルトのパスワードを利用し続けるわけにはいきませんし、GUIで設定するのも、せっかくansibleを利用しているのに手動で作業しないといけないというのは残念な感じです。
そこでZabbicookには、コマンドラインからAdminユーザーのパスワードを変更する機能を用意しています。
zabbicook --change-pass -i http://localhost:8080/ -u Admin -p zabbix --new-pass rDLz=a7w
- 
-u: パスワードを変更したいユーザー名を指定します。
- 
-p: 変更前のパスワードを指定します。
- 
--new-pass: 変更後のパスワードを指定します
パスワードがすでに変更済みの場合も正常終了します。
サンプルPlaybookでは このあたり が該当部分です。
パスワードは vault などで管理するのがよいでしょう。
Zabbicookの結果を取得する
もうひとつ連携で面倒なのが、結果の出力です。
標準出力をawkでいじったりするのは面倒なので、Zabbicookでは--jsonオプションで結果をJSONフォーマットで出力できるようにしました。
$ zabbicook -f ./zabbicook.conf -i http://localhost:8080/ -u Admin -p zabbix --json
{
  "result" : "success",
  "report" : {
    "created" : 3,
    "updated" : 0,
    "deleted" : 0,
    "total" : 3,
    "messages" : [ "Template entities modified(created=1)", "Item entities modified(created=2)" ]
  }
}
$ zabbicook -f ./zabbicook.conf -i http://localhost:8080/ -u Admin -p zabbix --json
{
  "result" : "fail",
  "error" : "./zabbicook.conf: 10: : unbalanced close brace '}' with no open brace (if you intended '}' to be part of a key or string value, try enclosing the key or value in double quotes)"
}
Ansible(jinja2)にはJSONフィルター(from_json)が用意されているので、 このような感じで 構造化して扱うことができます。
テンプレートエンジンとの組み合わせ
あえて言うことでも無いですが・・・テンプレートエンジン(Ansibleの場合はjinja2)とHOCONとを組み合わせることで、さらに記述の表現が増すのでオススメです。
ホストをinventoryで管理していれば、hostsの設定もinventoryを元に設定できます。
サンプルコードでは ユーザーの設定 を group_vars などで管理できるような形にしています。
最後に
Zabbicookは全ての設定に利用せずとも、hostsやusersの管理だけに利用するといったことができますので、もし興味があれば使ってみてください。
まだ開発を始めたばかりで、機能があまり豊富ではなかったり、要素の削除についてはイマイチだったりしますが、今後もマイペースに更新は続けていこうと思います。