elasticsearch 5.0.0-alpha4 + IPv6 + Packetbeats で遊びたい

Jul 10, 2016  

elasticsearch 5.0.0-alpha4 をみると datatype に IPv6 を含む IP 型ができている https://www.elastic.co/guide/en/elasticsearch/reference/master/ip.html

An ip field can index/store either IPv4 or IPv6 addresses.

試してみたい。 IPv6 もよく知らないので、ちょっと触ってみたい。せっかくなので Packetbeats も試してみたい。

やってみたら、 IPv6 を使うときは ip 型の stored を有効にしたほうが良さそうということがわかった。

Elasticsearch + kibana

とりあえず環境をつくる。

% docker pull elasticsearch:5.0.0-alpha4
% docker run -d --name es2 elasticsearch:5.0.0-alpha4

メモリ確保できないといわれた

{"log":"Exception in thread \"main\" java.lang.RuntimeException: bootstrap checks failed\n","stream":"stderr","time":"2016-07-10T06:56:11.405356902Z"}
{"log":"initial heap size [268435456] not equal to maximum heap size [2147483648]; this can cause resize pauses and prevents mlockall from locking the entire heap\n","stream":"stderr","time":"2016-07-10T06:56:11.405443037Z"}

https://discuss.elastic.co/t/initial-heap-size-not-equal-to-maximum-heap-size/50499 を参考にして ES_HEAP_SIZE を変更しようとしたら、 ES_JAVA_OPTS を編集してと言われた。

% docker run -it --rm -e ES_HEAP_SIZE='256m'  --name  es03  elasticsearch:5.0.0-alpha4
Error: encountered environment variables that are no longer supported
Use jvm.options or ES_JAVA_OPTS to configure the JVM
ES_HEAP_SIZE=256m: set -Xms256m and -Xmx256m in jvm.options or add "-Xms256m -Xmx256m" to ES_JAVA_OPTS

また、おこられた

% docker run -it --rm -e ES_JAVA_OPTS='-256m -256m'  --name  es03  elasticsearch:5.0.0-alpha4
max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]

vm.max_map_count はプロセスが利用可能なメモリマップの最大値らしい。 少なくとも 262144 にして欲しいそうなので変える。 sysctl で書き換える。

sudo sysctl -w vm.max_map_count=262144

無事立ち上がった。

docker run -it --rm -e ES_JAVA_OPTS='-Xms256m -Xmx256m'  --name  es03  elasticsearch:5.0.0-alpha4

kibana も新しいのにしてみた。

docker run -it --rm --link es03:elasticsearch --name kibana02 kibana:5.0.0-alpha4

kibana 開いてみたら自分が見慣れていた色と違う色使いの画面が出てきて戸惑った。

Upload CSV とか書いてあった。 1GB までの CSV ならアップロードできるみたい。

気になったので少し脱線してやってみた。 統計庁から適当な csv 持ってきていれてみた。 http://www.e-stat.go.jp/SG1/estat/List.do?bid=000001033705&cycode=0

先頭行がフィールド名として扱われた。デリミタはタブ、スペース、セミコロン、パイプも指定できる。 適当に整形した。

各フィールドの型は決められるみたいだった。 事前に時間を表すフィールドは date 型に変換できるように整形したほうが良さそうだった。 今回は 1999011999-01 に事前に修正すればよかった。 インデックス名もここで決められた。

無事アップロードできた。

飲み物の消費者物価指数推移とかが作れた。 どうでも良いことだが、物価指数は基準の月を 100 とした時の、 比較を表しているものらしかった。

packetbeats

まずはダッシュボードの準備。 https://github.com/elastic/beats-dashboards 指定する IP は ES の IP なので注意。

% ./load.sh -url "http://172.17.0.2:9200"

いくつか kibana のダッシュボードが増える。 web と db については、詳細に見られそうだった。

packetbeats そのものをインストールする。ここにしたがってインストールした。 https://www.elastic.co/guide/en/beats/packetbeat/current/packetbeat-installation.html

ES にテンプレートを適用した。

% curl -XPUT 'http://172.17.0.2:9200/_template/packetbeat' -d@packetbeat.template.json

packetbeat.yml が必要らしいので書く。インデックス名は packetbeat にしないと、 多分テンプレートと、ダッシュボードがうまく使えない。

hosts: ["172.17.0.2:9200"]
index: "packetbeat"
template:
  path: "packetbeat.template.json"

コンフィグテストして実行した。

% sudo packetbeat -configtest -e ./
% sudo packetbeat

es にちゃんと溜まった。

ES に残っている結果をみてみた

kibana からドキュメントを見たところ、 ip のフィールドの type が string になっていた。 v1.2 を入れていたが packetbeats 用のテンプレートで特に指定されていないのでそうなっている。 https://github.com/elastic/beats/blob/1.2/packetbeat/etc/packetbeat.template.json

master ブランチをみたら keyword となっていた。 ip ではないので、やろうと思っていたことができない。 https://github.com/elastic/beats/blob/master/packetbeat/packetbeat.template.json#L910-L913 よくよく考えたら現行バージョンの ip 型は IPv6 に対応していないので、この型になっているのは正しい。

試してみたいので IP が入るところを ip に適当に変換して適用してみた。 ingest API でも設定できそうだが、 beats で送信するときにうまく設定する方法がわからなかったので、やらなかった。

