Amazon Elasticsearch Service を継続的デリバリする

ども、藤本です。

みなさん、Elasticsearch の運用管理ってどうされていますか?クラスタ管理もそうですし、テンプレート管理もそうですし、テンプレートのテストもそうですし。 最近、Amazon Elasticsearch Service を使ったシステムを構築をしたのでどうするのがいいのかふわっと考えてみました。

概要

Elasticsearch はインストールも簡単ですし、クラスタ組むのも簡単ですし、設定も簡単です。でも、運用していく上でクラスタのノード数を調整したり、クラスタ設定を更新したり、インデックステンプレートを更新したり、スクリプトを更新したり、サービスを継続する上では運用作業が発生します。運用が必要になるのは Elasticsearch に限らずですが。

ドキュメントでもろもろ管理するのは辛いので、ソースコードリポジトリでコードとして構成管理して、アプリケーションの CI/CD のような運用を回したいものです。

考えたのがこういう管理。

一つ一つ説明します。

サンプルコード

サンプルのソースコードを GitHub リポジトリに上げています。

管理対象とツール

クラスタの構成管理

Amazon Elasticsearch Service クラスタの構成はドメインの設定、つまり AWS 上の設定となります。AWS 上の設定なので、CloudFormation を利用することでコードによる構成管理ができます。クラスタの構成とは Elasticsearch バージョン、ノード数、インスタンスタイプ、ディスクサイズ、アクセス制御などです。

Terraformや、Ansible のツールを使うでもよいのですが、CI/CD を考えた時に CodePipeline で CloudFormation Stack を直接操作でき、簡単に構成できることが CloudFormation 採用の理由です。

テンプレートの管理

Elasticsearch ではインデックステンプレート、サーチテンプレートといったテンプレートを扱うことができます。インデックステンプレートを登録することで事前にインデックス作成することなく、任意のアナライザーや、任意のフィールドタイプ、エイリアスを適用することができます。Elasticsearch を全文検索用途で利用するにはほぼ必須の機能です。サーチテンプレートを登録することで Mustache 形式のテンプレートからクエリを展開することができます。何が便利かというと検索のチューニングなどでクエリが変わったりした時にアプリケーション側を変更することなく、Elasticsearch の更新だけで済みます。今回はインデックステンプレート、サーチテンプレートのみを管理しています。テンプレートは Elasticsearch API から実行可能なので SPOT で扱える環境が欲しかったので CodeBuild を利用しました。

CodePipeline から利用できるという点では AWS Lambda でもよいのですが、設定ファイルをソースコードで管理しているので CodeBuild がいいですね。

開発フロー

基本的には GitHub をソースコードリポジトリとしたプルリクエスト運用です。

プルリクエスト

開発者は CloudFormation、Elasticsearch の各種テンプレートを開発ブランチで修正し、プルリクエストを起票します。プルリクエストに対しては CodeBuild による自動テストを行います。どこまでテストをやるべきなのかまだ悩み中ですが後述します。CodeBuild のテスト結果はプルリクエストに成功、失敗をフィードバックします。
また合わせて、レビュアーによりコード、および設定ファイルをレビューします。

自動テスト、レビューを通過した変更がリリースブランチにマージされることで本番環境へ適用されるコードの品質を高めることができます。

CodeBuild の自動テスト、テスト結果のフィードバックに関しては下記記事をご参照ください。

CodeBuild で GitHub のプルリクエストを自動ビルドして、結果を表示する

デプロイ

リリースブランチにマージ(プッシュ)をトリガーに CodePipeline が起動します。
マージされた変更内容が複数のプルリクエストの可能性もあるのでリリース前に再度テストを行います。
テストを通過したら、CloudFormation Stack に Update Stack を実行し、Amazon Elasticsearch Service のクラスタをアップデートします。
Amazon Elasticsearch Service のアップデートが完了したら、CodeBuild 上でスクリプトにより、Elasticsearch クラスタへインデックステンプレート、サーチテンプレートを適用します。

今回はシステムの用途上、ステージング環境を用意していないのですが、CodePipeline の承認アクションを利用して、本番環境へリリースする前にステージング環境でのテストを行うことでより安全に本番環境へデプロイできるかと思います。CodePipeline の承認アクションに関しては下記エントリをご参照ください。

CodePipeline で承認プロセスを設けて本番環境へリリースする #reinvent

各サービスでやっていることをもう少し詳しく

CodeBuild による自動テスト

プルリクエストに対する自動テスト、デプロイ時の自動テストは同じテストを行っています。
CloudFromation テンプレートには ValidateTemplate API によるチェックを行います。ValidateTemplate は構文チェックのみで設定値の妥当性までは確認してくれないのでもう少し何かしたい感。
Elasticsearch のインデックステンプレートには実際に Elasticsearch に適用し、インデックステンプレートに合致するデータを投入し、想定するインデックス設定になっているかをテストします。
サーチテンプレートには同じく Elasticsearch に適用し、テストデータを投入し、想定通りのクエリ結果が返ってくるかをテストします。

テスト用の Elasticsearch は Elastic 社公式の Docker イメージからコンテナを起動して利用します。

具体的な実装イメージはサンプルソースコードの buildspec-test.yml をご参照ください。

テストは Python の pytest で書いているのですがソースコードのテストではなく、Elasticsearch への API 操作だったり、レスポンスのテストを行っているだけなので使い慣れた言語、テストフレームワークでいいと思います。

Elasticsearch へのデプロイ

Elasticsearch へのデプロイは Elastic 社の Python 公式ライブラリである elasticsearch-py を利用しています。CodeBuild で AWS が提供する Python の Docker イメージを利用して、インデックステンプレート、サーチテンプレートをそれぞれ特定のディレクトリに配置し、順次、Elasticsearch API でリクエストして、登録しているだけです。登録だけだと登録、更新はできても、存在しなくなったテンプレートの削除ができないので、必要に応じて事前に一度、テンプレートを全削除して新規登録するデプロイでもよいかもしれません。

デプロイスクリプトの実装イメージはサンプルソースコードの deploy.py をご参照ください。

といった感じで実装してみました。運用してみて問題があったり、改善したりすることがあれば、また別途ブログエントリします。

まとめ

いかがでしたでしょうか?
Infrastructure as Code は Amazon Elasticsearch Service の運用にも適用することができます。手作業を減らして、運用コストを削減し、かつ安全に本番環境の変更を行いましょう。