エンジニアリング

AWS ElasticsearchからElasticsearch Service on Elastic Cloudへの移行

Elastic Stackのすべての機能を活用

ソリューションアーキテクトである私は、ElasticデプロイメントをAmazon Elasticsearch Service(AWS ES)からElasticsearch Serviceに移行する方法についてよく尋ねられます。 その質問の主な理由は、Elasticsearch Serviceに移行すると、Amazonでは利用できないElasticの機能、操作に関する専門知識、およびサポートのすべてを活用できるからです。このプラクティショナー向けのガイドでは、よく言われている「リフト&シフト」方式でElasticのElasticsearch Serviceに移行する方法を説明します。

無料の14日間のトライアルでデプロイメントを作成し、Elasticsearch Serviceの利用を開始することができます。クラウドプロバイダー(AWSまたはGCP)を選択し、Elasticを実行するデプロイメントのリージョンを選択します。 AWSユーザーは、AWSマーケットプレイスから直接、Elasticsearch Serviceを追加できます(AWSからの請求に含まれます)。

これにより、オープンソースのディストリビューションで利用可能な機能以外にも、たとえばCanvasAPM教師なしの機械学習フローズンインデックスSQLセキュリティ(基本的なIAMポリシーおよび境界のみのセキュリティ以上の機能)、および導入テンプレートなど、Elasticsearch Service on Elastic Cloud独自の多数の機能を利用できます。このような独自の機能は今後も常時追加されていきます。AWS ESとの違いについては、AWS Elasticsearch比較ページを定期的にご確認ください。

AWS ElasticsearchからElasticsearch Service on Elastic Cloudへの移行

この記事は、AWS ESからElasticsearch Service on Elastic Cloudへの移行に関するかなり技術的なガイドであり、理解するには多少のプログラミング経験が必要になります。AWS ESクラスターは一般的にVPCにプロビジョニングされますが、公開されているエンドポイントにプロビジョニングすることも可能です。この記事では、両方のシナリオに対応できるようにするためにPython AWS SDKを使用します。AWS SDKが含まれている言語(Java、Ruby、Goなど)ならどれでも使用できますが、ここではPythonの例のみを提示します。

このガイドは次の2つのパートで構成されています。

注:すでにAWS ESクラスターのスナップショットを手動で取ってS3に保存している場合は、パート2に進んでください。

開始する前に、次に説明するIAMセキュリティの手順について理解しておくことが重要です。まず、AWS ESクラスターのスナップショットをS3に保存するためには、AWS ESクラスターにプライベートのS3バケットへの書き込み許可が必要です。これには、必要な権限を持つIAMロールおよびポリシーが必要です。また、IAMユーザー(作成していない場合は作成する必要があります)にIAMポリシーをアタッチすることが必要です。IAMユーザーは、スクリプトでAWS ESクラスターと通信するために使用され、またElasticが管理するデプロイメントでS3バケットからスナップショットを読み取るために使用されます。

パート1 - スナップショットをS3に保存

このガイドの最初パートでは、AWS ESクラスターのスナップショットをS3に保存するために、IAMロール、IAMポリシー、およびIAMユーザーを設定する手順について説明します。このプロセスについてのAWSのドキュメントはこちらです:Amazon Elasticsearch Serviceインデックススナップショットの使用。これは不明点が生じたときの参照資料として役立ちます。

また、手順を進めていく中で使用するいくつかの変数を書き留めておく必要があります。下記の表をコピーし、メモ帳などのファイルにペーストして、このガイドを読み進めながら参照できるようにしてください。そうすることで、移行に固有の値を簡単に入力できます。

説明変数
AWS ESドメインARN DOMAIN_ARN
AWS ESエンドポイントURL ES_ENDPOINT
AWS ESリージョン ES_REGION
AWS S3バケット名 S3_BUCKET_NAME
AWS S3リージョン S3_REGION_NAME
AWS IAMロールARN ROLE_ARN
AWS IAMアクセスキーID ACCESS_KEY
AWS IAMシークレットアクセスキー SECRET_KEY
AWS ESスナップショットリポジドリ SNAPSHOT_REPO my-snapshot-repo
AWS ESスナップショット名 SNAPSHOT_NAME my-snapshot

SNAPSHOT_REPOおよびSNAPSHOT_NAMEの値を変更するか、または提示してある例(「my-snapshot-repo」および「my-snapshot」)を使用することができます。

ステップ1 - AWS ESの情報を取得する

