【Amazon Elasticsearch Service】 手動スナップショットからリストアする方法

2018.06.04

Amazon ESでは自動スナップショットと手動スナップショットがありますが、自動スナップショットからは新しいAmazon ES ドメインにリストアすることはできません。 そのため新しいAmazon ES ドメインにリストアするには手動スナップショットからリストアする必要があります。

今回は手動スナップショットの作成方法と手動スナップショットからリストアする方法についてご紹介します。

Step1: S3バケットの作成、設定

手動スナップショットを保存するためのS3バケットを作成します。 S3コンソールでes-test-index-repoという名前で作成しました。

バケットのARNは後ほど使用するのでメモしておきます。

  • arn:aws:s3:::es-test-index-repo

Step2: IAM の設定

IAMコンソールで設定していきます。

Policies -> Create policy から以下ポリシーes-test-index-repo-policyを作成します。

Resourceには先ほど作成したS3バケットのARNarn:aws:s3:::es-test-index-repoを指定しています。

{
"Version":"2012-10-17",
"Statement":[
{
"Action":[
"s3:ListBucket"
],
"Effect":"Allow",
"Resource":[
"arn:aws:s3:::es-test-index-repo"
]
},
{
"Action":[
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Effect":"Allow",
"Resource":[
"arn:aws:s3:::es-test-index-repo/*"
]
}
]
}

Roles -> Create role からIAM ロールes-test-index-repo-roleを作成します。 先ほど作成したポリシーを付与し、信頼関係を以下のようにします。

ロールの信頼関係

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "es.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

手動スナップショットレポジトリの登録のためにAPIキーを使用するユーザーに対して以下ポリシーを作成してアタッチします。

  • es-backup-policy
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::aws_account_id:role/es-test-index-repo-role"
}
}

Step3: 手動スナップショットレポジトリの登録

手動スナップショットを取得する前に、一度だけスナップショットレポジトリを登録する必要があります。 こちらはAWSリクエストに署名することが必要です。curlではAWSリクエスト署名をサポートしていません。 pythonのサンプルコードがありますのでこちらを参考に実施します。

register-repo.py

  • AWS_ACCESS_KEY_ID = ''
  • AWS_SECRET_ACCESS_KEY = ''
  • host = '' # ES ドメインのエンドポイント
  • region = 'us-west-2' # ES ドメインのリージョン
  • path = '' # スナップショットリポジトリの名前
  • bucket = '' # S3バケット名
  • role_arn = '' # 先ほど作成したIAMロールのANR
import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID =''
AWS_SECRET_ACCESS_KEY =''
region = 'us-west-2'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

path = '_snapshot/es-test-index-repo'
url = host + path

payload = {
"type": "s3",
"settings": {
"bucket": "s3-bucket-name",
"region": "us-west-2",
"role_arn": "arn:aws:iam::aws_account_id:role/es-test-index-repo-role"
}
}

headers = {"Content-Type": "application/json"}

r = requests.put(url, auth=awsauth, json=payload, headers=headers)

print(r.text)

実行

$ python register-repo.py
{"acknowledged":true}

Step4: 手動スナップショットの取得

アクセスポリシーがIAMユーザーや、IAMロールの場合、リクエストに署名をする必要があります。サンプルコードがドキュメントにありますのでサンプルコードを参考に実施します。

署名リクエストを必要とする場合はpythonのコードを、署名リクエストを必要としない場合はcurlの実行例をご参照ください。

snapshot.py

  • path # snapshot名を指定します。
import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID=''
AWS_SECRET_ACCESS_KEY=''
region = 'us-west-2'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

path = '_snapshot/es-test-index-repo/my-snapshot-1'
url = host + path

r = requests.put(url, auth=awsauth)

print(r.text)

実行

$ python snapshot.py
{"accepted":true}

curl

$ curl -XPUT 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/_snapshot/es-test-index-repo/my-snapshot-2'
{"accepted":true}

Step5: スナップショットのリポジトリ確認

check_repository.py

import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID=''
AWS_SECRET_ACCESS_KEY=''
region = 'us-west-2'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

path = '_snapshot/?pretty'
url = host + path

r = requests.get(url, auth=awsauth)

print(r.text)

実行結果

$ python repository.py
{
"es-test-index-repo" : {
"type" : "s3",
"settings" : {
"bucket" : "es-test-index-repo",
"region" : "us-west-2",
"role_arn" : "arn:aws:iam::aws_account_id:role/es-test-index-repo"
}
},
"cs-automated" : {
"type" : "s3"
}
}

curl

$ curl -XGET 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/_snapshot?pretty'
{
"es-test-index-repo" : {
"type" : "s3",
"settings" : {
"bucket" : "es-test-index-repo",
"region" : "us-west-2",
"role_arn" : "arn:aws:iam::aws_account_id:role/es-test-index-repo-role"
}
}
}

Step6: リポジトリからスナップショットの確認

スナップショットを確認します。

check_snapshot.py

import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID=''
AWS_SECRET_ACCESS_KEY=''
region = 'us-west-2'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

path = '_snapshot/es-test-index-repo/_all?pretty'
url = host + path

r = requests.get(url, auth=awsauth)

print(r.text)

実行結果

