[Firebase] CloudFunction(トリガー) + AWS Elasticsearch でハマった点のまとめ

# [Firebase] CloudFunction(トリガー) + AWS Elasticsearch でハマった点のまとめ

`Firestore/RealtimeDatabase` + `CloudFunction(トリガー)`
=> `AWS Elasticsearch`

上記の構成を作ったので、そのときの構築時の気付き・ハマった点のまとめ。

## はじめに

Firebase では全文検索機能が提供されていないので、公式ドキュメントに従うなら Algolia を導入することになるかと思う。

ただ、金額面やインフラ面で全文検索に AWS Elasticsearch（以後 AWS ES）を導入することもあるかと思う。

### 構成

Firestore / RealtimeDatabase に対するデータ追加・変更・削除をトリガーにして、CloudFunction を実行して、Elasticsaerch 側にもデータを流す。

## Firebase のプランの変更

**Firebase のプランを、Spark から Blaze へ変更が必須です。**

無料プランの Spark では Google サービス内で閉じた通信しか許可されてません。CloudFunction から AWS ES というネットワーク越しの通信を行う必要がある場合は定量課金の Blaze プランへの変更が必要になります。

Production 環境だけでなくて dev/staging の環境でも同じようにプランを上げないといけないです。

## CloudFunction Trigger が AWS ES へ接続する時の credentials とデプロイ

CloudFunction が AWS ES へ接続するときに、CloudFunction の AWS SDK が env にある credentials を読み込むけど、CloudFunction がデファクトで提供している config な方法ではないので、少しハックなやり方などが必要になります。

まず前提として、今回の構成では Firebaes の Realtimedatabase / Firestore に対する mutation をトリガーに Cloud Function を発火します。

このとき CloudFunction から AWS ES へ接続する方法として、`aws-sdk` というパッケージを使って認証＋接続しますが、認証もするので credential(id/key) が必要です。

この credentials はいくつかの方法で読み込むことはできるのですが、ただ、JSON / credentials のファイルでの読み込みはファイルをデプロイできない CloudFunction では出来ないので、実質は環境変数を使うことになるかと思います。

- [Node.js での認証情報の設定 - AWS SDK for JavaScript](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html)

ただ、ここでデプロイするコマンドとの相性が問題です。

credential の情報は環境変数に設定させる必要があるので、デプロイするときに CloudFunction 側への環境設定を指定するのだけど、firebase のデプロイコマンドの`firebase deploy`が環境変数の受け渡しをサポートしていないので、下記の方法などで無理くりデプロイしないといけないです。

- [Firebase: Cloud Function の Trigger にて config ではなく process.env の環境変数を設定する - Qiita](https://qiita.com/snamiki1212/items/b2c62eed04212fafe2af)

## Cloud Functions から AWS ES への認証・接続

基本的に公式の方法に従い aws-sdk 経由での接続になります。

axios や fetch などの HTTPClient で接続しようかと思ってたんですが、コネクション周りが認証とも密結合になってる感じなので基本的には出来ないみたいです。

（オレオレで通信レイヤーも作り込めるかもですが、大変そうだったので諦めました。）

## AWS ES だとビルトイン以外のプラグインを入れられない

**AWS ES では、ビルトインに入っているプラグイン以外は自分で入れることが出来ないです。**

AWS ES では、よく使われるプラグインがデフォルトで入れられています。具体的には、kuromoji、ICU などです。

- [Amazon AWS Elasticsearch installing plugins and files - Stack Overflow](https://stackoverflow.com/questions/48216842/amazon-aws-elasticsearch-installing-plugins-and-files)

その代わりに、それ以外のプラグインを自分で入れることができないです。

とはいえ、一般的な運用ならこの２つに対する CharFilter/Tokenier/TokenFilter が入っていれば十分だと思いますが。

## Elasticsearch と AWS ES は別物と考えておいたほうがよい

検証用などに Docker などで Elasticsearch のコンテナなどを使わずに、dev/staging/prod で AWS ES を使うほうが良いです。

今回、ES での開発が初めてだったので、ローカルに Docker の ES を立てて、ここでいろいろ稼働確認してから AWS ES の構築を行ったけど、あまりよくない流れでした。

というのも、Elasticsearch と AWS ES でできることが下記のように微妙に違うからです。

- AWS ES では Tokenizer などのプラグインは自動で入ってる。なので、設定すればすぐに使える。逆に追加はできない。
- AWS ES では一部の API や変更できる設定値が少ない。具体的には、\*でインデックスを DELETE できないように設定するべき `-XPUT /_cluster/settings -d "persistent": {"action.destructive_requires_name": true }` ができない。など。

なので、AWS ES で開発するときは、Elasticsearch ではなくて直接 AWS ES をいじって作っていったほうが良かったです。

## AWS ES に ssh 接続できない

できないです。

- [Amazon Elasticsearch Service トラブルシューティング - Amazon Elasticsearch Service](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/aes-handling-errors.html)

## REF

- [Amazon Elasticsearch Service の認証・認可に関する面倒くさい仕様をなるべくわかりやすく説明する - 無印吉澤](https://muziyoshiz.hatenablog.com/entry/2019/11/30/144213)
- [[小ネタ]Amazon Elasticsearch Service/Kibana にユーザ認証でアクセスしてみる | Developers.IO](https://dev.classmethod.jp/articles/amazon-elasticsearch-service-kibana-iamuser/)