Elasticsearch
Elasticsearch 総合技術ガイド
SREエンジニアのための包括的リファレンス
第1章: Elasticsearch とは
1.1 概要
Elasticsearch は、Apache Lucene をベースに構築された分散型の検索・分析エンジンである。RESTful API を通じて、大規模なデータセットに対するリアルタイムの全文検索、構造化検索、分析を提供する。
Elastic Stack(旧称 ELK Stack)の中核コンポーネントとして、Kibana(可視化)、Logstash(データ収集・変換)、Beats/Elastic Agent(軽量データシッパー)と連携して動作する。
1.2 主な特徴
- 分散アーキテクチャ: 水平スケーリングが可能で、ペタバイト規模のデータを処理
- リアルタイム検索: ドキュメントのインデックス後、ほぼリアルタイムで検索可能(デフォルト1秒のrefresh interval)
- スキーマレス: JSON ドキュメントをそのまま格納可能(動的マッピング)
- RESTful API: HTTP 経由で全機能にアクセス可能
- 高可用性: レプリカシャードによるデータ冗長化とフェイルオーバー
- 多言語対応: 日本語を含む多言語のアナライザーを内蔵
1.3 Elastic Stack の全体像
+------------------------------------------------------------------+
| Elastic Stack |
| |
| +------------+ +------------+ +-----------+ +--------+ |
| | Kibana | | Logstash | | Beats | | Elastic| |
| | (可視化/UI)| |(ETLパイプ | |(軽量データ| | Agent | |
| | | | ライン) | | シッパー) | | | |
| +------+-----+ +------+-----+ +-----+-----+ +---+----+ |
| | | | | |
| v v v v |
| +----------------------------------------------------------+ |
| | Elasticsearch | |
| | (検索・分析エンジン) | |
| +----------------------------------------------------------+ |
+------------------------------------------------------------------+
1.4 Apache Lucene との関係
Elasticsearch は内部的に Apache Lucene ライブラリを使用している。Lucene は Java で書かれた高性能な全文検索エンジンライブラリであり、転置インデックス(Inverted Index)を使用してテキスト検索を実現する。
Elasticsearch が Lucene の上に追加する主な機能:
| 機能 | Lucene | Elasticsearch |
|---|---|---|
| 分散処理 | なし | クラスタ管理、シャーディング |
| REST API | なし | 完全な RESTful API |
| リアルタイム | なし | ニアリアルタイム検索 |
| レプリケーション | なし | 自動レプリカ管理 |
| クラスタ管理 | なし | ノード検出、障害検知 |
| 集約(Aggregation) | 限定的 | 豊富な集約フレームワーク |
1.5 ユースケース
- ログ分析・モニタリング: アプリケーション/インフラログの集約と分析
- 全文検索: Web サイト検索、ドキュメント検索
- セキュリティ分析(SIEM): セキュリティイベントのリアルタイム分析
- APM(Application Performance Monitoring): アプリケーションパフォーマンスの監視
- ビジネス分析: 売上データ、ユーザー行動分析
- 地理空間データ検索: 位置情報ベースの検索・分析
第2章: アーキテクチャ
2.1 クラスタ構成の全体像
+------------------------------------------------------------------+
| Elasticsearch Cluster |
| (cluster.name: production) |
| |
| +------------------+ +------------------+ +-----------------+ |
| | Master Node (1) | | Master Node (2) | | Master Node (3) | |
| | [Elected Master] | | [Master-eligible]| | [Master-eligible]| |
| | クラスタ状態管理 | | フェイルオーバー | | フェイルオーバー | |
| +------------------+ +------------------+ +-----------------+ |
| |
| +------------------+ +------------------+ +-----------------+ |
| | Data Node (1) | | Data Node (2) | | Data Node (3) | |
| | [Hot] | | [Hot] | | [Warm] | |
| | P0 P1 R2 | | P2 R0 R1 | | P3 R3 | |
| | 高速SSD | | 高速SSD | | HDD | |
| +------------------+ +------------------+ +-----------------+ |
| |
| +------------------+ +------------------+ |
| | Ingest Node | | Coordinating | |
| | パイプライン処理 | | Node | |
| | データ変換 | | リクエストルーティ| |
| | | | ング・集約 | |
| +------------------+ +------------------+ |
+------------------------------------------------------------------+
P = Primary Shard (プライマリシャード)
R = Replica Shard (レプリカシャード)
2.2 ノードの役割
Elasticsearch クラスタ内の各ノードには、1つ以上の役割を割り当てることができる。
2.2.1 マスターノード (master)
クラスタの状態管理を担当する。選出されたマスターノードは以下を管理する:
- インデックスの作成・削除
- シャードの割り当て
- ノードの追加・削除の追跡
- クラスタ設定の管理
# elasticsearch.yml - マスター専用ノード
node.roles: [ master ]
node.name: master-node-1
cluster.name: production
# マスターノードは軽量なリソースで十分
# CPU: 2-4コア, RAM: 4-8GB, Disk: 低速でも可
2.2.2 データノード (data)
実際のデータを保持し、CRUD 操作、検索、集約を実行する。
# elasticsearch.yml - データノード(Hot tier)
node.roles: [ data_hot ]
node.name: data-hot-node-1
cluster.name: production
# Hot ノード: 高速SSD、十分なRAM
# CPU: 8-16コア, RAM: 32-64GB, Disk: SSD 1-4TB
# elasticsearch.yml - データノード(Warm tier)
node.roles: [ data_warm ]
node.name: data-warm-node-1
cluster.name: production
# Warm ノード: HDD可、中程度のRAM
# CPU: 4-8コア, RAM: 16-32GB, Disk: HDD 4-8TB
# elasticsearch.yml - データノード(Cold tier)
node.roles: [ data_cold ]
node.name: data-cold-node-1
cluster.name: production
# Cold ノード: 最低限のリソース、大容量ストレージ
# CPU: 2-4コア, RAM: 8-16GB, Disk: HDD 8-16TB
2.2.3 インジェストノード (ingest)
ドキュメントのインデックス前にデータを変換・加工するパイプライン処理を実行する。
# elasticsearch.yml - インジェスト専用ノード
node.roles: [ ingest ]
node.name: ingest-node-1
cluster.name: production
2.2.4 コーディネーティングノード (coordinating)
クライアントからのリクエストをルーティングし、検索結果の集約を行う。全ノードはデフォルトでコーディネーティングの役割を持つが、専用ノードを設定することもできる。
# elasticsearch.yml - コーディネーティング専用ノード
node.roles: [ ]
node.name: coordinating-node-1
cluster.name: production
2.2.5 ML ノード (ml)
機械学習ジョブを実行する専用ノード。
# elasticsearch.yml - MLノード
node.roles: [ ml, remote_cluster_client ]
node.name: ml-node-1
cluster.name: production
2.3 インデックス、シャード、レプリカ
2.3.1 インデックスの構造
+------------------------------------------------------------------+
| Index: logs-2026.04 |
| |
| Primary Shards Replica Shards |
| +--------+--------+ +--------+--------+ |
| | Shard 0| Shard 1| |Replica0|Replica1| |
| | (Node1)| (Node2)| | (Node2)| (Node1)| |
| +--------+--------+ +--------+--------+ |
| | Shard 2| |Replica2| |
| | (Node1)| | (Node2)| |
| +--------+ +--------+ |
| |
| 各シャード = 1つの Lucene インデックス |
| 各 Lucene インデックス = 複数のセグメント |
+------------------------------------------------------------------+
2.3.2 転置インデックス(Inverted Index)
Elasticsearch が高速な全文検索を実現する核心技術:
ドキュメント:
Doc1: "Elasticsearch は分散検索エンジンです"
Doc2: "Elasticsearch は Lucene ベースです"
Doc3: "分散システムは高可用性を提供します"
転置インデックス:
+------------------+------------------+
| Term | Document IDs |
+------------------+------------------+
| elasticsearch | Doc1, Doc2 |
| 分散 | Doc1, Doc3 |
| 検索 | Doc1 |
| エンジン | Doc1 |
| lucene | Doc2 |
| ベース | Doc2 |
| システム | Doc3 |
| 高可用性 | Doc3 |
| 提供 | Doc3 |
+------------------+------------------+
2.3.3 セグメント
各シャードは内部的に複数のセグメントで構成される。セグメントは不変(immutable)であり、新しいドキュメントは新しいセグメントとして書き込まれる。
Shard 0:
+-------------------------------------------+
| Segment 0 (immutable, merged) |
| - 10,000 documents |
| - Inverted Index |
| - Stored Fields |
| - Doc Values |
+-------------------------------------------+
| Segment 1 (immutable) |
| - 5,000 documents |
+-------------------------------------------+
| Segment 2 (新規、まだマージされていない) |
| - 500 documents |
+-------------------------------------------+
| Transaction Log (translog) |
| - まだセグメントに書き込まれていない変更 |
+-------------------------------------------+
2.4 クラスタ状態の管理
マスターノードが管理するクラスタ状態には以下が含まれる:
- ノードの一覧と各ノードの役割
- インデックスとそのマッピング/設定
- シャードの配置情報
- クラスタレベルの設定
# クラスタの状態を確認
curl -X GET "localhost:9200/_cluster/state?pretty"
# クラスタのヘルスチェック
curl -X GET "localhost:9200/_cluster/health?pretty"
# 応答例:
# {
# "cluster_name": "production",
# "status": "green", # green/yellow/red
# "number_of_nodes": 6,
# "number_of_data_nodes": 3,
# "active_primary_shards": 50,
# "active_shards": 100,
# "relocating_shards": 0,
# "initializing_shards": 0,
# "unassigned_shards": 0,
# "delayed_unassigned_shards": 0
# }
2.5 ドキュメントのルーティング
ドキュメントがどのシャードに格納されるかは、以下の式で決定される:
shard_number = hash(routing_value) % number_of_primary_shards
デフォルトでは routing_value はドキュメントの _id フィールドである。
# カスタムルーティングを指定してインデックス
curl -X PUT "localhost:9200/my-index/_doc/1?routing=user123" -H 'Content-Type: application/json' -d'
{
"user": "user123",
"message": "Custom routing example"
}'
第3章: インデックス管理
3.1 インデックスの作成
# 基本的なインデックス作成
curl -X PUT "localhost:9200/my-index" -H 'Content-Type: application/json' -d'
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s",
"analysis": {
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "stop", "snowball"]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "custom_analyzer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"timestamp": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
},
"status_code": {
"type": "integer"
},
"response_time": {
"type": "float"
},
"tags": {
"type": "keyword"
},
"geo_location": {
"type": "geo_point"
},
"metadata": {
"type": "object",
"dynamic": true
}
}
}
}'
3.2 マッピングとフィールドタイプ
3.2.1 主要なフィールドタイプ
| タイプ | 説明 | 用途 |
|---|---|---|
text | 全文検索用、アナライズされる | ログメッセージ、説明文 |
keyword | 完全一致検索用、アナライズされない | ステータス、タグ、ID |
long / integer / short / byte | 整数型 | カウント、ステータスコード |
double / float / half_float | 浮動小数点型 | レスポンスタイム、スコア |
date | 日時型 | タイムスタンプ |
boolean | 真偽値 | フラグ |
ip | IPアドレス | ネットワーク分析 |
geo_point | 緯度経度 | 地理空間検索 |
nested | ネストされたオブジェクト | 独立した検索が必要な配列 |
object | JSONオブジェクト | 構造化データ |
flattened | フラット化されたオブジェクト | 動的なキーを持つデータ |
3.2.2 マッピングの例(ログ用インデックス)
curl -X PUT "localhost:9200/application-logs" -H 'Content-Type: application/json' -d'
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": {
"type": "date"
},
"log_level": {
"type": "keyword"
},
"service_name": {
"type": "keyword"
},
"host": {
"properties": {
"name": { "type": "keyword" },
"ip": { "type": "ip" }
}
},
"message": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 1024
}
}
},
"trace_id": {
"type": "keyword"
},
"span_id": {
"type": "keyword"
},
"duration_ms": {
"type": "float"
},
"error": {
"properties": {
"type": { "type": "keyword" },
"message": { "type": "text" },
"stack_trace": {
"type": "text",
"index": false
}
}
},
"labels": {
"type": "flattened"
}
}
}
}'
3.3 動的マッピング
動的マッピングでは、Elasticsearch が未知のフィールドを自動的にマッピングする。
# 動的マッピングのテンプレートを設定
curl -X PUT "localhost:9200/dynamic-example" -H 'Content-Type: application/json' -d'
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword",
"ignore_above": 512
}
}
},
{
"longs_as_integers": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"unindexed_fields": {
"match": "debug_*",
"mapping": {
"type": "text",
"index": false
}
}
}
]
}
}'
3.4 インデックステンプレート
3.4.1 コンポーネントテンプレート
# 共通設定のコンポーネントテンプレート
curl -X PUT "localhost:9200/_component_template/common-settings" -H 'Content-Type: application/json' -d'
{
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s",
"index.lifecycle.name": "logs-policy",
"index.lifecycle.rollover_alias": "logs"
}
}
}'
# 共通マッピングのコンポーネントテンプレート
curl -X PUT "localhost:9200/_component_template/common-mappings" -H 'Content-Type: application/json' -d'
{
"template": {
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"host.name": { "type": "keyword" },
"host.ip": { "type": "ip" },
"agent.type": { "type": "keyword" }
}
}
}
}'
3.4.2 インデックステンプレート
# インデックステンプレートの作成
curl -X PUT "localhost:9200/_index_template/logs-template" -H 'Content-Type: application/json' -d'
{
"index_patterns": ["logs-*"],
"priority": 200,
"composed_of": ["common-settings", "common-mappings"],
"template": {
"settings": {
"number_of_shards": 5
},
"mappings": {
"properties": {
"log_level": { "type": "keyword" },
"message": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 1024
}
}
}
}
},
"aliases": {
"logs-current": {}
}
},
"data_stream": {}
}'
3.5 インデックスライフサイクル管理(ILM)
ILM を使用すると、インデックスのライフサイクルを自動的に管理できる。
# ILM ポリシーの作成
curl -X PUT "localhost:9200/_ilm/policy/logs-policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_primary_shard_size": "50gb",
"max_age": "1d",
"max_docs": 100000000
},
"set_priority": {
"priority": 100
},
"forcemerge": {
"max_num_segments": 1
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": {
"number_of_shards": 1
},
"forcemerge": {
"max_num_segments": 1
},
"allocate": {
"require": {
"data": "warm"
}
},
"set_priority": {
"priority": 50
}
}
},
"cold": {
"min_age": "30d",
"actions": {
"allocate": {
"require": {
"data": "cold"
}
},
"set_priority": {
"priority": 0
},
"freeze": {}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}'
3.5.1 ILM ライフサイクルの図解
Hot Phase Warm Phase Cold Phase Delete Phase
(0-7日) (7-30日) (30-90日) (90日以降)
+---------------+ +---------------+ +---------------+ +----------+
| 高速SSD | | 中速ストレージ | | 低速HDD | | データ |
| 書き込み可能 |->| 読み取り専用 |->| 凍結済み |->| 削除 |
| 高プライオリティ| | シュリンク | | 低プライオリティ| | |
| ロールオーバー | | フォースマージ| | | | |
+---------------+ +---------------+ +---------------+ +----------+
3.6 エイリアス
# エイリアスの作成
curl -X POST "localhost:9200/_aliases" -H 'Content-Type: application/json' -d'
{
"actions": [
{
"add": {
"index": "logs-2026.04.08",
"alias": "logs-current"
}
},
{
"add": {
"index": "logs-2026.04.*",
"alias": "logs-this-month"
}
},
{
"add": {
"index": "logs-*",
"alias": "logs-all",
"filter": {
"range": {
"@timestamp": {
"gte": "now-30d"
}
}
}
}
}
]
}'
# 書き込みエイリアス(ロールオーバー用)
curl -X PUT "localhost:9200/logs-000001" -H 'Content-Type: application/json' -d'
{
"aliases": {
"logs-write": {
"is_write_index": true
}
}
}'
# ロールオーバーの実行
curl -X POST "localhost:9200/logs-write/_rollover" -H 'Content-Type: application/json' -d'
{
"conditions": {
"max_age": "1d",
"max_primary_shard_size": "50gb",
"max_docs": 100000000
}
}'
3.7 データストリーム
データストリームは、時系列データ(ログ、メトリクスなど)のための簡素化されたインデックス管理を提供する。
# データストリーム用のインデックステンプレートを作成
curl -X PUT "localhost:9200/_index_template/metrics-template" -H 'Content-Type: application/json' -d'
{
"index_patterns": ["metrics-*"],
"data_stream": {},
"priority": 200,
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "metrics-policy"
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"metric_name": { "type": "keyword" },
"metric_value": { "type": "double" },
"host": { "type": "keyword" },
"tags": { "type": "keyword" }
}
}
}
}'
# データストリームへのドキュメント追加
curl -X POST "localhost:9200/metrics-app/_doc" -H 'Content-Type: application/json' -d'
{
"@timestamp": "2026-04-08T10:00:00Z",
"metric_name": "cpu_usage",
"metric_value": 75.5,
"host": "web-server-01",
"tags": ["production", "web"]
}'
第4章: データインジェスト
4.1 単一ドキュメントのインデックス
# ドキュメントIDを指定してインデックス
curl -X PUT "localhost:9200/my-index/_doc/1" -H 'Content-Type: application/json' -d'
{
"@timestamp": "2026-04-08T10:30:00Z",
"service": "payment-service",
"log_level": "ERROR",
"message": "Payment processing failed: timeout exceeded",
"trace_id": "abc123def456",
"duration_ms": 30500
}'
# ドキュメントIDを自動生成してインデックス
curl -X POST "localhost:9200/my-index/_doc" -H 'Content-Type: application/json' -d'
{
"@timestamp": "2026-04-08T10:31:00Z",
"service": "payment-service",
"log_level": "INFO",
"message": "Payment processed successfully",
"trace_id": "xyz789ghi012",
"duration_ms": 250
}'
4.2 Bulk API
大量のドキュメントを効率的にインデックスするための API。
# Bulk API の使用
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/x-ndjson' -d'
{"index": {"_index": "logs-2026.04.08", "_id": "1"}}
{"@timestamp": "2026-04-08T10:00:00Z", "service": "api-gateway", "log_level": "INFO", "message": "Request received", "status_code": 200}
{"index": {"_index": "logs-2026.04.08", "_id": "2"}}
{"@timestamp": "2026-04-08T10:00:01Z", "service": "api-gateway", "log_level": "WARN", "message": "Slow response detected", "status_code": 200, "duration_ms": 5000}
{"index": {"_index": "logs-2026.04.08", "_id": "3"}}
{"@timestamp": "2026-04-08T10:00:02Z", "service": "auth-service", "log_level": "ERROR", "message": "Authentication failed", "status_code": 401}
{"create": {"_index": "logs-2026.04.08", "_id": "4"}}
{"@timestamp": "2026-04-08T10:00:03Z", "service": "payment-service", "log_level": "INFO", "message": "Payment initiated", "status_code": 200}
{"update": {"_index": "logs-2026.04.08", "_id": "1"}}
{"doc": {"processed": true}}
{"delete": {"_index": "logs-2026.04.08", "_id": "999"}}
'
# Bulk API のベストプラクティス:
# - バッチサイズ: 5-15 MB が最適(ドキュメント数ではなくサイズで制御)
# - 並列度: データノード数 × 1-2 のスレッド数
# - エラーハンドリング: レスポンスの errors フラグを必ず確認
4.3 インジェストパイプライン
インジェストパイプラインは、ドキュメントがインデックスされる前にデータを変換する。
# インジェストパイプラインの作成
curl -X PUT "localhost:9200/_ingest/pipeline/logs-pipeline" -H 'Content-Type: application/json' -d'
{
"description": "ログデータの前処理パイプライン",
"processors": [
{
"date": {
"field": "timestamp_string",
"target_field": "@timestamp",
"formats": ["ISO8601", "yyyy-MM-dd HH:mm:ss"],
"timezone": "Asia/Tokyo"
}
},
{
"grok": {
"field": "raw_message",
"patterns": [
"%{IP:client_ip} %{WORD:method} %{URIPATH:path} %{NUMBER:status_code:int} %{NUMBER:response_time:float}"
]
}
},
{
"geoip": {
"field": "client_ip",
"target_field": "geo"
}
},
{
"user_agent": {
"field": "user_agent_string",
"target_field": "user_agent"
}
},
{
"set": {
"field": "ingest_timestamp",
"value": "{{_ingest.timestamp}}"
}
},
{
"lowercase": {
"field": "log_level"
}
},
{
"remove": {
"field": ["raw_message", "timestamp_string", "user_agent_string"],
"ignore_missing": true
}
},
{
"script": {
"lang": "painless",
"source": "if (ctx.status_code != null) { if (ctx.status_code >= 500) { ctx.severity = 'critical'; } else if (ctx.status_code >= 400) { ctx.severity = 'warning'; } else { ctx.severity = 'info'; } }"
}
}
],
"on_failure": [
{
"set": {
"field": "_index",
"value": "failed-logs"
}
},
{
"set": {
"field": "error.message",
"value": "{{ _ingest.on_failure_message }}"
}
},
{
"set": {
"field": "error.processor",
"value": "{{ _ingest.on_failure_processor_type }}"
}
}
]
}'
# パイプラインを使用してドキュメントをインデックス
curl -X POST "localhost:9200/processed-logs/_doc?pipeline=logs-pipeline" -H 'Content-Type: application/json' -d'
{
"timestamp_string": "2026-04-08T10:30:00+09:00",
"raw_message": "192.168.1.100 GET /api/users 200 0.125",
"user_agent_string": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"log_level": "INFO"
}'
# パイプラインのテスト(シミュレーション)
curl -X POST "localhost:9200/_ingest/pipeline/logs-pipeline/_simulate" -H 'Content-Type: application/json' -d'
{
"docs": [
{
"_source": {
"timestamp_string": "2026-04-08T10:30:00+09:00",
"raw_message": "10.0.0.1 POST /api/orders 500 2.500",
"user_agent_string": "curl/7.79.1",
"log_level": "ERROR"
}
}
]
}'
4.4 Logstash との連携
4.4.1 Logstash 設定ファイルの例
# /etc/logstash/conf.d/application-logs.conf
input {
# Filebeat からの入力
beats {
port => 5044
ssl => true
ssl_certificate => "/etc/logstash/certs/logstash.crt"
ssl_key => "/etc/logstash/certs/logstash.key"
}
# Kafka からの入力
kafka {
bootstrap_servers => "kafka-01:9092,kafka-02:9092,kafka-03:9092"
topics => ["application-logs"]
group_id => "logstash-consumers"
codec => json
consumer_threads => 3
}
}
filter {
# JSON パース
if [message] =~ /^\{/ {
json {
source => "message"
target => "parsed"
}
}
# Grok パターンでログをパース
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{LOGLEVEL:log_level}\] %{DATA:service} - %{GREEDYDATA:log_message}"
}
}
# 日時フィールドの変換
date {
match => ["timestamp", "ISO8601"]
target => "@timestamp"
}
# 不要なフィールドの削除
mutate {
remove_field => ["message", "timestamp", "agent", "ecs"]
}
# 条件付き処理
if [log_level] == "ERROR" {
mutate {
add_tag => ["alert"]
}
}
}
output {
# Elasticsearch への出力
elasticsearch {
hosts => ["https://es-node-01:9200", "https://es-node-02:9200"]
index => "logs-%{[service]}-%{+YYYY.MM.dd}"
ssl => true
cacert => "/etc/logstash/certs/ca.crt"
user => "logstash_writer"
password => "${ES_PASSWORD}"
# テンプレート管理
template_name => "logs"
template_overwrite => true
# パフォーマンス設定
pipeline => "logs-pipeline"
}
# エラーログは別途 Dead Letter Queue に送信
if "alert" in [tags] {
elasticsearch {
hosts => ["https://es-node-01:9200"]
index => "alerts-%{+YYYY.MM.dd}"
user => "logstash_writer"
password => "${ES_PASSWORD}"
}
}
}
4.5 Beats / Elastic Agent
4.5.1 Filebeat 設定例
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: filestream
id: application-logs
enabled: true
paths:
- /var/log/application/*.log
parsers:
- ndjson:
target: ""
add_error_key: true
fields:
environment: production
service: payment-api
fields_under_root: true
- type: filestream
id: system-logs
enabled: true
paths:
- /var/log/syslog
- /var/log/auth.log
exclude_lines: ['^DBG']
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- add_docker_metadata: ~
- add_kubernetes_metadata: ~
- drop_fields:
fields: ["agent.ephemeral_id", "agent.hostname"]
output.elasticsearch:
hosts: ["https://es-node-01:9200", "https://es-node-02:9200"]
protocol: "https"
username: "filebeat_writer"
password: "${ES_PASSWORD}"
ssl:
certificate_authorities: ["/etc/filebeat/certs/ca.crt"]
indices:
- index: "filebeat-app-%{+yyyy.MM.dd}"
when.contains:
fields.service: "payment-api"
- index: "filebeat-system-%{+yyyy.MM.dd}"
# Kibana 接続(ダッシュボード設定用)
setup.kibana:
host: "https://kibana:5601"
# ILM 設定
setup.ilm.enabled: true
setup.ilm.rollover_alias: "filebeat"
setup.ilm.pattern: "{now/d}-000001"
setup.ilm.policy_name: "filebeat-policy"
# モニタリング
monitoring.enabled: true
monitoring.elasticsearch:
hosts: ["https://monitoring-es:9200"]
4.5.2 Metricbeat 設定例
# /etc/metricbeat/metricbeat.yml
metricbeat.modules:
- module: system
metricsets:
- cpu
- memory
- network
- diskio
- filesystem
- process
period: 10s
processes: ['.*']
cpu.metrics: ["percentages", "normalized_percentages"]
- module: docker
metricsets:
- container
- cpu
- diskio
- memory
- network
hosts: ["unix:///var/run/docker.sock"]
period: 10s
- module: elasticsearch
metricsets:
- node
- node_stats
- index
- index_summary
- cluster_stats
- shard
period: 10s
hosts: ["https://localhost:9200"]
username: "monitoring_user"
password: "${ES_MONITORING_PASSWORD}"
output.elasticsearch:
hosts: ["https://monitoring-es:9200"]
index: "metricbeat-%{+yyyy.MM.dd}"
第5章: 検索と Query DSL
5.1 基本的な検索
# 全ドキュメントを検索
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
},
"size": 10,
"from": 0,
"sort": [
{ "@timestamp": { "order": "desc" } }
]
}'
5.2 全文検索クエリ
5.2.1 match クエリ
# match クエリ(アナライザーによりトークン化される)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"message": {
"query": "payment timeout error",
"operator": "and",
"minimum_should_match": "75%",
"fuzziness": "AUTO"
}
}
}
}'
# match_phrase クエリ(語順を考慮)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_phrase": {
"message": {
"query": "connection refused",
"slop": 2
}
}
}
}'
# multi_match クエリ(複数フィールドを検索)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"multi_match": {
"query": "database timeout",
"fields": ["message^3", "error.message^2", "service_name"],
"type": "best_fields"
}
}
}'
5.2.2 term クエリ(完全一致)
# term クエリ(keyword フィールドに使用)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"term": {
"log_level": {
"value": "ERROR"
}
}
}
}'
# terms クエリ(複数値のOR条件)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"terms": {
"status_code": [500, 502, 503, 504]
}
}
}'
5.3 Bool クエリ(複合クエリ)
# 複雑な Bool クエリの例
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "error"
}
},
{
"range": {
"@timestamp": {
"gte": "2026-04-08T00:00:00Z",
"lte": "2026-04-08T23:59:59Z"
}
}
}
],
"filter": [
{
"term": {
"service_name": "payment-service"
}
},
{
"terms": {
"log_level": ["ERROR", "CRITICAL"]
}
}
],
"should": [
{
"match": {
"message": "timeout"
}
},
{
"match": {
"message": "connection refused"
}
}
],
"minimum_should_match": 1,
"must_not": [
{
"term": {
"host.name": "test-server"
}
}
]
}
},
"highlight": {
"fields": {
"message": {
"pre_tags": ["<em>"],
"post_tags": ["</em>"],
"fragment_size": 200,
"number_of_fragments": 3
}
}
},
"sort": [
{ "@timestamp": "desc" },
"_score"
],
"size": 20,
"_source": ["@timestamp", "service_name", "log_level", "message", "host.name"]
}'
5.3.1 Bool クエリの各句の違い
+------------------------------------------------------------------+
| Bool クエリの句 | スコアリング | キャッシュ | 用途 |
+------------------------------------------------------------------+
| must | あり | なし | スコアに影響する |
| | | | 条件 |
| filter | なし | あり | Yes/No のフィルタ |
| | | | リング |
| should | あり | なし | オプションの条件 |
| | | | (スコアブースト) |
| must_not | なし | あり | 除外条件 |
+------------------------------------------------------------------+
パフォーマンスのポイント:
- スコアリングが不要な条件は filter を使用
- filter はキャッシュされるため高速
- must_not もキャッシュされる
5.4 Range クエリ
# 数値範囲
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"filter": [
{
"range": {
"duration_ms": {
"gte": 1000,
"lte": 30000
}
}
},
{
"range": {
"@timestamp": {
"gte": "now-24h",
"lte": "now",
"format": "strict_date_optional_time"
}
}
}
]
}
}
}'
5.5 Nested クエリ
# Nested オブジェクトのマッピング
curl -X PUT "localhost:9200/orders" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"order_id": { "type": "keyword" },
"items": {
"type": "nested",
"properties": {
"product_name": { "type": "text" },
"quantity": { "type": "integer" },
"price": { "type": "float" }
}
}
}
}
}'
# Nested クエリ
curl -X GET "localhost:9200/orders/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"nested": {
"path": "items",
"query": {
"bool": {
"must": [
{ "match": { "items.product_name": "laptop" } },
{ "range": { "items.price": { "lte": 1000 } } }
]
}
},
"inner_hits": {
"size": 3,
"highlight": {
"fields": {
"items.product_name": {}
}
}
}
}
}
}'
5.6 関連性スコアリング (BM25)
Elasticsearch はデフォルトで BM25(Best Matching 25)アルゴリズムを使用してドキュメントの関連性スコアを計算する。
BM25 スコア = IDF × (tf × (k1 + 1)) / (tf + k1 × (1 - b + b × dl/avgdl))
IDF = Inverse Document Frequency(そのタームを含むドキュメントが少ないほど高スコア)
tf = Term Frequency(ドキュメント内でのターム出現頻度)
dl = Document Length(ドキュメントの長さ)
avgdl = Average Document Length(平均ドキュメント長)
k1 = タームの出現頻度の影響度(デフォルト: 1.2)
b = ドキュメント長の正規化の影響度(デフォルト: 0.75)
# スコアの説明を取得
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"message": "payment error"
}
},
"explain": true
}'
# Function Score クエリ(スコアのカスタマイズ)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"function_score": {
"query": {
"match": { "message": "error" }
},
"functions": [
{
"gauss": {
"@timestamp": {
"origin": "now",
"scale": "2h",
"decay": 0.5
}
},
"weight": 2
},
{
"field_value_factor": {
"field": "severity_score",
"modifier": "log1p",
"missing": 1
}
}
],
"score_mode": "sum",
"boost_mode": "multiply"
}
}
}'
5.7 ページネーション
# 基本的なページネーション(from/size)
# 注意: from + size <= 10,000(デフォルト制限)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": { "match_all": {} },
"from": 0,
"size": 20,
"sort": [{ "@timestamp": "desc" }]
}'
# search_after(深いページネーション用)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": { "match_all": {} },
"size": 20,
"sort": [
{ "@timestamp": "desc" },
{ "_id": "asc" }
],
"search_after": ["2026-04-08T10:00:00.000Z", "abc123"]
}'
# Point in Time (PIT) API + search_after(一貫性のあるページネーション)
# まず PIT を作成
curl -X POST "localhost:9200/logs-*/_pit?keep_alive=5m"
# 応答: { "id": "..." }
# PIT を使って検索
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": { "match_all": {} },
"size": 100,
"sort": [{ "@timestamp": "desc" }, { "_id": "asc" }],
"pit": {
"id": "<PIT_ID>",
"keep_alive": "5m"
}
}'
# Scroll API(大量のドキュメントをエクスポートする場合)
# 注意: 新しいプロジェクトではPIT + search_after推奨
curl -X POST "localhost:9200/logs-*/_search?scroll=5m&pretty" -H 'Content-Type: application/json' -d'
{
"query": { "match_all": {} },
"size": 1000,
"sort": ["_doc"]
}'
# 次のページを取得
curl -X POST "localhost:9200/_search/scroll?pretty" -H 'Content-Type: application/json' -d'
{
"scroll": "5m",
"scroll_id": "<SCROLL_ID>"
}'
第6章: アグリゲーション(集約)詳解
6.1 バケットアグリゲーション
6.1.1 terms アグリゲーション
# サービス別のエラー件数
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"query": {
"term": { "log_level": "ERROR" }
},
"aggs": {
"errors_by_service": {
"terms": {
"field": "service_name",
"size": 20,
"order": { "_count": "desc" },
"min_doc_count": 1
},
"aggs": {
"error_types": {
"terms": {
"field": "error.type",
"size": 5
}
},
"avg_duration": {
"avg": {
"field": "duration_ms"
}
}
}
}
}
}'
6.1.2 date_histogram アグリゲーション
# 時間帯別のリクエスト数とレスポンスタイムの推移
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"query": {
"range": {
"@timestamp": {
"gte": "now-24h",
"lte": "now"
}
}
},
"aggs": {
"requests_over_time": {
"date_histogram": {
"field": "@timestamp",
"fixed_interval": "5m",
"time_zone": "Asia/Tokyo",
"min_doc_count": 0,
"extended_bounds": {
"min": "now-24h",
"max": "now"
}
},
"aggs": {
"avg_response_time": {
"avg": { "field": "duration_ms" }
},
"p95_response_time": {
"percentiles": {
"field": "duration_ms",
"percents": [95]
}
},
"error_rate": {
"filter": {
"range": { "status_code": { "gte": 500 } }
},
"aggs": {
"count": { "value_count": { "field": "status_code" } }
}
},
"status_codes": {
"terms": {
"field": "status_code",
"size": 10
}
}
}
}
}
}'
6.1.3 histogram アグリゲーション
# レスポンスタイムの分布
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"response_time_distribution": {
"histogram": {
"field": "duration_ms",
"interval": 100,
"min_doc_count": 0,
"extended_bounds": {
"min": 0,
"max": 5000
}
}
}
}
}'
6.1.4 range アグリゲーション
# レスポンスタイムのレンジ分類
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"response_time_ranges": {
"range": {
"field": "duration_ms",
"ranges": [
{ "key": "fast", "to": 100 },
{ "key": "normal", "from": 100, "to": 500 },
{ "key": "slow", "from": 500, "to": 2000 },
{ "key": "very_slow", "from": 2000 }
]
},
"aggs": {
"by_service": {
"terms": { "field": "service_name", "size": 10 }
}
}
}
}
}'
6.2 メトリックアグリゲーション
# 包括的な統計情報
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"query": {
"bool": {
"filter": [
{ "range": { "@timestamp": { "gte": "now-1h" } } },
{ "term": { "service_name": "api-gateway" } }
]
}
},
"aggs": {
"response_stats": {
"stats": { "field": "duration_ms" }
},
"extended_stats": {
"extended_stats": { "field": "duration_ms" }
},
"percentile_values": {
"percentiles": {
"field": "duration_ms",
"percents": [50, 75, 90, 95, 99, 99.9]
}
},
"percentile_ranks": {
"percentile_ranks": {
"field": "duration_ms",
"values": [100, 500, 1000, 5000]
}
},
"cardinality_users": {
"cardinality": {
"field": "user_id",
"precision_threshold": 3000
}
},
"value_count": {
"value_count": { "field": "duration_ms" }
}
}
}'
6.3 significant_terms アグリゲーション
# エラーログに特徴的なキーワードを検出
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"query": {
"term": { "log_level": "ERROR" }
},
"aggs": {
"significant_error_terms": {
"significant_terms": {
"field": "message.keyword",
"size": 10,
"min_doc_count": 5,
"background_filter": {
"range": {
"@timestamp": { "gte": "now-24h" }
}
}
}
}
}
}'
6.4 composite アグリゲーション
大量のバケットを効率的にページネーションする。
# composite アグリゲーション(最初のページ)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"service_status_composite": {
"composite": {
"size": 100,
"sources": [
{
"service": {
"terms": { "field": "service_name" }
}
},
{
"status": {
"terms": { "field": "status_code" }
}
},
{
"date": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "1h"
}
}
}
]
},
"aggs": {
"avg_duration": {
"avg": { "field": "duration_ms" }
},
"doc_count": {
"value_count": { "field": "_id" }
}
}
}
}
}'
# 次のページを取得(after キーを指定)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"service_status_composite": {
"composite": {
"size": 100,
"sources": [
{ "service": { "terms": { "field": "service_name" } } },
{ "status": { "terms": { "field": "status_code" } } },
{ "date": { "date_histogram": { "field": "@timestamp", "calendar_interval": "1h" } } }
],
"after": {
"service": "payment-service",
"status": 200,
"date": 1712566800000
}
}
}
}
}'
6.5 パイプラインアグリゲーション
# パイプラインアグリゲーションの例
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"requests_per_hour": {
"date_histogram": {
"field": "@timestamp",
"fixed_interval": "1h"
},
"aggs": {
"avg_response_time": {
"avg": { "field": "duration_ms" }
},
"error_count": {
"filter": {
"range": { "status_code": { "gte": 500 } }
}
}
}
},
"max_avg_response_time": {
"max_bucket": {
"buckets_path": "requests_per_hour>avg_response_time"
}
},
"avg_hourly_errors": {
"avg_bucket": {
"buckets_path": "requests_per_hour>error_count._count"
}
},
"response_time_derivative": {
"derivative": {
"buckets_path": "requests_per_hour>avg_response_time"
}
},
"moving_avg_response": {
"moving_fn": {
"buckets_path": "requests_per_hour>avg_response_time",
"window": 6,
"script": "MovingFunctions.unweightedAvg(values)"
}
},
"cumulative_errors": {
"cumulative_sum": {
"buckets_path": "requests_per_hour>error_count._count"
}
}
}
}'
第7章: クラスタ管理
7.1 クラスタヘルスの監視
# クラスタヘルスの確認
curl -X GET "localhost:9200/_cluster/health?pretty"
# インデックスレベルのヘルスチェック
curl -X GET "localhost:9200/_cluster/health?level=indices&pretty"
# シャードレベルのヘルスチェック
curl -X GET "localhost:9200/_cluster/health?level=shards&pretty"
# 特定インデックスのヘルスチェック
curl -X GET "localhost:9200/_cluster/health/logs-*?pretty"
7.1.1 クラスタステータスの意味
+------------------------------------------------------------------+
| ステータス | 意味 |
+------------------------------------------------------------------+
| Green | 全てのプライマリシャードとレプリカシャードが割り当て済み |
| Yellow | 全プライマリシャードは割り当て済みだが、一部レプリカが |
| | 未割り当て |
| Red | 一部のプライマリシャードが未割り当て |
| | (データの一部にアクセスできない可能性) |
+------------------------------------------------------------------+
7.2 シャード割り当て
# 未割り当てシャードの原因を調査
curl -X GET "localhost:9200/_cluster/allocation/explain?pretty" -H 'Content-Type: application/json' -d'
{
"index": "logs-2026.04.08",
"shard": 0,
"primary": false
}'
# シャードの割り当てを手動で再試行
curl -X POST "localhost:9200/_cluster/reroute?retry_failed=true&pretty"
# シャードの手動移動
curl -X POST "localhost:9200/_cluster/reroute?pretty" -H 'Content-Type: application/json' -d'
{
"commands": [
{
"move": {
"index": "logs-2026.04.08",
"shard": 0,
"from_node": "data-node-1",
"to_node": "data-node-2"
}
},
{
"allocate_replica": {
"index": "logs-2026.04.08",
"shard": 1,
"node": "data-node-3"
}
}
]
}'
# シャード割り当てのフィルタリング
curl -X PUT "localhost:9200/logs-2026.04.08/_settings" -H 'Content-Type: application/json' -d'
{
"index.routing.allocation.require.data": "hot",
"index.routing.allocation.exclude._name": "data-node-old"
}'
7.3 クラスタ設定
# クラスタ設定の確認
curl -X GET "localhost:9200/_cluster/settings?include_defaults=true&pretty"
# 動的クラスタ設定の変更
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.enable": "all",
"cluster.routing.allocation.cluster_concurrent_rebalance": 2,
"cluster.routing.allocation.node_concurrent_recoveries": 2,
"cluster.routing.allocation.node_initial_primaries_recoveries": 4,
"cluster.routing.allocation.disk.threshold_enabled": true,
"cluster.routing.allocation.disk.watermark.low": "85%",
"cluster.routing.allocation.disk.watermark.high": "90%",
"cluster.routing.allocation.disk.watermark.flood_stage": "95%",
"indices.recovery.max_bytes_per_sec": "100mb"
},
"transient": {
"cluster.routing.allocation.enable": "primaries"
}
}'
7.4 Hot/Warm/Cold アーキテクチャ
+------------------------------------------------------------------+
| データライフサイクル |
| |
| 書き込み -> Hot Tier -> Warm Tier -> Cold Tier -> Frozen -> 削除 |
| |
| +------------+ +--------------+ +-------------+ +----------+ |
| | Hot Tier | | Warm Tier | | Cold Tier | | Frozen | |
| | | | | | | | Tier | |
| | 高速SSD | | SATA SSD/HDD| | HDD | | 共有 | |
| | 最新データ | | 1-4週間前 | | 1-6ヶ月前 | | ストレージ| |
| | 読み書き可 | | 読み取り専用 | | 最小限の | | スナップ | |
| | 高CPU/RAM | | 中CPU/RAM | | リソース | | ショット | |
| +------------+ +--------------+ +-------------+ +----------+ |
+------------------------------------------------------------------+
# elasticsearch.yml - Hot ノード
node.roles: [ data_hot, data_content ]
node.name: hot-node-01
node.attr.data: hot
# elasticsearch.yml - Warm ノード
node.roles: [ data_warm ]
node.name: warm-node-01
node.attr.data: warm
# elasticsearch.yml - Cold ノード
node.roles: [ data_cold ]
node.name: cold-node-01
node.attr.data: cold
# elasticsearch.yml - Frozen ノード
node.roles: [ data_frozen ]
node.name: frozen-node-01
node.attr.data: frozen
7.5 スナップショットとリストア
# スナップショットリポジトリの登録(S3)
curl -X PUT "localhost:9200/_snapshot/s3-backup" -H 'Content-Type: application/json' -d'
{
"type": "s3",
"settings": {
"bucket": "es-backups-production",
"region": "ap-northeast-1",
"base_path": "elasticsearch/snapshots",
"compress": true,
"server_side_encryption": true,
"max_snapshot_bytes_per_sec": "200mb",
"max_restore_bytes_per_sec": "200mb"
}
}'
# スナップショットリポジトリの登録(共有ファイルシステム)
curl -X PUT "localhost:9200/_snapshot/nfs-backup" -H 'Content-Type: application/json' -d'
{
"type": "fs",
"settings": {
"location": "/mnt/backups/elasticsearch",
"compress": true,
"max_snapshot_bytes_per_sec": "100mb"
}
}'
# スナップショットの作成
curl -X PUT "localhost:9200/_snapshot/s3-backup/snapshot-2026-04-08?wait_for_completion=false" -H 'Content-Type: application/json' -d'
{
"indices": "logs-*,metrics-*",
"ignore_unavailable": true,
"include_global_state": false,
"metadata": {
"taken_by": "sre-team",
"reason": "daily backup"
}
}'
# スナップショットの状態確認
curl -X GET "localhost:9200/_snapshot/s3-backup/snapshot-2026-04-08/_status?pretty"
# スナップショット一覧
curl -X GET "localhost:9200/_snapshot/s3-backup/_all?pretty"
# スナップショットからのリストア
curl -X POST "localhost:9200/_snapshot/s3-backup/snapshot-2026-04-08/_restore" -H 'Content-Type: application/json' -d'
{
"indices": "logs-2026.04.07",
"ignore_unavailable": true,
"include_global_state": false,
"rename_pattern": "(.+)",
"rename_replacement": "restored-$1",
"index_settings": {
"index.number_of_replicas": 0
}
}'
# SLM(Snapshot Lifecycle Management)ポリシーの作成
curl -X PUT "localhost:9200/_slm/policy/daily-snapshots" -H 'Content-Type: application/json' -d'
{
"schedule": "0 0 1 * * ?",
"name": "<daily-snapshot-{now/d}>",
"repository": "s3-backup",
"config": {
"indices": ["logs-*", "metrics-*"],
"ignore_unavailable": true,
"include_global_state": false
},
"retention": {
"expire_after": "30d",
"min_count": 5,
"max_count": 50
}
}'
# SLM ポリシーの手動実行
curl -X POST "localhost:9200/_slm/policy/daily-snapshots/_execute?pretty"
7.6 リバランスの制御
# メンテナンス時のシャード割り当ての無効化
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.enable": "primaries"
}
}'
# メンテナンス後の復旧
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.enable": "all"
}
}'
# ノードのグレースフルシャットダウン前の排出
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"transient": {
"cluster.routing.allocation.exclude._ip": "10.0.1.100"
}
}'
第8章: セキュリティ
8.1 認証(Authentication)
# elasticsearch.yml - セキュリティ基本設定
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
# ネイティブレルム(内蔵ユーザーデータベース)
xpack.security.authc.realms.native.native1:
order: 0
# LDAP レルム
xpack.security.authc.realms.ldap.ldap1:
order: 1
url: "ldaps://ldap.example.com:636"
bind_dn: "cn=elasticsearch,ou=services,dc=example,dc=com"
user_search:
base_dn: "ou=users,dc=example,dc=com"
filter: "(uid={0})"
group_search:
base_dn: "ou=groups,dc=example,dc=com"
ssl:
certificate_authorities: ["/etc/elasticsearch/certs/ca.crt"]
verification_mode: full
unmapped_groups_as_roles: false
# SAML レルム
xpack.security.authc.realms.saml.saml1:
order: 2
idp.metadata.path: "/etc/elasticsearch/saml/idp-metadata.xml"
idp.entity_id: "https://idp.example.com/"
sp.entity_id: "https://kibana.example.com/"
sp.acs: "https://kibana.example.com/api/security/saml/callback"
attributes.principal: "nameid"
attributes.groups: "groups"
# API キー認証
xpack.security.authc.api_key.enabled: true
# 組み込みユーザーのパスワード設定
bin/elasticsearch-setup-passwords interactive
# ユーザーの作成
curl -X POST "localhost:9200/_security/user/sre_engineer" -H 'Content-Type: application/json' -d'
{
"password": "SecureP@ssw0rd!",
"roles": ["sre_role", "kibana_user"],
"full_name": "SRE Engineer",
"email": "sre@example.com",
"metadata": {
"team": "platform"
}
}'
# API キーの作成
curl -X POST "localhost:9200/_security/api_key" -H 'Content-Type: application/json' -d'
{
"name": "monitoring-api-key",
"expiration": "30d",
"role_descriptors": {
"monitoring_role": {
"cluster": ["monitor"],
"indices": [
{
"names": ["logs-*", "metrics-*"],
"privileges": ["read", "view_index_metadata"]
}
]
}
},
"metadata": {
"application": "monitoring-system",
"created_by": "sre-team"
}
}'
8.2 認可(Authorization / RBAC)
# カスタムロールの作成
curl -X PUT "localhost:9200/_security/role/sre_role" -H 'Content-Type: application/json' -d'
{
"cluster": [
"monitor",
"manage_index_templates",
"manage_ilm",
"manage_pipeline",
"cluster:admin/snapshot/create",
"cluster:admin/snapshot/status",
"cluster:admin/repository/get"
],
"indices": [
{
"names": ["logs-*", "metrics-*", "traces-*"],
"privileges": ["read", "view_index_metadata", "manage"],
"allow_restricted_indices": false
},
{
"names": [".kibana*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": ["feature_discover.all", "feature_dashboard.all", "feature_visualize.read"],
"resources": ["space:default", "space:monitoring"]
}
],
"run_as": [],
"metadata": {
"description": "SREチーム用のロール"
}
}'
# 読み取り専用ロール
curl -X PUT "localhost:9200/_security/role/readonly_role" -H 'Content-Type: application/json' -d'
{
"cluster": ["monitor"],
"indices": [
{
"names": ["logs-*"],
"privileges": ["read"],
"query": {
"bool": {
"filter": [
{ "term": { "environment": "production" } }
]
}
},
"field_security": {
"grant": ["@timestamp", "service_name", "log_level", "message", "host.name"],
"except": ["password", "secret", "token"]
}
}
]
}'
8.3 TLS/SSL の設定
# elasticsearch.yml - TLS 設定
# トランスポート層(ノード間通信)
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: full
xpack.security.transport.ssl.keystore.path: certs/transport.p12
xpack.security.transport.ssl.truststore.path: certs/transport.p12
# HTTP 層(クライアント通信)
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12
xpack.security.http.ssl.truststore.path: certs/http.p12
# 証明書の設定(PEM形式の場合)
# xpack.security.transport.ssl.key: certs/node.key
# xpack.security.transport.ssl.certificate: certs/node.crt
# xpack.security.transport.ssl.certificate_authorities: ["certs/ca.crt"]
# 証明書の生成(elasticsearch-certutil)
bin/elasticsearch-certutil ca --out elastic-stack-ca.p12 --pass ""
bin/elasticsearch-certutil cert \
--ca elastic-stack-ca.p12 \
--ca-pass "" \
--out elastic-certificates.p12 \
--pass "" \
--dns "es-node-01,es-node-02,es-node-03" \
--ip "10.0.1.1,10.0.1.2,10.0.1.3"
# HTTP 証明書の生成
bin/elasticsearch-certutil http
8.4 監査ログ
# elasticsearch.yml - 監査ログ設定
xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include:
- access_denied
- access_granted
- anonymous_access_denied
- authentication_failed
- authentication_success
- connection_denied
- tampered_request
- run_as_denied
- run_as_granted
- security_config_change
xpack.security.audit.logfile.events.exclude:
- system_access_granted
xpack.security.audit.logfile.events.emit_request_body: false
8.5 フィールドレベル・ドキュメントレベルセキュリティ
# ドキュメントレベルセキュリティ(DLS)
# 特定の条件に一致するドキュメントのみアクセス可能
curl -X PUT "localhost:9200/_security/role/team_a_role" -H 'Content-Type: application/json' -d'
{
"indices": [
{
"names": ["logs-*"],
"privileges": ["read"],
"query": {
"term": { "team": "team-a" }
}
}
]
}'
# フィールドレベルセキュリティ(FLS)
# 特定のフィールドのみアクセス可能
curl -X PUT "localhost:9200/_security/role/limited_fields_role" -H 'Content-Type: application/json' -d'
{
"indices": [
{
"names": ["customer-*"],
"privileges": ["read"],
"field_security": {
"grant": ["customer_id", "order_date", "total_amount"],
"except": ["credit_card_number", "ssn", "password_hash"]
}
}
]
}'
第9章: パフォーマンスチューニング
9.1 インデックスパフォーマンス
9.1.1 Bulk インデックスの最適化
# リフレッシュインターバルの調整(大量インポート時)
curl -X PUT "localhost:9200/logs-*/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"refresh_interval": "30s",
"number_of_replicas": 0,
"translog.durability": "async",
"translog.sync_interval": "30s",
"translog.flush_threshold_size": "1gb"
}
}'
# 大量インポート完了後、設定を戻す
curl -X PUT "localhost:9200/logs-*/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"refresh_interval": "1s",
"number_of_replicas": 1,
"translog.durability": "request"
}
}'
9.1.2 マッピングの最適化
# 不要なフィールドのインデックスを無効化
curl -X PUT "localhost:9200/optimized-logs" -H 'Content-Type: application/json' -d'
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": { "type": "date" },
"message": {
"type": "text",
"norms": false
},
"log_level": {
"type": "keyword",
"doc_values": true
},
"stack_trace": {
"type": "text",
"index": false,
"doc_values": false
},
"raw_data": {
"type": "object",
"enabled": false
},
"request_id": {
"type": "keyword",
"doc_values": false,
"index": true
}
},
"_source": {
"excludes": ["raw_data_binary"]
}
}
}'
9.2 検索パフォーマンス
9.2.1 フィルターコンテキストの活用
# 悪い例: must でフィルタリング(スコアリングが不要なのに計算される)
# "must": [{ "term": { "status": "active" } }]
# 良い例: filter を使用(キャッシュされ、スコアリングなし)
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "match": { "message": "error timeout" } }
],
"filter": [
{ "term": { "service_name": "api-gateway" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } },
{ "terms": { "status_code": [500, 502, 503] } }
]
}
}
}'
9.2.2 検索プロファイリング
# プロファイル API で検索のボトルネックを特定
curl -X GET "localhost:9200/logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"profile": true,
"query": {
"bool": {
"must": [
{ "match": { "message": "error" } }
],
"filter": [
{ "range": { "@timestamp": { "gte": "now-24h" } } }
]
}
},
"size": 10
}'
9.3 ハードウェアサイジング
+------------------------------------------------------------------+
| ハードウェアサイジングガイドライン |
+------------------------------------------------------------------+
| 役割 | CPU | RAM | ストレージ | ネットワーク |
+------------------------------------------------------------------+
| Master | 2-4コア | 4-8 GB | 低速SSD 50GB | 1 Gbps |
| (3ノード推奨) | | | | |
+------------------------------------------------------------------+
| Data (Hot) | 8-16コア | 32-64 GB | NVMe SSD | 10 Gbps |
| | | | 1-4 TB | |
+------------------------------------------------------------------+
| Data (Warm) | 4-8コア | 16-32 GB | SATA SSD/HDD | 1-10 Gbps|
| | | | 4-8 TB | |
+------------------------------------------------------------------+
| Data (Cold) | 2-4コア | 8-16 GB | HDD | 1 Gbps |
| | | | 8-16 TB | |
+------------------------------------------------------------------+
| Ingest | 4-8コア | 8-16 GB | SSD 100GB | 10 Gbps |
+------------------------------------------------------------------+
| Coordinating | 4-8コア | 16-32 GB | SSD 100GB | 10 Gbps |
+------------------------------------------------------------------+
| ML | 8-16コア | 16-64 GB | SSD 200GB | 10 Gbps |
+------------------------------------------------------------------+
一般的なガイドライン:
- RAM: JVM ヒープに50%(最大31GB)、残り50%はOSファイルキャッシュ
- ディスク: 1シャードあたり10-50GB(推奨上限50GB)
- シャード数: ノード数 × 1-3(ホットデータ)
- データノードあたりのシャード数: 600-1000以下
9.4 JVM / ヒープ設定
# jvm.options - JVM ヒープ設定
# /etc/elasticsearch/jvm.options.d/heap.options
# ヒープサイズ(物理メモリの50%、最大31GBに設定)
-Xms16g
-Xmx16g
# 重要: Xms と Xmx は同じ値にする
# 最大31GB(Compressed Oops の閾値を超えない)
# 残りのメモリはファイルシステムキャッシュに使用される
# elasticsearch.yml - メモリ関連設定
# メモリロック(スワップ防止)
bootstrap.memory_lock: true
# /etc/systemd/system/elasticsearch.service.d/override.conf
# [Service]
# LimitMEMLOCK=infinity
# メモリロックの確認
curl -X GET "localhost:9200/_nodes?filter_path=**.mlockall&pretty"
# JVM のヒープ使用量確認
curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"
9.5 インデックス設定の最適化
# マージポリシーの設定
curl -X PUT "localhost:9200/logs-*/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"merge.policy.max_merge_at_once": 10,
"merge.policy.max_merged_segment": "5gb",
"merge.policy.segments_per_tier": 10,
"merge.scheduler.max_thread_count": 1
}
}'
# フォースマージ(読み取り専用インデックスに対して)
curl -X POST "localhost:9200/logs-2026.04.07/_forcemerge?max_num_segments=1"
9.6 サーキットブレーカー
# elasticsearch.yml - サーキットブレーカー設定
# 親サーキットブレーカー(全体のメモリ使用量制限)
indices.breaker.total.limit: 70%
# フィールドデータサーキットブレーカー
indices.breaker.fielddata.limit: 40%
indices.breaker.fielddata.overhead: 1.03
# リクエストサーキットブレーカー
indices.breaker.request.limit: 60%
indices.breaker.request.overhead: 1
# インフライトリクエストサーキットブレーカー
network.breaker.inflight_requests.limit: 100%
network.breaker.inflight_requests.overhead: 2
# サーキットブレーカーの状態確認
curl -X GET "localhost:9200/_nodes/stats/breaker?pretty"
9.7 Fielddata と Doc Values
+------------------------------------------------------------------+
| Fielddata vs Doc Values |
+------------------------------------------------------------------+
| 特性 | Fielddata | Doc Values |
+------------------------------------------------------------------+
| ストレージ | ヒープメモリ | ディスク(OS キャッシュ) |
| 対象 | text フィールド | keyword, 数値, 日付等 |
| 構築タイミング| クエリ時(遅延ロード) | インデックス時 |
| メモリ圧力 | 高(OOM リスク) | 低 |
| 推奨 | 避けるべき | デフォルトで有効 |
+------------------------------------------------------------------+
推奨: text フィールドでの集約には keyword サブフィールドを使用する
# Fielddata の使用状況確認
curl -X GET "localhost:9200/_nodes/stats/indices/fielddata?fields=*&pretty"
# Fielddata キャッシュのクリア
curl -X POST "localhost:9200/_cache/clear?fielddata=true"
# クエリキャッシュのクリア
curl -X POST "localhost:9200/_cache/clear?query=true"
# リクエストキャッシュのクリア
curl -X POST "localhost:9200/_cache/clear?request=true"
9.8 スレッドプール
# スレッドプールの状態確認
curl -X GET "localhost:9200/_cat/thread_pool?v&h=name,active,queue,rejected,completed&pretty"
# スレッドプールの詳細情報
curl -X GET "localhost:9200/_nodes/stats/thread_pool?pretty"
# elasticsearch.yml - スレッドプール設定
# 検索スレッドプール
thread_pool.search.size: 13 # デフォルト: int((# of allocated processors * 3) / 2) + 1
thread_pool.search.queue_size: 1000
# 書き込みスレッドプール
thread_pool.write.size: 8 # デフォルト: # of allocated processors
thread_pool.write.queue_size: 10000
第10章: モニタリングとオブザーバビリティ
10.1 Cat API
Cat API は、クラスタの状態をテーブル形式で簡潔に表示する。
# ノード一覧
curl -X GET "localhost:9200/_cat/nodes?v&h=name,ip,role,heap.percent,ram.percent,cpu,load_1m,disk.used_percent,node.role&pretty"
# インデックス一覧
curl -X GET "localhost:9200/_cat/indices?v&h=index,health,status,pri,rep,docs.count,store.size&s=store.size:desc&pretty"
# シャードの割り当て状況
curl -X GET "localhost:9200/_cat/shards?v&h=index,shard,prirep,state,docs,store,node&s=store:desc&pretty"
# 未割り当てシャード
curl -X GET "localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state&pretty" | grep UNASSIGNED
# ノードのディスク使用量
curl -X GET "localhost:9200/_cat/allocation?v&pretty"
# セグメント情報
curl -X GET "localhost:9200/_cat/segments/logs-*?v&h=index,shard,segment,docs.count,size,size.memory&pretty"
# ペンディングタスク
curl -X GET "localhost:9200/_cat/pending_tasks?v&pretty"
# リカバリ状況
curl -X GET "localhost:9200/_cat/recovery?v&active_only=true&pretty"
# テンプレート一覧
curl -X GET "localhost:9200/_cat/templates?v&pretty"
# プラグイン一覧
curl -X GET "localhost:9200/_cat/plugins?v&pretty"
# スレッドプール
curl -X GET "localhost:9200/_cat/thread_pool?v&h=node_name,name,active,queue,rejected&pretty"
10.2 クラスタ統計
# クラスタ統計
curl -X GET "localhost:9200/_cluster/stats?pretty"
# クラスタヘルス
curl -X GET "localhost:9200/_cluster/health?pretty"
# ノード統計(詳細)
curl -X GET "localhost:9200/_nodes/stats?pretty"
# 特定のメトリクスのみ取得
curl -X GET "localhost:9200/_nodes/stats/jvm,os,fs,indices?pretty"
# ノードのホットスレッド(パフォーマンス問題のデバッグ)
curl -X GET "localhost:9200/_nodes/hot_threads?threads=5&interval=500ms"
10.3 インデックス統計
# インデックスの統計情報
curl -X GET "localhost:9200/logs-*/_stats?pretty"
# 特定のメトリクス
curl -X GET "localhost:9200/logs-*/_stats/indexing,search,merge?pretty"
# インデックスのリカバリ状況
curl -X GET "localhost:9200/logs-*/_recovery?pretty&active_only=true"
# インデックスのセグメント情報
curl -X GET "localhost:9200/logs-*/_segments?pretty"
10.4 スローログ
# 検索スローログの設定
curl -X PUT "localhost:9200/logs-*/_settings" -H 'Content-Type: application/json' -d'
{
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.query.info": "5s",
"index.search.slowlog.threshold.query.debug": "2s",
"index.search.slowlog.threshold.query.trace": "500ms",
"index.search.slowlog.threshold.fetch.warn": "1s",
"index.search.slowlog.threshold.fetch.info": "800ms",
"index.search.slowlog.threshold.fetch.debug": "500ms",
"index.search.slowlog.threshold.fetch.trace": "200ms",
"index.search.slowlog.level": "info"
}'
# インデックススローログの設定
curl -X PUT "localhost:9200/logs-*/_settings" -H 'Content-Type: application/json' -d'
{
"index.indexing.slowlog.threshold.index.warn": "10s",
"index.indexing.slowlog.threshold.index.info": "5s",
"index.indexing.slowlog.threshold.index.debug": "2s",
"index.indexing.slowlog.threshold.index.trace": "500ms",
"index.indexing.slowlog.level": "info",
"index.indexing.slowlog.source": "1000"
}'
# log4j2.properties - スローログの出力設定
# /etc/elasticsearch/log4j2.properties
appender.index_search_slowlog_rolling.type = RollingFile
appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling
appender.index_search_slowlog_rolling.fileName = ${sys:es.logs.base_path}/${sys:es.logs.cluster_name}_index_search_slowlog.json
appender.index_search_slowlog_rolling.layout.type = JsonLayout
appender.index_search_slowlog_rolling.policies.type = Policies
appender.index_search_slowlog_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.index_search_slowlog_rolling.policies.size.size = 1GB
appender.index_search_slowlog_rolling.strategy.type = DefaultRolloverStrategy
appender.index_search_slowlog_rolling.strategy.max = 10
10.5 モニタリングダッシュボード用のクエリ例
# クラスタの主要メトリクスを一括取得するスクリプト
# #!/bin/bash
# ES_HOST="localhost:9200"
#
# echo "=== Cluster Health ==="
# curl -s "$ES_HOST/_cluster/health" | jq '.'
#
# echo "=== Node Disk Usage ==="
# curl -s "$ES_HOST/_cat/allocation?v"
#
# echo "=== JVM Heap Usage ==="
# curl -s "$ES_HOST/_cat/nodes?v&h=name,heap.percent,ram.percent,cpu"
#
# echo "=== Pending Tasks ==="
# curl -s "$ES_HOST/_cat/pending_tasks?v"
#
# echo "=== Thread Pool Rejections ==="
# curl -s "$ES_HOST/_cat/thread_pool?v&h=node_name,name,rejected" | grep -v "^$" | awk '$3 > 0'
#
# echo "=== Unassigned Shards ==="
# curl -s "$ES_HOST/_cat/shards?v" | grep UNASSIGNED
#
# echo "=== Index Stats ==="
# curl -s "$ES_HOST/_cat/indices?v&h=index,health,pri,rep,docs.count,store.size&s=store.size:desc" | head -20
# タスク管理 API
curl -X GET "localhost:9200/_tasks?detailed=true&group_by=parents&pretty"
# 長時間実行中のタスクを確認
curl -X GET "localhost:9200/_tasks?actions=*search*&detailed=true&pretty"
# タスクのキャンセル
curl -X POST "localhost:9200/_tasks/<task_id>/_cancel"
第11章: Kibana との統合
11.1 Kibana の主要機能
+------------------------------------------------------------------+
| Kibana |
| |
| +------------------+ +------------------+ +-----------------+ |
| | Discover | | Dashboard | | Lens | |
| | ログの検索/閲覧 | | ダッシュボード | | 可視化ビルダー | |
| +------------------+ +------------------+ +-----------------+ |
| |
| +------------------+ +------------------+ +-----------------+ |
| | Alerting | | Dev Tools | | Stack Monitoring| |
| | アラート管理 | | Console/Profiler | | クラスタ監視 | |
| +------------------+ +------------------+ +-----------------+ |
| |
| +------------------+ +------------------+ +-----------------+ |
| | Maps | | Canvas | | Machine Learning| |
| | 地理空間可視化 | | プレゼンテーション| | 異常検知 | |
| +------------------+ +------------------+ +-----------------+ |
+------------------------------------------------------------------+
11.1.1 Kibana の設定
# kibana.yml - 基本設定
server.port: 5601
server.host: "0.0.0.0"
server.name: "kibana-production"
server.basePath: "/kibana"
server.rewriteBasePath: true
# Elasticsearch 接続
elasticsearch.hosts: ["https://es-node-01:9200", "https://es-node-02:9200"]
elasticsearch.username: "kibana_system"
elasticsearch.password: "${KIBANA_ES_PASSWORD}"
elasticsearch.ssl.certificateAuthorities: ["/etc/kibana/certs/ca.crt"]
elasticsearch.ssl.verificationMode: full
# セキュリティ
xpack.security.encryptionKey: "something_at_least_32_characters"
xpack.encryptedSavedObjects.encryptionKey: "something_at_least_32_characters"
xpack.reporting.encryptionKey: "something_at_least_32_characters"
# ロギング
logging.root.level: info
logging.appenders.file.type: file
logging.appenders.file.fileName: /var/log/kibana/kibana.log
logging.appenders.file.layout.type: json
# アラート設定
xpack.actions.email:
host: 'smtp.example.com'
port: 587
secure: true
from: 'kibana-alerts@example.com'
11.1.2 アラートルール(Kibana Alerting)
# Kibana API を使ったアラートルールの作成
curl -X POST "localhost:5601/api/alerting/rule" \
-H 'kbn-xsrf: true' \
-H 'Content-Type: application/json' \
-u "admin:password" -d'
{
"name": "High Error Rate Alert",
"rule_type_id": ".es-query",
"consumer": "alerts",
"schedule": { "interval": "5m" },
"params": {
"index": ["logs-*"],
"timeField": "@timestamp",
"esQuery": "{\"bool\":{\"filter\":[{\"term\":{\"log_level\":\"ERROR\"}},{\"range\":{\"@timestamp\":{\"gte\":\"now-5m\"}}}]}}",
"threshold": [100],
"thresholdComparator": ">",
"timeWindowSize": 5,
"timeWindowUnit": "m",
"size": 100
},
"actions": [
{
"group": "query matched",
"id": "<slack-connector-id>",
"params": {
"message": "🚨 High error rate detected: {{context.hits}} errors in the last 5 minutes"
}
},
{
"group": "query matched",
"id": "<email-connector-id>",
"params": {
"to": ["sre-team@example.com"],
"subject": "Alert: High Error Rate",
"message": "Error count: {{context.hits}} in the last 5 minutes.\n\nCheck Kibana dashboard: https://kibana.example.com/dashboard/error-overview"
}
}
],
"tags": ["production", "sre", "error-monitoring"]
}'
第12章: クロスクラスタ検索とレプリケーション
12.1 クロスクラスタ検索(CCS)
複数の Elasticsearch クラスタにまたがって検索を実行する機能。
# リモートクラスタの登録
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster": {
"remote": {
"cluster_us": {
"seeds": ["es-us-01:9300", "es-us-02:9300"],
"transport.compress": true,
"skip_unavailable": true
},
"cluster_eu": {
"seeds": ["es-eu-01:9300", "es-eu-02:9300"],
"transport.compress": true,
"skip_unavailable": true
},
"cluster_ap": {
"seeds": ["es-ap-01:9300", "es-ap-02:9300"],
"transport.compress": true,
"skip_unavailable": false
}
}
}
}
}'
# Proxy モードでのリモートクラスタ登録
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster": {
"remote": {
"cluster_us": {
"mode": "proxy",
"proxy_address": "es-proxy-us:9443",
"server_name": "cluster-us.example.com",
"num_proxy_sockets_per_connection": 18
}
}
}
}
}'
# リモートクラスタの接続状態確認
curl -X GET "localhost:9200/_remote/info?pretty"
# クロスクラスタ検索の実行
curl -X GET "localhost:9200/logs-*,cluster_us:logs-*,cluster_eu:logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "match": { "message": "critical error" } }
],
"filter": [
{ "range": { "@timestamp": { "gte": "now-1h" } } }
]
}
},
"sort": [{ "@timestamp": "desc" }],
"size": 50
}'
# クロスクラスタ検索で特定クラスタのインデックスのみ対象
curl -X GET "localhost:9200/cluster_us:logs-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
},
"size": 10
}'
12.2 クロスクラスタレプリケーション(CCR)
リーダーインデックスの変更をフォロワーインデックスに自動的にレプリケーションする機能。
# フォロワークラスタでの設定
# フォロワーインデックスの作成
curl -X PUT "localhost:9200/logs-follower" -H 'Content-Type: application/json' -d'
{
"remote_cluster": "cluster_us",
"leader_index": "logs-production"
}'
# 自動フォローパターンの設定
curl -X PUT "localhost:9200/_ccr/auto_follow/logs-pattern" -H 'Content-Type: application/json' -d'
{
"remote_cluster": "cluster_us",
"leader_index_patterns": ["logs-*"],
"follow_index_pattern": "{{leader_index}}-replicated",
"settings": {
"index.number_of_replicas": 0
},
"max_read_request_operation_count": 5120,
"max_outstanding_read_requests": 12,
"max_read_request_size": "32mb",
"max_write_request_operation_count": 5120,
"max_write_request_size": "9223372036854775807b",
"max_outstanding_write_requests": 9,
"max_write_buffer_count": 2147483647,
"max_write_buffer_size": "512mb",
"max_retry_delay": "500ms",
"read_poll_timeout": "1m"
}'
# CCR の状態確認
curl -X GET "localhost:9200/logs-follower/_ccr/stats?pretty"
# フォロワーインデックスの一時停止
curl -X POST "localhost:9200/logs-follower/_ccr/pause_follow"
# フォロワーインデックスの再開
curl -X POST "localhost:9200/logs-follower/_ccr/resume_follow" -H 'Content-Type: application/json' -d'{}'
# フォロワーを通常のインデックスに昇格(DR時)
curl -X POST "localhost:9200/logs-follower/_ccr/unfollow"
+------------------------------------------------------------------+
| クロスクラスタレプリケーション |
| |
| リーダークラスタ (US) フォロワークラスタ (JP) |
| +--------------------+ +--------------------+ |
| | logs-production | ---> | logs-production | |
| | (読み書き可能) | CCR | -replicated | |
| +--------------------+ | (読み取り専用) | |
| | metrics-production | ---> +--------------------+ |
| | (読み書き可能) | CCR | metrics-production | |
| +--------------------+ | -replicated | |
| | (読み取り専用) | |
| 変更はリーダーから +--------------------+ |
| フォロワーへ自動同期 |
+------------------------------------------------------------------+
第13章: SRE のためのベストプラクティス
13.1 キャパシティプランニング
13.1.1 ストレージ計算
必要ストレージの計算:
1日のデータ量: 100 GB/日
レプリカ係数: × 2 (プライマリ + 1レプリカ)
インデックスオーバーヘッド: × 1.1 (10%の追加)
保持期間: × 30日
必要ストレージ = 100 × 2 × 1.1 × 30 = 6,600 GB (≈ 6.4 TB)
安全マージン (20%): × 1.2
合計必要ストレージ: ≈ 7.9 TB
ノード数計算:
- 各ノードの利用可能ストレージ: 2 TB
- 必要ノード数: 7.9 TB / 2 TB ≈ 4 ノード(切り上げ)
シャード計算:
- 推奨シャードサイズ: 10-50 GB
- 1日のプライマリデータ: 100 GB
- 推奨シャード数/日: 100 GB / 25 GB = 4 シャード
13.1.2 シャード数の見積もり
# シャードのサイズと数を確認
curl -X GET "localhost:9200/_cat/shards?v&h=index,shard,prirep,store,docs&s=store:desc&pretty" | head -50
# データノードあたりのシャード数を確認
curl -X GET "localhost:9200/_cat/allocation?v&pretty"
# 推奨事項:
# - 1シャードあたり: 10-50 GB
# - データノードあたり: 600シャード以下
# - 1 GBのヒープメモリあたり: 20シャード以下
# - クラスタ全体: シャード数 × 20MB のヒープメモリが必要
13.2 モニタリング戦略
13.2.1 重要なアラート条件
# アラート設定の推奨値
クラスタヘルス:
- クラスタステータスが Yellow: WARNING
- クラスタステータスが Red: CRITICAL
ディスク使用量:
- ノードのディスク使用量 > 75%: WARNING
- ノードのディスク使用量 > 85%: CRITICAL
- ノードのディスク使用量 > 90%: EMERGENCY(書き込みブロックの可能性)
JVM ヒープ:
- ヒープ使用量 > 75%: WARNING
- ヒープ使用量 > 85%: CRITICAL
- Old GC 時間 > 5秒/分: WARNING
- Old GC 時間 > 15秒/分: CRITICAL
CPU:
- CPU 使用率 > 80%(5分平均): WARNING
- CPU 使用率 > 95%(5分平均): CRITICAL
検索レイテンシ:
- P95 検索レイテンシ > 2秒: WARNING
- P95 検索レイテンシ > 10秒: CRITICAL
インデックスレイテンシ:
- P95 インデックスレイテンシ > 1秒: WARNING
- P95 インデックスレイテンシ > 5秒: CRITICAL
スレッドプール:
- search rejected > 0: WARNING
- write rejected > 0: WARNING
- bulk rejected > 0: CRITICAL
シャード:
- 未割り当てシャード > 0: WARNING(5分以上継続)
- 初期化中シャード > 0: INFO
- リロケーティングシャード > 10: WARNING
13.2.2 Prometheus + Grafana でのモニタリング
# elasticsearch-exporter の設定(Prometheus 用)
# docker-compose.yml
version: '3'
services:
elasticsearch-exporter:
image: quay.io/prometheuscommunity/elasticsearch-exporter:latest
command:
- '--es.uri=https://elasticsearch:9200'
- '--es.all'
- '--es.indices'
- '--es.indices_settings'
- '--es.indices_mappings'
- '--es.shards'
- '--es.snapshots'
- '--es.timeout=30s'
- '--es.ssl-skip-verify'
- '--es.ca=/certs/ca.crt'
environment:
ES_USERNAME: monitoring_user
ES_PASSWORD: ${MONITORING_PASSWORD}
ports:
- "9114:9114"
13.3 バックアップ戦略
+------------------------------------------------------------------+
| バックアップ戦略 |
+------------------------------------------------------------------+
| レベル | 頻度 | 保持期間 | 方法 |
+------------------------------------------------------------------+
| 日次 | 毎日 01:00 | 30日 | SLM (S3スナップショット) |
| 週次 | 毎週日曜 | 90日 | SLM (完全スナップショット) |
| 月次 | 毎月1日 | 1年 | SLM (完全スナップショット) |
+------------------------------------------------------------------+
| DR テスト | 四半期 | - | リストアテストの実施 |
+------------------------------------------------------------------+
# バックアップの検証スクリプト
# #!/bin/bash
# set -e
#
# ES_HOST="localhost:9200"
# REPO="s3-backup"
#
# echo "最新のスナップショットを確認..."
# LATEST_SNAPSHOT=$(curl -s "$ES_HOST/_snapshot/$REPO/_all" | \
# jq -r '.snapshots | sort_by(.start_time) | last | .snapshot')
#
# echo "最新スナップショット: $LATEST_SNAPSHOT"
#
# SNAPSHOT_STATE=$(curl -s "$ES_HOST/_snapshot/$REPO/$LATEST_SNAPSHOT" | \
# jq -r '.snapshots[0].state')
#
# if [ "$SNAPSHOT_STATE" != "SUCCESS" ]; then
# echo "ERROR: スナップショットの状態が異常: $SNAPSHOT_STATE"
# exit 1
# fi
#
# echo "スナップショットの状態: $SNAPSHOT_STATE"
#
# # リストアテスト(テスト用インデックスのみ)
# echo "リストアテストを実行..."
# curl -X POST "$ES_HOST/_snapshot/$REPO/$LATEST_SNAPSHOT/_restore" \
# -H 'Content-Type: application/json' -d'
# {
# "indices": "logs-2026.04.07",
# "rename_pattern": "(.+)",
# "rename_replacement": "restore-test-$1",
# "index_settings": {
# "index.number_of_replicas": 0
# }
# }'
#
# # リストア完了を待機
# sleep 30
#
# # リストアされたインデックスのドキュメント数を確認
# DOC_COUNT=$(curl -s "$ES_HOST/restore-test-logs-2026.04.07/_count" | jq '.count')
# echo "リストアされたドキュメント数: $DOC_COUNT"
#
# # テストインデックスの削除
# curl -X DELETE "$ES_HOST/restore-test-logs-2026.04.07"
#
# echo "バックアップ検証完了"
13.4 障害対応ランブック
13.4.1 クラスタが Red の場合
# 1. 未割り当てシャードの確認
curl -X GET "localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason" | grep UNASSIGNED
# 2. 割り当て失敗の原因を特定
curl -X GET "localhost:9200/_cluster/allocation/explain?pretty"
# 3. ノードの状態確認
curl -X GET "localhost:9200/_cat/nodes?v&h=name,ip,role,heap.percent,ram.percent,cpu,disk.used_percent"
# 4. ディスクスペースの確認
curl -X GET "localhost:9200/_cat/allocation?v"
# 5. 必要に応じてシャード割り当てをリトライ
curl -X POST "localhost:9200/_cluster/reroute?retry_failed=true"
# 6. 緊急時: 読み取り専用インデックスの解除
curl -X PUT "localhost:9200/_all/_settings" -H 'Content-Type: application/json' -d'
{
"index.blocks.read_only_allow_delete": null
}'
13.4.2 JVM ヒープ圧迫時
# 1. ヒープ使用量の確認
curl -X GET "localhost:9200/_cat/nodes?v&h=name,heap.percent,heap.max,ram.percent,cpu"
# 2. フィールドデータの使用量確認
curl -X GET "localhost:9200/_cat/fielddata?v&fields=*"
# 3. 大きなフィールドデータのクリア
curl -X POST "localhost:9200/_cache/clear?fielddata=true"
# 4. サーキットブレーカーの状態確認
curl -X GET "localhost:9200/_nodes/stats/breaker?pretty"
# 5. 長時間実行タスクのキャンセル
curl -X GET "localhost:9200/_tasks?actions=*search*&detailed=true&pretty"
13.4.3 インデックスパフォーマンス低下時
# 1. バルクキューの確認
curl -X GET "localhost:9200/_cat/thread_pool/write?v&h=node_name,active,queue,rejected"
# 2. マージの状態確認
curl -X GET "localhost:9200/_cat/nodes?v&h=name,merges.current,merges.total"
# 3. リフレッシュの負荷確認
curl -X GET "localhost:9200/_cat/indices?v&h=index,refresh.total,refresh.time"
# 4. 一時的な対策: リフレッシュインターバルの延長
curl -X PUT "localhost:9200/logs-*/_settings" -H 'Content-Type: application/json' -d'
{
"index.refresh_interval": "30s"
}'
13.5 セキュリティチェックリスト
SREセキュリティチェックリスト:
[ ] xpack.security.enabled: true が設定されている
[ ] TLS がトランスポート層と HTTP 層の両方で有効
[ ] デフォルトのパスワードが変更されている
[ ] 最小権限の原則に基づいたロールが設定されている
[ ] API キーに有効期限が設定されている
[ ] 監査ログが有効化されている
[ ] ネットワークアクセスが制限されている(ファイアウォール/セキュリティグループ)
[ ] 定期的なセキュリティパッチの適用
[ ] クラスタ間通信が暗号化されている
[ ] Kibana へのアクセスが認証/認可されている
[ ] フィールドレベル/ドキュメントレベルセキュリティが必要に応じて設定されている
[ ] バックアップが暗号化されている
[ ] 定期的なアクセスレビューが実施されている
付録
A. 便利な curl コマンド集
# クラスタ情報
curl -X GET "localhost:9200/?pretty"
# インデックスの作成確認
curl -X HEAD "localhost:9200/my-index"
# ドキュメントの取得
curl -X GET "localhost:9200/my-index/_doc/1?pretty"
# ドキュメントの更新
curl -X POST "localhost:9200/my-index/_update/1" -H 'Content-Type: application/json' -d'
{
"doc": { "status": "updated" }
}'
# ドキュメントの削除
curl -X DELETE "localhost:9200/my-index/_doc/1"
# クエリによる削除
curl -X POST "localhost:9200/logs-old/_delete_by_query" -H 'Content-Type: application/json' -d'
{
"query": {
"range": {
"@timestamp": { "lt": "now-90d" }
}
}
}'
# Reindex API
curl -X POST "localhost:9200/_reindex" -H 'Content-Type: application/json' -d'
{
"source": {
"index": "logs-old",
"query": {
"range": {
"@timestamp": { "gte": "2026-04-01" }
}
}
},
"dest": {
"index": "logs-new",
"pipeline": "logs-pipeline"
}
}'
# Update by Query
curl -X POST "localhost:9200/logs-*/_update_by_query" -H 'Content-Type: application/json' -d'
{
"query": {
"term": { "service_name": "old-service" }
},
"script": {
"source": "ctx._source.service_name = params.new_name",
"params": {
"new_name": "new-service"
}
}
}'
B. elasticsearch.yml 完全設定例
# ============================================================
# Elasticsearch プロダクション設定例
# ============================================================
# --- クラスタ設定 ---
cluster.name: production-cluster
node.name: ${HOSTNAME}
node.roles: [ data_hot, data_content ]
# --- ネットワーク設定 ---
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300
# --- ディスカバリ設定 ---
discovery.seed_hosts:
- "master-01:9300"
- "master-02:9300"
- "master-03:9300"
cluster.initial_master_nodes:
- "master-01"
- "master-02"
- "master-03"
# --- パス設定 ---
path.data: /data/elasticsearch
path.logs: /var/log/elasticsearch
# --- メモリ設定 ---
bootstrap.memory_lock: true
# --- セキュリティ設定 ---
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: full
xpack.security.transport.ssl.keystore.path: certs/transport.p12
xpack.security.transport.ssl.truststore.path: certs/transport.p12
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12
# --- モニタリング設定 ---
xpack.monitoring.collection.enabled: true
xpack.monitoring.elasticsearch.collection.enabled: true
# --- その他 ---
action.destructive_requires_name: true
indices.query.bool.max_clause_count: 4096
# --- ノード属性 ---
node.attr.data: hot
node.attr.rack: rack-1
本ドキュメントは SRE エンジニアのための Elasticsearch 包括的リファレンスガイドです。 内容は Elasticsearch 8.x 系に基づいています。 最終更新: 2026年4月8日