Elasticsearch のセットアップ

Zabbix は、リレーショナルデータベースの代わりに Elasticsearch にヒストリデータを保存できます。

このガイドでは、Elasticsearch のサポート対象バージョンのセットアップについて説明します。 Elasticsearch のバージョンがサポート対象の最小バージョンより古い場合、Zabbix サーバーは起動しません。 サポート対象の最大バージョンより新しい場合、AllowUnsupportedDBVersions パラメータを 1 に設定した場合にのみ、Zabbix サーバーが起動します。

Elasticsearch には、次の値の種類を保存できます。

アイテムの値の種類 データベーステーブル Elasticsearch の種類
数値(符号なし) history_uint uint
数値(浮動小数点) history dbl
文字 history_str str
ログ history_log log
テキスト history_text text
バイナリ history_bin Zabbix ではサポートされていません
JSON history_json json

重要な注意事項

  • Elasticsearch には libcurl が必要です。 詳細については、要件を参照してください。
  • ハウスキーパーは、Elasticsearch からデータを削除しません。 データを保持する期間を制御するには、Index Lifecycle Managementを参照してください。
  • Zabbix は、Elasticsearch 内のトレンドを計算または保存しません。 古いデータを保持するには、履歴の保存期間を延長することを検討してください。
  • Elasticsearch を使用する場合、データベースから値を取得する範囲クエリは、データの保存期間のタイムスタンプによって制限されます。
  • Elasticsearch は Zabbix プロキシではサポートされていません。
  • Elasticsearch 8.0 以降では、セキュリティ機能がデフォルトで有効になっています。Elasticsearch では認証が必要であり、HTTP API に HTTPS を使用します。また、自動生成された CA によって署名された証明書を使用します。 このページの例では、認証なしの http://localhost:9200 を使用しています。 セキュリティが有効な場合は、https:// URL を使用し、リクエストに CA 証明書と認証情報を渡してください(例: sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic https://localhost:9200。CA 証明書ファイルは root と elasticsearch グループのみが読み取れます)。 Zabbix サーバーと Zabbix Webインターフェースをこのようなクラスターに接続する方法については、セキュリティ保護されたクラスターへの接続を参照してください。

Elasticsearch がまだインストールされていない場合は、続行する前に公式のインストールガイドを参照してください。

Elasticsearchの設定

履歴データをElasticsearchに保存するには、以下の手順が必要です。

  • 保存したい値の型ごとにインデックスを作成します。これはElasticsearchがデータを保存する場所であり、リレーショナルデータベースのテーブルに相当します。
  • 各インデックスにマッピングを定義します。これはデータの構造を定義し、テーブルスキーマに相当します。
  • 保存前に値を処理するためのインジェストパイプラインを設定します(JSON値や日付ベースのインデックスには必須です)。

Elasticsearchは、値の型ごとに単一のインデックスにデータを保存することも、複数の日付ベースのインデックスに分散して保存することもできます。 両方のアプローチについて以下で説明します。

1つのインデックスに履歴を保存する

この方法では、指定した値の種類のすべての履歴データが、1つのインデックス(例: uint または text)に書き込まれます。

Numeric (unsigned) 値の種類のインデックスを作成するには、次のリクエスト(URLに /uint を指定)をElasticsearchインスタンスに送信します。

curl -X PUT \
 http://localhost:9200/uint \
 -H 'content-type:application/json' \
 -d '{
   "settings": {
      "index": {
         "number_of_replicas": 1,
         "number_of_shards": 5
      }
   },
   "mappings": {
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "format": "epoch_second", "type": "date" },
         "value": { "type": "long" }
      }
   }
}'

Elasticsearchは、インデックスが作成されたことを示す確認メッセージを返します。

{"acknowledged": true, "shards_acknowledged": true, "index": "uint"}

Elasticsearchに保存する各値の種類、つまりZabbixサーバーの設定の value_types オプションに記載されている各種類について、同様のリクエストを送信する必要があります。

すべての値の種類のマッピングは、Zabbixソースリポジトリで確認できます。

例えば、Text 値の種類のインデックスを作成するには、次のようにします。