$ python check_snapshot.py
{
"snapshots" : [ {
"snapshot" : "my-snapshot-1",
"uuid" : "**********aixSzBQFI_2g",
"version_id" : 6020299,
"version" : "6.2.2",
"indices" : [ "index1", "index2" ],
"include_global_state" : true,
"state" : "SUCCESS",
"start_time" : "2018-05-25T02:12:52.086Z",
"start_time_in_millis" : 1527214372086,
"end_time" : "2018-05-25T02:12:55.745Z",
"end_time_in_millis" : 1527214375745,
"duration_in_millis" : 3659,
"failures" : [ ],
"shards" : {
"total" : 10,
"failed" : 0,
"successful" : 10
}
}, {
"snapshot" : "my-snapshot-2",
"uuid" : "**********Svf55AYG0QuQ",
"version_id" : 6020299,
"version" : "6.2.2",
"indices" : [ "index1", "index2" ],
"include_global_state" : true,
"state" : "SUCCESS",
"start_time" : "2018-05-25T02:13:36.289Z",
"start_time_in_millis" : 1527214416289,
"end_time" : "2018-05-25T02:13:38.326Z",
"end_time_in_millis" : 1527214418326,
"duration_in_millis" : 2037,
"failures" : [ ],
"shards" : {
"total" : 10,
"failed" : 0,
"successful" : 10
}
} ]
}

curl

curl -XGET 'elasticsearch-domain.us-west-2.es.amazonaws.com/_snapshot/es-test-index-repo/_all?pretty'
{
"snapshots" : [ {
"snapshot" : "my-snapshot-1",
"uuid" : "**********aixSzBQFI_2g",
"version_id" : 6020299,
"version" : "6.2.2",
"indices" : [ "index1", "index2" ],
"include_global_state" : true,
"state" : "SUCCESS",
"start_time" : "2018-05-25T02:12:52.086Z",
"start_time_in_millis" : 1527214372086,
"end_time" : "2018-05-25T02:12:55.745Z",
"end_time_in_millis" : 1527214375745,
"duration_in_millis" : 3659,
"failures" : [ ],
"shards" : {
"total" : 10,
"failed" : 0,
"successful" : 10
}
}, {
"snapshot" : "my-snapshot-2",
"uuid" : "**********Svf55AYG0QuQ",
"version_id" : 6020299,
"version" : "6.2.2",
"indices" : [ "index1", "index2" ],
"include_global_state" : true,
"state" : "SUCCESS",
"start_time" : "2018-05-25T02:13:36.289Z",
"start_time_in_millis" : 1527214416289,
"end_time" : "2018-05-25T02:13:38.326Z",
"end_time_in_millis" : 1527214418326,
"duration_in_millis" : 2037,
"failures" : [ ],
"shards" : {
"total" : 10,
"failed" : 0,
"successful" : 10
}
} ]
}

Step7: スナップショットのリストア

ここでは2つのパターンで実施します。

  • 同じESドメインにリストアする
  • 別のESドメインにリストアする

Step7-1 同じESドメインにリストアする

リストアの際に同じ名前のインデックスがある場合、リストアができないので一旦削除します。 ※ Amazon ES は Elasticsearch _close API をサポートしていないため。

delete_index.py

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

import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID=''
AWS_SECRET_ACCESS_KEY=''
region = 'us-west-1'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

# DELETE INDEX

path = 'my-index'
url = host + path

r = requests.delete(url, auth=awsauth)

print(r.text)
$ python delete_index.py
{"acknowledged":true}

curl

インデックスをすべて削除

curl -XDELETE'https://elasticsearch-domain.us-west-2.es.amazonaws.com/_all'

インデックスを指定して削除

$ curl -XDELETE 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/index-name'

restore-all.py

pathでスナップショット名を指定しています。

import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID=''
AWS_SECRET_ACCESS_KEY=''
region = 'us-west-1'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

path = '_snapshot/es-test-index-repo/my-snapshot-1/_restore'
url = host + path

r = requests.post(url, auth=awsauth)

print(r.text)
$ python restore.py
{"accepted":true}

restore-one.py

特定のインデックスをリストア

こちらはpayloadで特定のインデックスを指定しています。

import requests
from requests_aws4auth import AWS4Auth

AWS_ACCESS_KEY_ID=''
AWS_SECRET_ACCESS_KEY=''
region = 'us-west-1'
service = 'es'

awsauth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region, service)

host = 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/'

path = '_snapshot/es-test-index-repo/my-snapshot-1/_restore'
url = host + path

payload = {"indices": "my-index"}

headers = {"Content-Type": "application/json"}

r = requests.post(url, auth=awsauth, json=payload, headers=headers)

print(r.text)
$ python restore-one.py
{"accepted":true}

curl

インデックスをすべてリストア

curl -XPOST 'elasticsearch-domain.us-west-2.es.amazonaws.com/_snapshot/es-test-index-repo/my-snapshot-1/_restore'

{"accepted":true}

特定のインデックスをリストア

$ curl -XPOST 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/_snapshot/es-test-index-repo/_restore' -d '{"indices": "my-index"}' -H 'Content-Type: application/json'

Step7-2 別ドメインにリストアする

別ドメインに対してリストアする場合は、別ドメインも同じスナップショットレポジトリを登録する必要があります。

Step3: 手動スナップショットレポジトリの登録 を別ドメインで再度登録します。

※register-repo.pyのhostを変更して実行します。

register-repo.py

$ python register-repo.py
{"acknowledged":true}

その後、別ドメインに対してリストアを実行します。 hostを変更して実行します。

restore.py でリストアを実施

$ python restore-all.py
{"accepted":true}

curl

curl -XPOST 'https://elasticsearch-domain.us-west-2.es.amazonaws.com/_snapshot/es-test-index-repo/my-snapshot-1/_restore'

まとめ

今回は手動スナップショットからAmazon ES ドメインをリストアする方法について以下ドキュメントを元に試してみました。 別ドメインにリストアする場合や、メンテナンスの前に手動スナップショットを取得しリストアするときに参考になれば幸いです。

参考URL

Amazon Elasticsearch Service インデックススナップショットの使用