AWS ESクラスターのスナップショットをS3に保存するためには、AWS ESクラスターに関する基本情報がいくつか必要です。

  1. AWSコンソールでElasticsearch Serviceを選択します
  2. スナップショットを取るクラスターのドメインを選択します
  3. 「ドメインARN」の値をメモ帳ファイルにコピーします(DOMAIN_ARN)
  4. 「エンドポイント」URLの値をメモ帳ファイルにコピーします(ES_ENDPOINT)
  5. AWS ESクラスターのAWSリージョン(例:us-east-1)をメモしておきます(ES_REGION)

これらの情報は後でIAMポリシーを作成する際、およびクラスターにコマンドを発行する際に使用します。

ステップ2 - AWS S3バケットを作成する

スナップショットを保存するためにS3バケットを作成する必要があります。

重要: S3バケットはAWS ESクラスターと同じリージョンである必要があります。そのS3バケットから、Elasticが管理するデプロイメント(任意のリージョン)またはクラウドプロバイダー(AWSまたはGCP)への復元が可能です。

  1. AWSコンソールでS3サービスを選択します
  2. プライベートのS3バケットを作成します
    注: デフォルトのままにすると、バケットはプライベートとなり、安全です
  3. バケット名をメモ帳ファイルにコピーします(S3_BUCKET_NAME)
  4. バケットのリージョンをメモ帳ファイルにコピーします(S3_REGION_NAME)

これらの情報は、スナップショットリポジトリをElasticsearchに登録する際に使用します。

ステップ3 - IAMロールを作成する