curl -X PUT \
 http://localhost:9200/text \
 -H 'content-type:application/json' \
 -d '{
   "settings": {
      "index": {
         "number_of_replicas": 1,
         "number_of_shards": 5
      }
   },
   "mappings": {
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "format": "epoch_second", "type": "date" },
         "value": {
            "fields": {
               "analyzed": { "index": true, "type": "text", "analyzer": "standard" }
            },
            "index": false,
            "type": "text"
         }
      }
   }
}'
JSON値タイプ

他の値タイプとは異なり、JSON値は保存前に追加の処理が必要です。 JSON値タイプのインデックスでは、各値を次の2つのフィールドのいずれかに保存します。

  • value_parsed—JSONオブジェクト。キーと値で検索できるよう、flattenedフィールドとして保存されます。
  • value_raw—その他すべてのJSON値(配列、文字列、数値、ブール値、null)。文字列として保存されます。

Ingestパイプラインは各値をJSONとして解析し、正しいフィールドに保存します。 有効なJSONではない値はElasticsearchに送信されません。これらの値を受け取るアイテムはサポート対象外になるためです。

まず、Ingestパイプラインを作成します。

curl -X PUT \
 http://localhost:9200/_ingest/pipeline/json \
 -H 'content-type:application/json' \
 -d '{
   "processors": [
      {
         "json": {
            "field": "value",
            "target_field": "value_parsed",
            "ignore_failure": true
         }
      },
      {
         "script": {
            "source": "if (ctx.value_parsed == null || !(ctx.value_parsed instanceof Map)) { ctx.value_raw = ctx.value; ctx.remove(\"value_parsed\"); }"
         }
      }
   ]
}'

Elasticsearchは、Ingestパイプラインが作成されたことを示す確認メッセージを返します。

{"acknowledged": true}

次に、以下のリクエストをElasticsearchインスタンスに送信して、JSON値タイプ用のインデックスを作成します(URLに/jsonを指定します)。 default_pipeline設定により、Elasticsearchはこのインデックスに書き込まれるすべての値をjson Ingestパイプラインで処理します。 この設定は必須です。Zabbixサーバーは、履歴を単一のインデックスに保存する際にIngestパイプラインを指定しないためです。

curl -X PUT \
 http://localhost:9200/json \
 -H 'content-type:application/json' \
 -d '{
   "settings": {
      "index": {
         "number_of_replicas": 1,
         "number_of_shards": 5,
         "default_pipeline": "json"
      }
   },
   "mappings": {
      "dynamic": false,
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "type": "date", "format": "epoch_second" },
         "ns": { "type": "long" },
         "value_parsed": { "type": "flattened", "ignore_above": 8191 },
         "value_raw": { "type": "keyword", "ignore_above": 8191 }
      }
   }
}'

Elasticsearchでは、32766バイトを超えるkeywordおよびflattened値にインデックスを付けることはできません。 "ignore_above": 8191を指定すると、8191文字を超える文字列にはインデックスが付けられず(検索もできません)、ただし完全な状態で保存され、Zabbixに返されます。 この制限を指定しない場合、Elasticsearchはこのような値を拒否し、値は失われます。

日付ベースのインデックスに履歴を保存する

すべての履歴データを単一のインデックス(例: uint)に書き込む代わりに、Elasticsearch はこのデータを複数の日付ベースのインデックス(例: uint-2026-01-01、uint-2026-01-02)に分散できます。
これにより、時間の経過に伴うデータ量と保持期間をより簡単に管理できます。

これを有効にするには、次の操作が必要です。

  • 保存する各値タイプごとに index template を作成します。これにより、Elasticsearch が新しい日付ベースのインデックスを自動作成する際に適用するマッピングが指定されます。
  • 各値タイプごとに ingest pipeline を作成します。これは、受信した各値を処理し、正しい日付ベースのインデックスへ振り分けます。
インデックステンプレート

text インデックスのテンプレートを作成するには、次の詳細を指定してリクエストを送信します。

  • ElasticsearchインスタンスのURLで _index_template/text_template を使用します。
  • 日付ベースのインデックス名に一致させるため、"index_patterns" フィールドで "text-*" を使用します。
  • "template" フィールドで、インデックス設定と text 値タイプのマッピングを指定します(マッピングについては、Zabbixソースリポジトリを参照してください)。