% curl -XPUT 'http://172.17.0.2:9200/_template/packetbeat' -d@packetbeat-iptest.template.json
% curl -XDELETE 'http://172.17.0.2:9200/packetbeat-*'
% sudo packetbeat

ip 型を使うと良い所 IPv4

IPv4 では range の検索はできる。

POST packetbeat-*/_search
{
  "query": {
    "range": {
      "client_ip": {
        "from": "127.0.0.1",
        "to": "127.255.255.255"
      }
    }
  }
}

IPv4 で CIDR の検索もできる(v2.2.0 以降らしい)。

POST packetbeat-*/_search
{
  "query": {
    "term": {
      "client_ip": "127.0.0.0/8"
    }
  }
}

IPv6 を入れた時のこと

packetbeats からやるのが面倒になったので試しにデータを入れてみる。

curl -XPOST http://172.17.0.2:9200/iptest -d '{
    "mappings" : {
        "testtype" : {
            "properties" : {
                "ip" : { "type" : "ip" }
            }
        }
    }
}'

入れた順番でソートしたいので作成時間のフィールドを追加。 _datetime は5系ではなくなって、 ingest API で設定するようになったらしい。 https://www.elastic.co/guide/en/elasticsearch/reference/master/accessing-data-in-pipelines.html#accessing-ingest-metadata 現在のところ mapping とかで pipeline は指定できないので、ドキュメント作成時に指定するか、 reindex しないといけないらしい。

curl -XPUT 'http://172.17.0.2:9200/_ingest/pipeline/add-received-pipeline' -d'{
  "description": "add received time",
  "processors": [
    {
      "set": {
        "field": "received",
        "value": "{{ _ingest.timestamp }}"
      }
    }
  ]
}'

入れるデータは http://www.ietf.org/rfc/rfc5952.txt を参考にした。

curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:001" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:01" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:0:1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0:0:0::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0:0::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8::aaaa:0:0:1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0:0:aaaa::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "::0" }'

中に入っているデータは、同じ IP でも入れた時と同じ形式で入っていた。

% curl -s -XPOST http://172.17.0.2:9200/iptest/_search -d'{ "size": 100, "sort": "received" }' | jq ".hits.hits[]._source.ip"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"
"2001:db8:aaaa:bbbb:cccc:dddd::1"
"2001:db8:aaaa:bbbb:cccc:dddd:0:1"
"2001:db8:0:0:0::1"
"2001:db8:0:0::1"
"2001:db8:0::1"
"2001:db8::1"
"2001:db8::aaaa:0:0:1"
"2001:db8:0:0:aaaa::1"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa"

検索してみた。表記方法が異なってもちゃんと検索されていた。

curl -s -XPOST http://172.17.0.2:9200/iptest/_search -d'{
  "query": {
    "term": {
      "ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
    }
  }
}
' | jq ".hits.hits[]._source.ip"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"

中に入っている情報は 128bit なはずなので調べる。 (補足)5 系から field -> stored_field, fielddata_field -> docvalue_field に変更されているようだが、 alpha4 の時点では、一度元に戻されていたため、 fielddata_fields を指定しないと動かなかった。5系リリース時点では、 docvalue_field 指定が正しくなっていそう。

% curl -s -XGET http://172.17.0.2:9200/iptest/_search -d'{
  "query": {
    "term": {
      "ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
    }
  },
  "fielddata_fields" : ["ip"]
}
' | jq ".hits.hits[] | .fields.ip[0], ._source.ip" | paste -d, - -

フィールドとして変換された結果は同じものとして、入っているみたいだった。 フィールドのほうは読めない。

" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"

入っている内容はよくわからないし、バイト数も多い。

% curl -s -XGET http://172.17.0.2:9200/iptest/_search -d'{
  "query": {
    "term": {
      "ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
    }
  },
  "fielddata_fields" : ["ip"]
}
' | jq -r ".hits.hits[0] | .fields.ip[0]" | hexdump -C -s 1
00000001  01 0d c2 b8 c2 aa c2 aa  c2 bb c2 bb cc 8c dd 9d  |................|
00000011  ee ae 80 01 0a                                    |.....|
00000016

いろいろ調べてたら doc_value として持っていたら良さそうだった。 https://github.com/elastic/elasticsearch/blob/master/core/src/main/java/org/elasticsearch/search/DocValueFormat.java#L296

ip を stored にしてみた。

curl -XPOST http://172.17.0.2:9200/iptest -d '{
    "mappings" : {
        "testtype" : {
            "properties" : {
                "ip" : { "type" : "ip", "stored": true }
            }
        }
    }
}'

検索してみる。

curl -s -XGET http://172.17.0.2:9200/iptest/_search -d'{
  "query": {
    "term": {
      "ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
    }
  },
  "fields" : ["ip"]
}
' | jq ".hits.hits[] | .fields.ip[0], ._source.ip" | paste -d, - -

ちゃんと見える状態で入ってきた。 stored にすると source を変換した値が入ることがあるようだった。知らなかった。

"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null

kibana でも統一されたフォーマットで表示されるようになった。

感想

  • ip 型を使って、 IPv6 の検索結果のフォーマットを統一したいときは、 stored を true にしたほうが良い。
  • ingests API の pipeline をデフォルトで通すようにしたいけど、 mapping とかで設定できないのでどう設定すればいいかわからなかった
  • test-kitchen を途中で見かけたけど便利そうだった

みたところ