読者です 読者をやめる 読者になる 読者になる

PHP の Elasticsearch クライアント Elastica で Amazon ES に接続する

PHP から Elasticsearch を操作するために Elastica というライブラリを使っている.今まで EC2 で運用していた Elasticsearch を Amazon ES に移行する話があり,Elastica から Amazon ES を操作するときに悩むことが多かったため,まとめておこうと思う.

github.com

ちなみに,僕は使ったことはないけれど,Elastic 社から公式に提供されている elasticsearch-php というライブラリもある.ただ,Elastic 社の公式ライブラリだと,積極的に Amazon ES 対応をすることはないだろうし,Amazon ES を使う場合は,サードパーティライブラリの Elastica の方が良い気がする.

github.com

Amazon ES に接続する方法

Amazon ES に接続する方法を復習しておくと,大きく3種類ある.

  • リソースベース
  • IP ベース
  • IAM ユーザーとロールベース

docs.aws.amazon.com

今回のように,アプリケーションから Amazon ES に接続する場合は IAM を使う.IAM Role を使うのがベスト.必要に応じて IP 設定を変更して運用することも考えられるが,Amazon ES で IP 設定を変更すると,ノードが全台作り直されてしまうため,クラスタのデータ規模によっては1時間程度待たされることもあるので,実質不可能だと思うし,そもそも,アーキテクチャ的に微妙すぎる.

また,IP ベースの場合は未署名の匿名リクエストも受け付けることができるが,IAM を使う場合,署名付きリクエスト(AWS 署名バージョン 4)を送る必要がある.よって,ライブラリが署名付きリクエストに対応している必要がある.

docs.aws.amazon.com

docs.aws.amazon.com

Elastica から Amazon ES に接続する

github.com

Issue を見ると,Elastica は既に署名付きリクエストの対応がされているが,実装例などのドキュメントが全くなくて,よくわからなかった.困ったので Gitter で聞いてみたら,すぐ教えてもらうことができて助かった.簡単過ぎるけど,今回の構成をまとめた.

f:id:kakku22:20170407002340j:plain

ライブラリをインストールする

署名付きリクエストを送るためには,Elastica 3.1.1 以上が必要になる.ただし,このままで実行すると,以下のエラーが出る.

Class 'GuzzleHttp\Psr7\Uri' not found

Elastica の composer.json を見ると,suggest プロパティに以下の設定がある.suggest とは,基本的には必要ないけど,入れておくと便利な依存パッケージのことを意味している.Ruby の Gemfile にはそういう概念がないため,今まで知らなかった.

{
    (中略)
    "require-dev": {
        "aws/aws-sdk-php": "~3.0",
        "guzzlehttp/guzzle": "~6.0"
    },
    "suggest": {
        "aws/aws-sdk-php": "Allow using IAM authentication with Amazon ElasticSearch Service",
        "egeloen/http-adapter": "Allow using httpadapter transport",
        "guzzlehttp/guzzle": "Allow using guzzle 6 as the http transport",
        "monolog/monolog": "Logging request"
    },
    (中略)    
}

よって,Amazon ES に IAM で接続する場合は,以下のような composer.json になる(バージョン設定はご自由に).

{
    (中略)
    "require": {
        "ruflin/Elastica": "~3.2",
        "aws/aws-sdk-php": "~3.25",
        "guzzlehttp/guzzle": "~6.2"
    },
    (中略)
}

まだ aws/aws-sdk-php v2 を使っていると動かないため,合わせて aws/aws-sdk-php をバージョンアップする必要がある.

Elastica のクライアント実装

以下のように transportAwsAuthV4 を設定して,aws_region を設定すると,Amazon ES に IAM で接続できるようになる.

$client = new Elastica\Client(
    array(
        'host'       => 'xxx.ap-northeast-1.es.amazonaws.com',
        'port'       => 80,
        'transport'  => ['type' => 'AwsAuthV4', 'postWithRequestBody' => true],
        'aws_region' => 'ap-northeast-1'
    )
);

もし IAM Role ではなく,クレデンシャルを埋め込む場合(非推奨な実装)は,以下のようになる.

$client = new Elastica\Client(
    array(
        'host'                  => 'xxx.ap-northeast-1.es.amazonaws.com',
        'port'                  => 80,
        'transport'             => ['type' => 'AwsAuthV4', 'postWithRequestBody' => true],
        'aws_access_key_id'     => 'yyy',
        'aws_secret_access_key' => 'xxx',
        'aws_region'            => 'ap-northeast-1'
    )
);

まとめ

  • Elastica は Amazon ES の接続をサポートしている
  • ドキュメントが詳しくないため,困ったら Gitter で聞いてみると良い
  • 必ず IAM Role を使おう

参考情報 : Amazon ES を運用するときに知っておくと便利なこと

kakakakakku.hatenablog.com