curl -X PUT \
 http://localhost:9200/_index_template/text_template \
 -H 'content-type:application/json' \
 -d '{
   "index_patterns": [ "text-*" ],
   "template": {
      "settings": {
         "index": {
            "number_of_replicas": 1,
            "number_of_shards": 5
         }
      },
      "mappings": {
         "properties": {
            "itemid": { "type": "long" },
            "clock": { "format": "epoch_second", "type": "date" },
            "value": {
               "fields": {
                  "analyzed": { "index": true, "type": "text", "analyzer": "standard" }
               },
               "index": false,
               "type": "text"
            }
         }
      }
   }
}'

保存する各値タイプについて、テンプレート名、インデックスパターン、マッピングを適宜変更してテンプレートを作成します。

たとえば、json インデックスのテンプレートは次のようになります(value_parsed フィールドと value_raw フィールドの詳細については、JSON値タイプを参照してください)。

curl -X PUT \
 http://localhost:9200/_index_template/json_template \
 -H 'content-type:application/json' \
 -d '{
   "index_patterns": [ "json-*" ],
   "template": {
      "settings": {
         "number_of_replicas": 1
      },
      "mappings": {
         "dynamic": false,
         "properties": {
            "itemid": { "type": "long" },
            "clock": { "type": "date", "format": "epoch_second" },
            "ns": { "type": "long" },
            "value_parsed": { "type": "flattened", "ignore_above": 8191 },
            "value_raw": { "type": "keyword", "ignore_above": 8191 }
         }
      }
   }
}'

上記のように、コンポーザブルインデックステンプレート(_index_template)を使用してください。 従来のインデックステンプレート(_template)は非推奨です。また、Elasticsearchは、組み込みテンプレートとインデックスパターンが重複する従来のテンプレートを拒否します(たとえば、log インデックスに対して log* パターンを使用する従来のテンプレート)。

Ingestパイプライン

text インデックス用のIngestパイプラインを作成するには、次の手順を実行します。

  • ElasticsearchインスタンスのURLで _ingest/pipeline/text-pipeline を使用します。
  • 各値をタイムスタンプに基づく正しい日付ベースのインデックスにルーティングするため、date_index_name プロセッサーを含めます。
curl -X PUT \
 http://localhost:9200/_ingest/pipeline/text-pipeline \
 -H 'content-type:application/json' \
 -d '{
   "description": "daily text index naming",
   "processors": [
      {
         "date_index_name": {
            "field": "clock",
            "date_formats": ["UNIX"],
            "index_name_prefix": "text-",
            "date_rounding": "d"
         }
      }
   ]
}'

保存する値のタイプごとにパイプラインを作成し、パイプライン名、説明、および "index_name_prefix" の値を適宜変更します。
パイプライン名は、インデックス名と -pipeline サフィックスで構成する必要があります(例: uint-pipeline)。これは、ZabbixサーバーがElasticsearchに値を送信するときにこの名前を使用するためです。

json インデックスの場合、正しいインデックスにルーティングする前にJSON値を解析する必要があるため、パイプラインには次の処理も必要です。

curl -X PUT \
 http://localhost:9200/_ingest/pipeline/json-pipeline \
 -H 'content-type:application/json' \
 -d '{
   "description": "daily json index naming",
   "processors": [
      {
         "json": {
            "field": "value",
            "target_field": "value_parsed",
            "ignore_failure": true
         }
      },
      {
         "script": {
            "source": "if (ctx.value_parsed == null || !(ctx.value_parsed instanceof Map)) { ctx.value_raw = ctx.value; ctx.remove(\"value_parsed\"); }"
         }
      },
      {
         "date_index_name": {
            "field": "clock",
            "date_formats": [ "UNIX" ],
            "index_name_prefix": "json-",
            "date_rounding": "d"
         }
      }
   ]
}'

Zabbixサーバーの設定

Zabbixサーバーの設定ファイル(zabbix_server.conf)で、HistoryProviderパラメータを設定します。

例えば、Character、Log、Text、JSONタイプの値をElasticsearchに保存し、Numeric値はデータベースに保持する場合は、次のように設定します。

HistoryProvider=elasticsearch;value_types="str,log,text,json",url=http://localhost:9200

日付ベースのインデックスを使用する場合は、パラメータにdate_index=1を追加します。

HistoryProvider=elasticsearch;value_types="str,log,text,json",url=http://localhost:9200,date_index=1