次に、スナップショットをS3に保存する権限をAmazon Elasticsearch Serviceに委任するロールを作成します。

  1. AWSコンソールでIAMサービスを選択します
  2. [Roles]を選択します
  3. [Create role]を選択します
  4. この新しいロールを使用するサービスとして[EC2]を選択します(後で変更します)
  5. [Next: Permissions]を選択します
  6. ここではロールのポリシーを空のままにします
  7. [Next: Tags]を選択します
  8. [Next: Review]を選択します
  9. ロールの名前をTheSnapshotRoleにします
  10. [Create role]を選択します
  11. ロールのリストから、今作成したロールのTheSnapshotRoleを選択します
  12. [Trust relationships]を選択します
  13. [Edit trust relationship]を選択します
  14. 下記の内容をコピーして、信頼関係にペーストします(該当箇所を下記の内容に置き換えます)

    {
     "Version":"2012-10-17",
      "Statement": [{
        "Effect":"Allow",
        "Principal": {
          "Service": "es.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }]
    }
    
  15. [Update Trust Policy]を選択します
  16. [Permissions]を選択します
  17. [Add inline policy]を選択します
  18. [JSON]タブを選択します
  19. 下記のJSONをコピー&ペーストします(該当箇所を下記の内容に置き換えます)
  20. S3_BUCKET_NAMEを正しい値に置き換えます(2か所)

    {
      "Version":"2012-10-17",
      "Statement": [{
          "Action": [
            "s3:ListBucket"
          ],
          "Effect":"Allow",
          "Resource": [
            "arn:aws:s3:::S3_BUCKET_NAME"
          ]
        },
        {
          "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject"
          ],
          "Effect":"Allow",
          "Resource": [
            "arn:aws:s3:::S3_BUCKET_NAME/*"
          ]
        }
      ]
    }   
  21. [Review policy]を選択します
  22. ポリシーの名前をTheSnapshotS3Policyにします
  23. [Create policy]を選択します
  24. 「ロールARN」の値をメモ帳ファイルにコピーします(ROLE_ARN)

IAMロールと、S3バケットへの書き込みと読み取りが可能なインラインポリシーを作成しました。

ステップ4 - IAMポリシーを作成する

スナップショットリポジトリを登録するには、上記のロールを引き受ける権限を持つ新しいIAMポリシーを作成する必要があります。

  1. AWSコンソールでIAMサービスを選択します
  2. [Policies]を選択します
  3. [Create policy]を選択します
  4. [JSON]タブを選択します
  5. 下記のJSONをコピー&ペーストします(該当箇所を下記の内容に置き換えます)
  6. ROLE_ARNを正しい値に置き換えます
  7. DOMAIN_ARNを正しい値に置き換えます
  8. S3_BUCKET_NAMEを正しい値に置き換えます(2か所)

    {
      "Version":"2012-10-17",
      "Statement": [
        {
          "Effect":"Allow",
          "Action": "iam:PassRole",
          "Resource":"ROLE_ARN"
        },
        {
          "Effect":"Allow",
          "Action": "es:ESHttpPut",
          "Resource":"DOMAIN_ARN/*"
        }
      ]
    }
    
  9. [Review policy]を選択します
  10. ポリシーの名前をTheSnapshotPolicyにします
  11. [Create policy]を選択します

IAMポリシーを作成しました。これでIAMロールはAWS ESドメインと通信できます。

ステップ5 - IAMユーザーを作成する

まだIAMユーザーを作成していない場合は作成して、プライベートのS3バケットへのアクセス権を付与します。すでにIAMユーザーが存在する場合は、それに以下のIAMポリシーをアタッチすることができます。

  1. AWSコンソールでIAMサービスを選択します
  2. [Users]を選択します
  3. [Add user]を選択します
  4. ユーザーの名前をTheSnapshotUserにします
  5. [Programmatic access]ボックスにチェックマークを入れます
  6. [Next: Permissions]を選択します
  7. [Attach existing policies directly]ボックスを選択します
  8. 「TheSnapshot」と入力してポリシーをフィルターします
  9. ポリシー「TheSnapshotPolicy」の横のチェックボックスを選択します
  10. [Next: Tags]を選択します
  11. [Next: Review]を選択します
  12. [Create user]を選択します
  13. 「Access key ID」の値をメモ帳ファイルにコピーします(ACCESS_KEY)
  14. [Secret access key]の下の[Show]を選択します
  15. 「Secret access key」の値をメモ帳ファイルにコピーします(SECRET_KEY)
  16. [Close]を選択します
  17. ユーザーのリストから、今作成したロールのTheSnapshotUserを選択します
  18. [Add inline policy]を選択します
  19. [JSON]タブを選択します
  20. 下記のJSONをコピー&ペーストします(該当箇所を下記の内容に置き換えます)
  21. S3_BUCKET_NAMEを正しい値に置き換えます(2か所)

    {
      "Version":"2012-10-17",
      "Statement": [{
          "Action": [
            "s3:ListBucket"
          ],
          "Effect":"Allow",
          "Resource": [
            "arn:aws:s3:::S3_BUCKET_NAME"
          ]
        },
        {
          "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject"
          ],
          "Effect":"Allow",
          "Resource": [
            "arn:aws:s3:::S3_BUCKET_NAME/*"
          ]
        }
      ]
    }
    
  22. [Review policy]を選択します
  23. ポリシーの名前をTheSnapshotUserS3Policyにします
  24. [Create policy]を選択します

IAMユーザーを作成しました。これによって、手動でスナップショットを取り、そのスナップショットから読み取ることが可能になります。

ステップ6 - Python AWS SDKを設定する

手動でスナップショットを取る前に、デプロイメントにスナップショットリポジトリを登録する必要があります。そのためには、AWS ESクラスターに署名済みリクエストを送信する必要があります。その最も簡単な方法の1つは、Python AWS SDKを使用する方法です。別のAWS SDK(Java、Ruby、Goなど)を使用することもできますが、下記の例ではPython AWS SDKを使用します。

PythonのパッケージインストーラーのPIPを使用してインストールします(pip3)。これを実行するにはPython v3がインストールされている必要があります。Python v3をインストールしていない場合は、pip3をインストールするだけでPython v3がインストールされます。Python v3はpip3に依存しているため、オペレーティングシステムのパッケージマネージャーが自動的にPython v3をインストールします。問題が発生した場合は、Pythonのインストールに関するドキュメントを参照してください。

pip3のインストール

pip3Red Hatとその派生物にインストールするには、yumを使用します。

$ sudo yum -y install python3-pip

または、Fedoraディストリビューションの一部ではpip3パッケージの記述が異なります。

$ sudo yum -y install python36-pip

どちらのパッケージ名を使用してもインストールできない場合は、次のようにしてパッケージ名を検索することができます。

$ yum search pip

Ubuntuなど、Debianの派生物の場合は、apt-getを使用します。

$ sudo apt-get -y install python3-pip

Python AWS SDKのインストール

pip3のインストールが完了したら、 boto3という名前のPython AWS SDKをインストールできます。

$ pip3 install --user boto3 requests_aws4auth
Collecting boto3
...
Successfully installed boto3-1.9.106 requests-aws4auth-0.9 ...

注: --userフラグを指定した場合、rootアクセスは必要ありません。

AWS credentialsを保持するために、~/.awsディレクトリを作成する必要があります。下記のコマンドを実行してディレクトリを作成します。

$ mkdir ~/.aws

お好みのエディターでcredentialsという名前のファイルを作成します。シンプルにするためにnanoを使用します。

$ nano ~/.aws/credentials

次の内容をファイルにコピー&ペーストし、大文字の2つの変数を置き換えます。

[default]
aws_access_key_id = ACCESS_KEY
aws_secret_access_key = SECRET_KEY

Ctrl+Xを使用してnanoを終了し、プロンプトに従ってファイルを保存します。

次に、必要なタスクを実行するいくつかのPythonスクリプトを記述します。

ステップ7 - AWS ESのスナップショットを手動で取る

まずは簡単なテストを実行しましょう。Pythonスクリプトを使用してAWS ESクラスターのインデックスをリストします。これでAWSクレデンシャルが有効であり、クラスターと通信できることが証明されます。

お好みのエディターでindices.pyという名前のファイルを作成します。シンプルにするためにnanoを使用します。

$ nano indices.py

次の内容をコピー&ペーストし、大文字の2つの変数を自分の値に置き換えます。

import boto3, requests
from requests_aws4auth import AWS4Auth
host = 'ES_ENDPOINT'
region = 'ES_REGION'
creds = boto3.Session().get_credentials()
auth = AWS4Auth(creds.access_key, creds.secret_key, region, 'es', session_token=creds.token)
print("Listing Indices from AWS ES ...")
req = requests.get(host + '/_cat/indices?v', auth=auth)
print("HTTP Response Code: " + str(req.status_code) + '\n' + req.text)

Ctrl+Xを使用してnanoを終了し、プロンプトに従ってファイルを保存します。

Pythonスクリプトを実行します。

$ python3 indices.py

その出力は下記に類似したものになるはずです。

Listing Indices from AWS ES ...
HTTP Response Code:200
health status index     uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   testindex yME2BphgR3Gt1ln6n03nHQ   5   1          1            0      4.4kb          4.4kb

次に、お好みのエディターでregister.pyという名前のファイルを作成します。

$ nano register.py

次の内容をコピー&ペーストし、大文字の7つの変数を自分の値に置き換えます。

import boto3, requests
from requests_aws4auth import AWS4Auth
host = 'ES_ENDPOINT'
region = 'ES_REGION'
repo_name = 'SNAPSHOT_REPO'
snapshot_name = 'SNAPSHOT_NAME'
s3_region_name = 'S3_REGION_NAME'
s3_bucket_name = 'S3_BUCKET_NAME'
role_arn = 'ROLE_ARN'
creds = boto3.Session().get_credentials()
auth = AWS4Auth(creds.access_key, creds.secret_key, region, 'es', session_token=creds.token)
headers = {"Content-Type": "application/json"}
payload = {
        "type": "s3",
        "settings": {
                "region": s3_region_name,
                "bucket": s3_bucket_name,
                "role_arn": role_arn
        }
}
print("Registering Snapshot with AWS ES ...")
url = host + '/_snapshot/' + repo_name
req = requests.put(url, auth=auth, json=payload, headers=headers)
print("HTTP Response Code: " + str(req.status_code) + '\n' + req.text)

Ctrl+Xを使用してnanoを終了し、プロンプトに従ってファイルを保存します。

Pythonスクリプトを実行します。

$ python3 register.py

その出力は下記に類似したものになるはずです。

Registering Snapshot with AWS ES ...
HTTP Response Code:200
{"acknowledged":true}

次に、お好みのエディターでsnapshot.pyという名前のファイルを作成します。

$ nano snapshot.py

次の内容をコピー&ペーストし、大文字の4つの変数を自分の値に置き換えます。

import boto3, requests
from requests_aws4auth import AWS4Auth
host = 'ES_ENDPOINT'
region = 'ES_REGION'
repo_name = 'SNAPSHOT_REPO'
snapshot_name = 'SNAPSHOT_NAME'
creds = boto3.Session().get_credentials()
auth = AWS4Auth(creds.access_key, creds.secret_key, region, 'es', session_token=creds.token)
print("Starting Snapshot with AWS ES ...")
url = host + '/_snapshot/' + repo_name + '/' + snapshot_name
req = requests.put(url, auth=auth)
print("HTTP Response Code: " + str(req.status_code) + '\n' + req.text)

Ctrl+Xを使用してnanoを終了し、プロンプトに従ってファイルを保存します。

Pythonスクリプトを実行します。

$ python3 snapshot.py

その出力は下記に類似したものになるはずです。

Starting Snapshot with AWS ES ...
HTTP Response Code:200
{"accepted":true}

注: スナップショットを取るための時間は、AWS ESドメインのサイズに比例して増えます。AWSのドキュメントによると、スナップショットのオペレーションが長時間に及ぶと「504 GATEWAY_TIMEOUT」が表示される場合があるとのことです。このエラーは無視し、スナップショットが正常に完了するまで待機するようにと記載されています。

最後に、スナップショットの状態を確認します。status.pyという名前のファイルを作成します。

$ nano status.py

次の内容をコピー&ペーストし、大文字の4つの変数を自分の値に置き換えます。

import boto3, requests
from requests_aws4auth import AWS4Auth
host = 'ES_ENDPOINT'
region = 'ES_REGION'
repo_name = 'SNAPSHOT_REPO'
snapshot_name = 'SNAPSHOT_NAME'
creds = boto3.Session().get_credentials()
auth = AWS4Auth(creds.access_key, creds.secret_key, region, 'es', session_token=creds.token)
print("Getting Status of Snapshot with AWS ES ...")
url = host + '/_snapshot/' + repo_name + '/' + snapshot_name + '?pretty'
req = requests.get(url, auth=auth)
print("HTTP Response Code: " + str(req.status_code) + '\n' + req.text)

Ctrl+Xを使用してnanoを終了し、プロンプトに従ってファイルを保存します。

Pythonスクリプトを実行します。

$ python3 status.py

その出力は下記に類似したものになるはずです。

Getting Status of Snapshot with AWS ES ...
HTTP Response Code:200
{
  "snapshots" : [ {
    "snapshot" : "my-snapshot",
    "uuid" :"ClYKt5g8QFO6r3kTCEzjqw",
    "version_id" :6040299,
    "version" :"6.4.2",
    "indices" : [ "testindex" ],
    "include_global_state" : true,
    "state" :"SUCCESS",
    "start_time" :"2019-03-03T14:46:04.094Z",
    "start_time_in_millis" :1551624364094,
    "end_time" :"2019-03-03T14:46:04.847Z",
    "end_time_in_millis" :1551624364847,
    "duration_in_millis" :753,
    "failures" : [ ],
    "shards" : {
      "total" :5,
      "failed" :0,
      "successful" :5
    }
  } ]
}

"state":"SUCCESS"」が表示されていれば、スナップショットは正常にS3に保存されています。これでパート2に進む準備が整いました。

パート2 - S3からの復元

このガイドの2つ目のパートでは、S3にある手動スナップショットから、Elasticが管理するデプロイメントに復元する手順について説明します。

このパートの内容を実行するために、Elasticが管理するデプロイメントをAWSまたはGCPにプロビジョニングできます。

ステップ1 - デプロイメントのサイズを指定する

Elasticsearch Service on Elastic Cloudに作成したデプロイメントのリソースの量は、AWS ESクラスターのリソースの量と同じはずです。AWS ES内のクラスターのサイズを反映するために、スライダーを使用してデータノード数を増やします。保存してから次に進みます。

ステップ2 - カスタムリポジトリを追加する

Elasticが管理するデプロイメント(AWS ESクラスターではなく)で、Kibanaを開いて[Dev Tools]にアクセスします。

下記のAPIコールをコピーしてDev Toolsにペーストし、5つの変数を置き換えます。

PUT /_snapshot/SNAPSHOT_REPO
{
  "type": "s3",
  "settings": {
    "bucket":"S3_BUCKET_NAME",
    "region":"S3_REGION_NAME",
    "access_key":"ACCESS_KEY",
    "secret_key":"SECRET_KEY",
    "compress": true
  }
}

リクエストを実行します。

下記の応答になるはずです。

{
  "acknowledged": "true"
}

あと少しで完了です。

ステップ3 - S3から復元する

最後に、先ほど登録したスナップショットリポジトリから復元します。

下記のAPIコールをコピーしてDev Toolsにペーストし、2つの変数を置き換えます。

POST /_snapshot/SNAPSHOT_REPO/SNAPSHOT_NAME/_restore

下記の応答になるはずです。

{
  "accepted": "true"
}

復元の進捗状況は下記によって確認できます。

GET /_snapshot/SNAPSHOT_REPO/SNAPSHOT_NAME/_status

"state":"SUCCESS"」が表示されていれば、復元が正常に完了しています。

{
  "snapshots": [
    {
      "snapshot": "my-snapshot",
      "repository": "my-snapshot-repo",
      "state":"SUCCESS",
      ...
    }
  ]
}

これで、「リフト&シフト」方式による、AWS ESからElasticsearch Serviceへの移行が完了しました。

まとめ

これでElasticsearch Service on Elastic Cloudへの移行が完了したため、AWS ESでは利用できない機能を活用できるようになるだけでなく、Elastic Stackを作成した専門家によってデプロイメントが管理されているという安心感を得ることもできます。使用中に問題が発生した場合は、Elasticのサポートチームの専門家が支援します。 まだElasticsearch Service on Elastic Cloudを利用していない場合は、14日間の無料トライアルで試用してみることをお勧めします。ご質問がある場合は遠慮なくご連絡ください。