AWS Elasticsearch Service バージョンアップ 2.2 → 5.5

AWS Elasticsearch Service バージョンアップ 2.2 → 5.5

概要

AWS Elasticsearch Service (ES) 2.3 → 5.5 へバージョンアップを実施に際して
以下記事をまとめました。

大まかな流れ

  1. ES バージョン 2.3 のドメインから Snapshot 取得
  2. ES バージョン 5.5 のドメイン作成
  3. アプリの fluentd の向け先を ES バージョン 5.5 へ変更
  4. ES バージョン 5.5 のドメインにデータリストア
  5. ES バージョン 2.3 のドメイン削除

現状バージョン確認

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ curl https://<Elasticsearch 2.3 Endpoint Domain>

{
"name" : "Jackdaw",
"cluster_name" : "<Account ID>:xxxxxxxxxx",
"version" : {
"number" : "2.3.2",
"build_hash" : "72aa8010df1a4fc849da359c9c58acba6c4d9518",
"build_timestamp" : "2016-11-14T15:59:50Z",
"build_snapshot" : false,
"lucene_version" : "5.5.0"
},
"tagline" : "You Know, for Search"
}

その他、AWS console のクラスターの設定確認

その他クラスターへ設定している情報をメモ

  • インスタンスタイプ
  • アクセスポリシーの確認

AWS Elasticsearch Service スナップショットを S3 で管理する

IAM role 作成

  • ec2 タイプで作成
  • アクセス権限は特に設定せず 「次のステップ」ボタンクリック
  • ロール名を es-index-backups とし作成

ロール ARN arn:aws:iam:::role/es-index-backups で作成されていることが確認できる

  • 信頼関係の編集

Service を es.amazonaws.com に編集

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "es.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

IAM User 作成

  • ユーザ > ユーザ追加 選択


  • ユーザ名 es-index-backup-user とし プログラムによるアクセスにチェックを入れて 次のステップ クリック


  • 特にポリシーをアタッチせず 次のステップ クリック
  • es-index-backup-user を作成し独自ポリシーで先ほど作成した role へのアクセス許可設定をアタッチします。
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": "arn:aws:iam::<Account ID>:role/es-index-backups"
}
]
}

  • 発行されたアクセスキー、シークレットアクセスキーをメモしておきます。

S3 バケット作成

S3 > バケットを作成する でバケット作成してください。

Elasticsearch にてスナップショットリポジトリ作成

スナップショットを管理するリポジトリを Elasticsearch に作成する必要があります。

Elasticsearch へのアクセス可能なサーバにて以下スクリプト実行します。

  • register_es_repository.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from boto.connection import AWSAuthConnection

class ESConnection(AWSAuthConnection):

def __init__(self, region, **kwargs):
super(ESConnection, self).__init__(**kwargs)
self._set_auth_region_name(region)
self._set_auth_service_name("es")

def _required_auth_capability(self):
return ['hmac-v4']

if __name__ == "__main__":

client = ESConnection(
region='ap-northeast-1',
host='<Elasticsearch 2.3 Endpoint Domain>',
aws_access_key_id='<ACCESS KEY ID>',
aws_secret_access_key='<SECRET ACCESS KEY>', is_secure=False)

resp = client.make_request(
method='POST',
path='/_snapshot/index-backups',
data='{"type": "s3","settings": { "bucket": "<bucket name>","region": "ap-northeast-1","role_arn": "arn:aws:iam::<Account ID>:role/es-index-backups"}}'
)
body = resp.read()
print body
1
2
3
4
5
6
$ chmod +x register_es_repository.py

$ python register_es_repository.py

// 成功
{"acknowledged":true}

リポジトリ登録完了しました。

Snapshot 取得

snapshot 名を 20170926 とします。

1
2
3
4
$ curl -XPUT "https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/20170926"

// 成功
{"accepted":true}

Snapshot 一覧

20170926 という snapshot 名で取得したことが確認できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ curl -s -XGET "https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/_all" | jq .
{
"snapshots": [
{
"snapshot": "20170926",
"version_id": 2030299,
"version": "2.3.2",
"indices": [
"nginx-access-2017.09.09",
"nginx-access-2017.09.07",
"nginx-access-2017.09.08",
"nginx-error-2017.08.24",
"nginx-error-2017.08.23",
".kibana-4",
...
],
"state": "IN_PROGRESS",
"start_time": "2017-09-26T03:58:51.040Z",
"start_time_in_millis": 1506398331040,
"failures": [],
"shards": {
"total": 0,
"failed": 0,
"successful": 0
}
}
]
}

Snapshot 削除

スナップショット 20170926 を削除する場合、DELETE メソッドを実行します。

1
2
3
4
$ curl -XDELETE https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/20170926

// 成功
{"acknowledged":true}

S3 確認