Elasticsearchのセキュリティ機能が有効になっている場合は、認証情報を含むhttps:// URLを指定します(セキュリティ保護されたクラスターへの接続を参照)。

変更後、Zabbixサーバーを再起動します。

systemctl restart zabbix-server

Zabbix Webインターフェースの設定

Zabbix の Webインターフェース設定ファイル(zabbix.conf.php)で、$HISTORY_PROVIDERS 変数をサーバーの設定に合わせて設定します。

$HISTORY_PROVIDERS[] = [
  'types' => ['str','log','text','json'],
  'provider' => 'elasticsearch',
  'url' => 'http://localhost:9200'
];

Elasticsearch のセキュリティ機能が有効になっている場合は、サーバーの設定と同じ認証情報を含む https:// URL を指定します(セキュリティ保護されたクラスターへの接続を参照)。

セキュリティ保護されたクラスターへの接続

Elasticsearch のセキュリティ機能が有効になっている場合(Elasticsearch 8.0 以降のデフォルト)、Zabbix サーバーと Zabbix の Webインターフェースは、Elasticsearch HTTP レイヤーの CA 証明書を信頼し、ユーザー名とパスワードで認証する必要があります。

  1. Zabbix 用のロールとユーザーを作成します。 以下のロールでは、Zabbix が Elasticsearch のバージョン(monitor クラスター権限)を取得し、インデックスを作成し、履歴データの書き込みと読み取りを行い、アイテムの履歴が消去されたときに履歴データを削除できます。
sudo curl -X PUT \
 --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic \
 https://localhost:9200/_security/role/zabbix_history \
 -H 'content-type:application/json' \
 -d '{
   "cluster": [ "monitor" ],
   "indices": [
      {
         "names": [ "uint", "uint-*", "dbl", "dbl-*", "str", "str-*", "log", "log-*", "text", "text-*", "json", "json-*" ],
         "privileges": [ "create_index", "index", "read", "delete" ]
      }
   ]
}'
sudo curl -X PUT \
 --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic \
 https://localhost:9200/_security/user/zabbix \
 -H 'content-type:application/json' \
 -d '{
   "password": "<password>",
   "roles": [ "zabbix_history" ]
}'
  1. Zabbix サーバーおよび Zabbix の Webインターフェースのホスト上にあるオペレーティングシステムの信頼済み証明書に、Elasticsearch の CA 証明書を追加します。 Zabbix が Elasticsearch とは異なるホストで実行されている場合は、まず CA 証明書(/etc/elasticsearch/certs/http_ca.crt)をそのホストにコピーします。 たとえば、Debian/Ubuntu では次のように実行します。
sudo cp /etc/elasticsearch/certs/http_ca.crt /usr/local/share/ca-certificates/elasticsearch-http-ca.crt
sudo update-ca-certificates

URL 内のホスト名は、Elasticsearch HTTP 証明書と一致している必要があります。 自動生成された証明書は、localhost、ホスト名、および Elasticsearch ホストの IP アドレスに対して有効です。

  1. Zabbix サーバーの設定ファイルと Webインターフェースの設定ファイルの両方で、URL に認証情報を指定します。 パスワードに特殊文字が含まれている場合は、パーセントエンコードしてください(たとえば、@ は %40、: は %3A、, は %2C)。
HistoryProvider=elasticsearch;value_types="str,log,text,json",url=https://zabbix:<password>@localhost:9200
$HISTORY_PROVIDERS[] = [
  'types' => ['str','log','text','json'],
  'provider' => 'elasticsearch',
  'url' => 'https://zabbix:<password>@localhost:9200'
];
  1. Zabbix サーバーと PHP-FPM を再起動します(PHP が Web サーバーモジュールとして実行されている場合は、Web サーバーを再起動します)。

トラブルシューティング

Elasticsearch のセットアップに関する障害のトラブルシューティングには、次の手順が役立つ場合があります。

  1. Elasticsearch または Zabbix サーバーのログでエラーを確認します。 たとえば、次の Zabbix サーバーのログメッセージは、セキュリティ保護されたクラスターへの接続に問題があることを示しています(セキュリティ保護されたクラスターへの接続を参照)。
  • cannot query Elasticsearch: SSL certificate problem: self-signed certificate in certificate chain—Elasticsearch CA 証明書が信頼されていません。
  • cannot query Elasticsearch, HTTP error message: The requested URL returned error: 401—認証情報がないか、正しくありません。
  • cannot query Elasticsearch, HTTP error message: The requested URL returned error: 403—ユーザーに必要な権限がありません。

