まったくElasticserchを触ったことがない状態で構築から色々とやって行きます。ほぼ個人の備忘録です。
実行環境
-
前提条件
- Elasticに関する理解度
- 「ELK strackって?」というページとそのリンク先Elasticsearchについてを読んだ程度です。
- 「ELK strackって?」というページとそのリンク先Elasticsearchについてを読んだ程度です。
- 検証方法
- Dockerとdocker-composeで再利用可能な環境構築を目指す。
- Elasticserchの基本の「キ」もわかってないので、先ずは動く環境を手に入れてから、あーだこうだヤリたいと思う。
- なるべく公式HPの情報をもとに手順検証する。
- 書籍は発行されたタイミングの情報に閉じている為、誤記入の訂正も最新のトレンドに対応出来てないケースが過去に多々あったので。
- Elasticに関する理解度
-
HW
- MacBook Pro(2018)
- CPU:2.9GHz 6core
- MEM:32GB(Dockerに4GB割り当て) 1
- HDD:物理
- MacBook Pro(2018)
-
SW
- MacOS Monterey(12.0.1)
- Docker desktop(3.0.3)
- Engin: 20.10.0
- Compose: 1.27.4
- elasticserch 7.16.3
-
その他、bashでのコマンドalias設定 2
- d: docker
- dc: docker-compose
環境構築
- ユーザーのHomeディレクトリに「elasticserch」ディレクトリを作成しそこで検証開始。
- 公式サイトのこのページ(Install Elasticsearch with Docker)でdocker-compose.yamlをコピペして、上記elasticserchディレクトリ配下に取得。
- とりあえずコマンド
docker-compose up
実行でコンテナ立ち上げてみたが失敗。。。- 問題点
- es01が起動しない
- 解決方法: portsの記述にクォート囲みがなかったので修正。
- contenarが母艦側ディレクトリをmountする「volumes」パラメータ設定が絶対パスとなっている。
- 解決方法: elasticserchディレクトリ配下に閉じたいので修正。
- es01が起動しない
- 問題点
- 以下、上述の問題点を修正してcontener起動が可能となったdocker-compose.yaml
version: '2.2'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.3
container_name: es01
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es02,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
# data01->./data01に修正
- ./data01:/usr/share/elasticsearch/data
ports:
# 公式コピペだとここが原因でなぜか起動しなかった(MAC環境独自の問題?原因不明)、クォート囲みに修正
- "9200:9200"
networks:
- elastic
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.3
container_name: es02
environment:
- node.name=es02
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
# 修正箇所
- ./data02:/usr/share/elasticsearch/data
networks:
- elastic
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.3
container_name: es03
environment:
- node.name=es03
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es02
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
# 修正箇所
- ./data03:/usr/share/elasticsearch/data
networks:
- elastic
# ここの表記は要否不明(別途調査)
volumes:
data01:
driver: local
data02:
driver: local
data03:
driver: local
networks:
elastic:
driver: bridge
で、上記修正後に再度docker-compose up -d
コマンドでelasticserchをバックグラウンド起動。
❯❯❯ dc up -d
Creating network "elasticserch_elastic" with driver "bridge"
Creating es03 ... done
Creating es02 ... done
Creating es01 ... done
コンテナを立ち上げたら一応docker ps
コマンドでコンテナが適切に起動したか確認。
❯❯❯ d ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
47aa9219c2cc docker.elastic.co/elasticsearch/elasticsearch:7.16.3 "/bin/tini -- /usr/l…" About a minute ago Up About a minute 9200/tcp, 9300/tcp es02
80202c1c86c7 docker.elastic.co/elasticsearch/elasticsearch:7.16.3 "/bin/tini -- /usr/l…" About a minute ago Up About a minute 0.0.0.0:9200->9200/tcp, 9300/tcp es01
b5b324cb5a30 docker.elastic.co/elasticsearch/elasticsearch:7.16.3 "/bin/tini -- /usr/l…" About a minute ago Up About a minute 9200/tcp, 9300/tcp es03
起動後に公式チュートリアルのコマンド(_cat/node
にリクエストを送信してノードが起動している事を確認)を実行。
~/elasticserch
❯❯❯ curl -X GET "localhost:9200/_cat/nodes?v=true&pretty"
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
172.19.0.2 32 97 0 0.08 0.08 0.06 cdfhilmrstw - es03
172.19.0.4 27 97 0 0.08 0.08 0.06 cdfhilmrstw * es02
172.19.0.3 46 97 0 0.08 0.08 0.06 cdfhilmrstw - es01
とりあえず、無事環境構築できた様子なので、Quick startページのサンプル「Add a single documentedit(単一のドキュメントを追加する)」を実行してみます。以下、ページの説明文をGoogle翻訳に掛けた物を引用
logs-my_app-default次のインデックス作成リクエストを送信して、データストリームに単一のログエントリを追加し ます。logs-my_app-default存在しないため、リクエストは組み込みのインデックステンプレートを使用して自動的に作成しますlogs--。
よくわからんがindexっていうのがRDBMSで言うところのテーブルらしい。で、document(RDBMSでのレコードと思われる)を追加対象となるindexが存在しない場合には自動で作成してくれる様子っぽいです。この辺はjsonベースなのでmongodbと同じなのかな?POSTデータを送信するcurlコマンドをコピペ実行してみる。
❯❯❯ curl -X POST "localhost:9200/logs-my_app-default/_doc?pretty" -H 'Content-Type: application/json' -d'
{
"@timestamp": "2099-05-06T16:21:15.000Z",
"event": {
"original": "192.0.2.42 - - [06/May/2099:16:21:15 +0000] \"GET /images/bg.jpg HTTP/1.0\" 200 24736"
}
}
'
尚、Quick startページではKibanaを使用して実行との記載があったが方法がわからないので別途調査。。。
参考までに上記curlコマンドをKibanaというGUIのツールで実行する場合、少し目に優しい構文でできるような記載でした。
# kibanaでのサンプル。HTTPメソッドと対象となるindex(/_docはお約束なのかな?)にINSERTする実データで良いらしい。
POST logs-my_app-default/_doc
{
"@timestamp": "2099-05-06T16:21:15.000Z",
"event": {
"original": "192.0.2.42 - - [06/May/2099:16:21:15 +0000] \"GET /images/bg.jpg HTTP/1.0\" 200 24736"
}
}
上記curlコマンドのレスポンス値。
# curlコマンドの戻り値
{
"_index" : ".ds-logs-my_app-default-2022.02.04-000001",
"_type" : "_doc",
"_id" : "npmIwn4BrcdMpf7_-mmB",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
戻り値をざっと確認してみると"successful"の値が1で、"failed"の値は0。この2つのパラメーターの値はゼロイチでTrue/Falseを表現しているらしく結果として成功っぽい。なにやら"index"の値(テーブル名にあたる部分)として生成された名称はds-logs-my_app-default-2022.02.04-000001
となってます。で、idが発番されたらしい。その他"version"等もあるので更新履歴なのか、はたまた楽観ロックで使うのかは別途調査が必要ですが、とりあえずはデータ挿入成功です。
お次、このdocumentを表示する方法は?こちらもQuick StartページのSearch dataをコピペ実行してみる。
❯❯❯ curl -X GET "localhost:9200/logs-my_app-default/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": { }
},
"sort": [
{
"@timestamp": "desc"
}
]
}
'
どうやらURIの第一ディレクティブに検索対象のindexを指定するらしい。以降第二ディレクティブで指定している'_search'はRESTfulの第一ディレクティブで指定したindexへのアクションの指定で_searchが検索アクションらしい。アクション名以降にクエストリンクとして渡している'pretty'は必須値ではないがJSON戻り値に成形オプション有効化を指してます(省略すると整形されない状態で戻る)。で、-dオプションで渡しているgetでのパラメータ。こちらもJSON形式でキー名称"query"で渡している値(ネストされた連想配列)のキー"match_all"の値(これも連想配列)に何も指定しないことにより、全てのdocumentを引っ張ってきているっぽい(訂正:defaultで10件指定で取得しているらしいです。SQLだとLimit/offset句が適用された状態かと)。で、キー名称"sort"の値が配列で複数のソート条件を渡せるっぽいね。これらを親の顔より見て慣れ親しんだSQLのDMLで書くとこんな感じだろうか。
SELECT * from `logs-my_app-default` LIMIT 10 OFFSET 0 order by `@timestamp` desc;
で、上記curlコマンド実行結果のレスポンス値
{
"took" : 26,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : ".ds-logs-my_app-default-2022.02.04-000001",
"_type" : "_doc",
"_id" : "npmIwn4BrcdMpf7_-mmB",
"_score" : null,
"_source" : {
"@timestamp" : "2099-05-06T16:21:15.000Z",
"event" : {
"original" : "192.0.2.42 - - [06/May/2099:16:21:15 +0000] \"GET /images/bg.jpg HTTP/1.0\" 200 24736"
}
},
"sort" : [
4081767675000
]
}
]
}
}
ステータスやhits件数等もデータ内に含まれている。RESTfulなWebAPIだとデータに付随する情報はHeaderにX-tortal-count
やLink
等で持たせろとかWebAPI設計のベストプラクティスで紹介されていた気がするが、httpベースでの用途だけではないから良いのかな?で、データは連想配列第一階層の'hits'Objectの中に同名称'hits'配列があり、この配列内にElasticserchのdocument毎にObjectとして格納される形かな?なんとなくJSONレスポンスの設計をSwaggerに貼ったら設計上良くない作りだと指摘されそうな構成ですが、まぁなんとなくレスポンス内容は掴めました。
一応複数データ挿入もサンプルがあったので実行。endpointのアクション名は'_balk'で、改行で区切られたJSON(NDJSON)というらしい。各データの終端記号は(\n)で、最後の行を含め(\n)終わる必要がありとの事。
curl -X PUT "localhost:9200/logs-my_app-default/_bulk?pretty" -H 'Content-Type: application/json' -d'
{ "create": { } }
{ "@timestamp": "2099-05-07T16:24:32.000Z", "event": { "original": "192.0.2.242 - - [07/May/2020:16:24:32 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0" } }
{ "create": { } }
{ "@timestamp": "2099-05-08T16:25:42.000Z", "event": { "original": "192.0.2.255 - - [08/May/2099:16:25:42 +0000] \"GET /favicon.ico HTTP/1.0\" 200 3638" } }
'
(上記複数データ挿入の戻り値は省略してますが、無事に成功しております。)
とりあえず、アプリケーション起動とデータ単一挿入、複数挿入、データ抽出まで簡単に検証できたので今回はここまで。