以下が作成されているのがわかります。

  • indices/*
  • meta-*
  • snap-*

はじめ meta-_ が作成できたら完了なのかなと思いきや
snap-_ も作られるまで待つ必要がありました。

  • CLI 上でスナップショット完了確認した方が確実です。
1
2
3
4
5
6
$ curl -s -GET https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/20170926

...
"state": "SUCCESS",
...
...

Elasticsearch 5.5 Service 新規ドメイン作成

Elasticsearch 2.3 の設定に倣って作成します。

リポジトリ作成

  • register_es55_repository.py

register_es_repository.py の host 部分を新規ドメインに修正します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from boto.connection import AWSAuthConnection

class ESConnection(AWSAuthConnection):

def __init__(self, region, **kwargs):
super(ESConnection, self).__init__(**kwargs)
self._set_auth_region_name(region)
self._set_auth_service_name("es")

def _required_auth_capability(self):
return ['hmac-v4']

if __name__ == "__main__":

client = ESConnection(
region='ap-northeast-1',
host='<Elasticsearch 5.5 Endpoint Domain>',
aws_access_key_id='<ACCESS KEY ID>',
aws_secret_access_key='<SECRET ACCESS KEY>', is_secure=False)

print 'Registering Snapshot Repository'
resp = client.make_request(
method='POST',
path='/_snapshot/index-backups',
data='{"type": "s3","settings": { "bucket": "<bucket name>","region": "ap-northeast-1","role_arn": "arn:aws:iam::<Account ID>:role/es-index-backups"}}'
)
body = resp.read()
print body
1
2
3
4
5
6
$ chmod +x register_es55_repository.py

$ python register_es55_repository.py

// 成功
{"acknowledged":true}

スナップショットからリストア

20170926 のスナップショットをリストアします。

1
2
3
4
$ curl -XPOST "https://<Elasticsearch 5.5 Endpoint Domain>/_snapshot/index-backups/20170926/_restore"

// 成功
{"accepted": true}

リストア確認

1
$ curl -XGET "https://<Elasticsearch 5.5 Endpoint Domain>/_cat/indices"

スナップショットに失敗するケース

  • .kibana index が既に存在しており、リストアできない。
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"error":{
"root_cause":[
{
"type":"snapshot_restore_exception",
"reason":"[index-backups:20170926/Hc4rLIoARCWqpyJXeP7edw] cannot restore index [.kibana] because it's open"
}
],
"type":"snapshot_restore_exception",
"reason":"[index-backups:20170926/Hc4rLIoARCWqpyJXeP7edw] cannot restore index [.kibana] because it's open"
},
"status":500
}

対応策

1
2
3
curl -XPOST https://<Elasticsearch 5.5 Endpoint Domain>/_snapshot/index-backups/20170926/_restore -d '{
"indices": "nginx-*"
}' | jq .

indices を用い、スナップショット内のインデックスの中からマッチする正規表現のみをリストアできます。

自身ではこの様な解決法を実施し回避できました。
その他良い方法があれば御指南いただけますと幸いです。

ちなみに

Terraform で ES 2.2 → 5.5 バージョンアップを実施した所
1 時間以上経過してようやくアップデートが完了しました。

1
2
3
4
aws_elasticsearch_domain.elasticsearch: Still destroying... (ID: arn:aws:es:ap-northeast-1:xxxxxxxxxxxx:domain/***, 59m11s elapsed)
aws_elasticsearch_domain.elasticsearch: Still destroying... (ID: arn:aws:es:ap-northeast-1:xxxxxxxxxxxx:domain/***, 59m21s elapsed)
aws_elasticsearch_domain.elasticsearch: Still destroying... (ID: arn:aws:es:ap-northeast-1:xxxxxxxxxxxx:domain/***, 59m31s elapsed)
aws_elasticsearch_domain.elasticsearch: Destruction complete after 59m41s

これは辛い (>_<)

Terraform で管理している場合、
スナップショットを取得したら aws console 上でドメイン削除した方が早い。

ブルーグリーン的に ES 5.5 作成して ES 2.2 から乗り換えて
しばらく運用して問題なければ ES 2.2 を削除する方法が一番確実だなと思いました。

Elasticsearch curatorで不要Indexをまとめて削除

概要

fluentd + ElasticSearch + kibana を運用していますが
ある日ElasticSearchが動作しなくなる事象が発生しました。

過去indexが溜まりに溜まってメモリ不足というエラー。

logはS3にアップロードしているし、
不要なIndexは適宜削除して対策しました。

環境

  • CentOS Linux release 7.0.1406 (Core)
  • ElasticSearch 1.7.1
  • Python 2.7.5
  • pip 7.1.0

curator インストール

  • ElasticSearchをインストールしているサーバにて以下実施
1
# pip install curator

curator コマンド実行

  • ElasticSearchをインストールしているサーバにて以下実施
1
2
3
4
5
6
7
8
# 14日(2週間)経過でclose
curator --host localhost close indices --prefix logstash --older-than 14 --time-unit days --timestring %Y.%m.%d

# 35日(4週間)経過でdelete
curator --host localhost delete indices --prefix logstash --older-than 35 --time-unit days --timestring %Y.%m.%d

# 2日経過でbloom filter無効化
curator --host localhost bloom indices --prefix logstash --older-than 2 --time-unit days --timestring %Y.%m.%d

上記をjenkinsで SSH plugin
リモートサーバにログインして実行するよう、
設定して定期ポーリングで1日1回実行させてます。

以上

Elasticsearch インデックス一覧・マッピング一覧・マッピング設定

前提

Elasticsearch のインストールされているサーバ内での作業を想定しています。

インデックス一覧

1
curl -XGET localhost:9200/_aliases?pretty
1
2
3
4
5
6
7
8
{
"logstash-2015.09.22" : {
"aliases" : { }
},
"logstash-2015.09.21" : {
"aliases" : { }
},
}
  • prettyをクエリストリングに指定すると
    jsonが整形されて表示されます。

インデックスのマッピング一覧

1
$ curl -XGET localhost:9200/_mapping?pretty
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{
"logstash-2015.09.22" : {
"mappings" : {
"project_production_nginx" : {
"properties" : {
"@log_name" : {
"type" : "string"
},
"@timestamp" : {
"type" : "date",
"format" : "dateOptionalTime"
},
"body_bytes_sent" : {
"type" : "long"
},
"bytes_sent" : {
"type" : "long"
},
"forwardedfor" : {
"type" : "string"
},
"host" : {
"type" : "string"
},
"https" : {
"type" : "string"
},
"log_level" : {
"type" : "string"
},
"message" : {
"type" : "string"
},
"pid" : {
"type" : "string"
},
"query_string" : {
"type" : "string"
},
"referer" : {
"type" : "string"
},
"remote_addr" : {
"type" : "string"
},
"request_length" : {
"type" : "long"
},
"request_method" : {
"type" : "string"
},
"request_time" : {
"type" : "double"
},
"request_uri" : {
"type" : "string"
},
"status" : {
"type" : "long"
},
"tid" : {
"type" : "string"
},
"upstream_response_time" : {
"type" : "long"
},
"uri" : {
"type" : "string"
},
"useragent" : {
"type" : "string"
}
}
}
}
}
}

マッピング設定

jsonファイル作成

1
2
$ cd /etc/elasticsearch/
$ vim el_mapping.json
  • el_mapping.json

以下のように設定し保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
{
"template": "logstash-*",
"mappings" : {
"_default_" : {
"dynamic_templates":[{
"string_template":{
"match":"*",
"mapping":{
"type":"string",
"index":"not_analyzed"
},
"match_mapping_type":"string"
}
}],
"properties" : {
"@timestamp" : {
"type" : "date",
"format" : "dateOptionalTime"
},
"body_bytes_sent" : {
"type" : "long"
},
"bytes_sent" : {
"type" : "long"
},
"geoip" : {
"properties" : {
"location" : {
"type" : "geo_point",
"lat_lon" : true,
"geohash" : true,
"geohash_prefix" : true,
"geohash_precision" : 10
}
}
},
"request_length" : {
"type" : "long"
},
"request_time" : {
"type" : "double"
},
"status" : {
"type" : "long"
},
"upstream_response_time" : {
"type" : "long"
},
"coordinate" : {
"type" : "double"
},
"country" : {
"type" : "string"
},
"lat" : {
"type" : "double"
},
"location_properties" : {
"type" : "geo_point"
},
"lon" : {
"type" : "double"
}
}
}
}
}

マッピング設定実行

1
curl -X PUT localhost:9200/_template/template_1 --data @el_mapping.json

マッピング設定一覧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
curl -X GET localhost:9200/_template/?pretty

# 一覧が出力される
...
...
},
"template_1" : {
"order" : 0,
"template" : "flag_prd.accesslog-*",
"settings" : { },
"mappings" : {
"_default_" : {
"dynamic_templates" : [ {
"string_template" : {
"mapping" : {
"index" : "not_analyzed",
"type" : "string"
},
"match_mapping_type" : "string",
"match" : "*"
}
} ],
"properties" : {
...
...

マッピング設定削除

1
curl -X DELETE localhost:9200/_template/template_1

string型はまとめてdynamic_templatesで定義してます。

1
2
3
4
5
6
7
8
9
10
"dynamic_templates":[{
"string_template":{
"match":"*",
"mapping":{
"type":"string",
"index":"not_analyzed"
},
"match_mapping_type":"string"
}
}],

インデックス削除

インデックスを指定し削除します。

1
2
3
curl -X DELETE localhost:9200/logstash-2015.09.22

{"acknowledged":true}

インデックス全削除

1
2
3
$ curl -XDELETE 'http://localhost:9200/*'

{"acknowledged":true}

サービス開始前で試行錯誤してるときに何度か利用しました。
極力使わない。

指定インデックス削除

  • 例) .kibana インデックス削除
1
$ curl -XDELETE 'http://localhost:9200/.kibana'

各フィールド設定は以下まとめていただいている方がいらっしゃいました。
ありがとうございます♪

Kibana+Elasticsearchで文字列の完全一致と部分一致検索の両方を実現する