Zabbix Webインターフェースにも同様のエラーが表示されます(例: Elasticsearch error: missing authentication credentials for REST request)。

  1. 遅いクエリを特定するには、Zabbix サーバーの設定パラメータ LogSlowQueries を設定します。 Elasticsearch から履歴を読み取る処理が指定した時間を超えると、Zabbix サーバーは slow query: <N> sec, "<query>" をログに記録します。 Elasticsearch の応答を待機している間、Zabbix サーバーは指定した時間が経過するたびに、または LogSlowQueries が 0 に設定されている場合は 10 秒ごとに、waiting for Elasticsearch response <N>sec もログに記録します。

  2. Elasticsearch が Zabbix サーバーおよび Zabbix Webインターフェースからのアクセスを許可していることを確認します。

  3. auto_create_index が有効になっていることを確認します(デフォルトで有効です)。

curl -X GET \
 "http://localhost:9200/_cluster/settings?include_defaults=true&filter_path=**.auto_create_index"

# {"persistent": {"action": {"auto_create_index": "false"} } }

有効にするには、次のリクエストを送信します。

curl -X PUT \
 http://localhost:9200/_cluster/settings \
 -H 'content-type:application/json' \
 -d '{
   "persistent": {
      "action.auto_create_index": "true"
   }
}'

# {"acknowledged": true, "persistent": {"action": {"auto_create_index": "true"} }, "transient": {} }
  1. それぞれの URL に GET リクエストを送信して、マッピング、テンプレート、取り込みパイプラインが正しいことを確認します。
curl -X GET "http://localhost:9200/json*"
curl -X GET "http://localhost:9200/_index_template/json*"
curl -X GET "http://localhost:9200/_ingest/pipeline/json*"

受信したレスポンスは、Elasticsearch API ドキュメントに記載されている期待されるレスポンスと比較できます。

  1. シャードが失敗状態になっていないか確認します。Elasticsearch を再起動すると解決する場合があります。 単一ノードのクラスターでは、レプリカを持つインデックス("number_of_replicas": 1)は、レプリカをプライマリシャードと同じノードに割り当てることができないため、yellow ステータスになります。これは Zabbix に影響しません。 これを回避するには、"number_of_replicas" を 0 に設定します。

  2. Elasticsearch にクエリを実行して、Zabbix が収集したデータが保存されているか確認します。例:

curl "http://localhost:9200/json*/_search" \
 -H 'Content-Type: application/json' \
 -d '{
   "query": {
     "term": {
       "itemid": 42269
     }
   }
 }'
  1. Elasticsearch のセットアップをリセットして最初からやり直す必要がある場合は、Zabbix 用に作成されたインデックス、インデックステンプレート、取り込みパイプラインを削除します(これにより、Elasticsearch に保存されているすべての履歴データが削除されます)。 デフォルトでは、Elasticsearch はワイルドカード式によるインデックスの削除を許可していません。そのため、日付ベースのインデックスを削除するには、action.destructive_requires_name 設定を一時的に変更します。 インデックステンプレートと取り込みパイプラインは 1 つずつ削除する必要があります。存在しないテンプレートまたはパイプラインに対するリクエストはエラーを返しますが、無視できます。
curl -X DELETE "http://localhost:9200/uint,dbl,str,log,text,json?ignore_unavailable=true"

curl -X PUT \
 http://localhost:9200/_cluster/settings \
 -H 'content-type:application/json' \
 -d '{"persistent": {"action.destructive_requires_name": false}}'
curl -X DELETE "http://localhost:9200/uint-*,dbl-*,str-*,log-*,text-*,json-*"
curl -X PUT \
 http://localhost:9200/_cluster/settings \
 -H 'content-type:application/json' \
 -d '{"persistent": {"action.destructive_requires_name": null}}'

for type in uint dbl str log text json; do
  curl -X DELETE "http://localhost:9200/_index_template/${type}_template"
  curl -X DELETE "http://localhost:9200/_ingest/pipeline/${type}-pipeline"
done
curl -X DELETE "http://localhost:9200/_ingest/pipeline/json"