$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

プロジェクト単位でElasticsearchのローカル開発環境を作成する

 最近Elasticsearchを触っていて、まずはローカル開発環境を作ることになった。ただ、Elasticsearchはバージョンがかなり変わり、別プロジェクトと利用したいバージョンが異なっていたので、プロジェクト単位で使い分けるにはどうすればよいかを考えた。

やりたいこと

  • プロジェクトごとにElasticsearchのバージョンを切り替えられるようにしたい
    • MySQLだったら同じようなものにmysqlenvなどがある
  • また、他の人が一瞬で環境を整えられるようにしておきたい
  • バージョンを上げる時もローカル環境なら簡単にあげたい

作戦

  • Elasticsearchはここ からダウンロードして、特定のディレクトリに展開するだけでも利用できる
  • そこでプロジェクトルートのelasticsearch/ディレクトリ以下に展開し、ここに展開したバイナリを利用するようにする
  • 一瞬でセットアップできるように、Elasticsearchのセットアップスクリプトを用意し、そこでいい感じにセットアップできるようにする
  • セットアップスクリプトのバージョン情報を少しいじるだけで、アップグレードも行えるようにする

セットアップスクリプトを作る

 セットアップスクリプトに求める機能要件は以下のとおり。

  • 指定したバージョンのElasticsearchが自動でダウンロードされ、elasticsearch/ディレクトリ以下に展開される
  • 必要なプラグインが自動でインストールされる
  • バージョン情報を変えると、自動でそのバージョンに変更してくれる

 また、このセットアップスクリプトの非機能要件としては以下のとおり。

  • 何度実行しても同じ状態になる(冪等である)
  • 必要ないのにデータのダウンロードをしない(高速である)

 冪等であれば、何かあったらもう一回セットアップスクリプトを実行してくれたら直るとか、プラグインを追加した時も何も考えずセットアップスクリプトを実行してくださいということができ、利用が簡単である。また高速であれば、例えば他の開発者に簡単に利用できるようにローカルサーバ起動時に自動でセットアップスクリプトを呼ぶなどをしても、特にストレス無く開発できる。

 このような要件を満たすセットアップスクリプトPerlで作成した。特にPerlである必要はなく、適当に好きな言語を使ってもらっても作れるはず。

setup-local-elasticsearch.pl

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use feature qw(say);

# バージョン情報
my $ELASTICSEARCH_VERSION = '2.3.4';

# tarをdownloadして、elasticsearch/以下に配置するコマンド
# 指定したバージョンのダウンロードリンクからダウンロードし、elasticsearch/ディレクトリ以下に展開する
my $get_elasticsearch_command = <<"COMMAND";
curl -O https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/$ELASTICSEARCH_VERSION/elasticsearch-$ELASTICSEARCH_VERSION.tar.gz 2>/dev/null;
tar zxf elasticsearch-$ELASTICSEARCH_VERSION.tar.gz;
mv elasticsearch-$ELASTICSEARCH_VERSION elasticsearch;
rm -f elasticsearch-$ELASTICSEARCH_VERSION.tar.gz
COMMAND

# ---- ElasticSearchをインストールする ----
if (-e "elasticsearch/") {
    # elasticsearch/ディレクトリがあれば、バージョンの変化がないかチェックし、
    # 変化があれば更新する
    my ($version) = `elasticsearch/bin/elasticsearch --version` =~ /\AVersion: ([0-9.]+)/;
    unless ($version eq $ELASTICSEARCH_VERSION) {
        say "update elasticsearch...";
        system "rm -rf elasticsearch";
        system $get_elasticsearch_command;
        say "elasticsearch update was done";
    }
}
else {
    # そもそもelasticsearch/ディレクトリがなければ新規でセットアップ
    say "Download and install elasticsearch...";
    system $get_elasticsearch_command;
    say "elasticsearch setup was done";
}

# ---- Javaのバージョンの確認を行う ----
# https://www.elastic.co/guide/en/elasticsearch/hadoop/current/requirements.html#requirements-jdk
# によると、JDK 8以上が強く推奨されているのでチェックを行っておく
my ($java_version) = `java -version 2>&1` =~ /java version "(\d+\.\d+)/;
unless ($java_version >= 1.8) {
    say '';
    say "!!!!!!!! NOTICE !!!!!!!!";
    say "Elasticsearch requires recent java.";
    say "Please download and install recent java from the following URL.";
    say "http://www.oracle.com/technetwork/java/javase/downloads/index.html";
    exit 1;
}

# ---- 必要なpluginのインストールを行う ----

# すでにインストールされているプラグインをリストアップ
my $is_installed = do {
    my $output = `elasticsearch/bin/plugin list`;
    my @list = $output =~ /^    - (.+)$/mg;
    +{ map { $_ => 1 } @list };
};

# plugin listで表示される名前と、インストールに利用する名前は違うため
# [ (plugin名), (installに渡す名前) ] の組を書いておく
my $plugins = [
    [ 'head'                     , 'mobz/elasticsearch-head' ],
    [ 'elasticsearch-inquisitor' , 'polyfractal/elasticsearch-inquisitor' ],
    [ 'analysis-kuromoji'        , 'analysis-kuromoji' ],
    [ 'analysis-icu'             , 'analysis-icu' ],
];
for my $plugin (@$plugins) {
    my ($name, $install_name) = @$plugin;
    # すでにインストールされているなら省略
    next if $is_installed->{$name};

    say "Install $name plugin...";
    system "./elasticsearch/bin/plugin install --batch $install_name >/dev/null 2>&1";
}

 このスクリプトを実行しさえすればElasticsearchのセットアップやプラグインのインストールを自動で行うことができる。またすでにセットアップが終わっていればElasticsearchのダウンロードやプラグインのインストールをしないので、二回目以降は高速に実行が出来る。もしバージョンを変えたくなった場合も、スクリプトの最初の方にある$ELASTICSEARCH_VERSION変数を変更して、セットアップスクリプトを実行し直すだけですぐに変更できる。

 あとはこれをプロジェクト全体のセットアップスクリプトに組み込んだり、初期セットアップフローにこれを実行するようにしてもらえば、チームメンバーも簡単にセットアップできるようになる。自分のプロジェクトではプロジェクト全体のセットアップスクリプトがあり、それがローカルサーバ起動時に呼ばれるようになっているので、そちらに組み込んでいる。


 セットアップしたElasticsearchは以下のように起動すれば良い。クラスタ名も明示的に付け、他のプロジェクトと誤ってクラスタリングされないようにしておく。

$ elasticsearch/bin/elasticsearch --cluster.name=myproject

まとめ

 今回はElasticsearchをプロジェクトごとにセットアップする方法についてまとめてみた。個人的にはミドルウェアを入れる場合は、他のメンバーに如何に何も考えずに利用してもらえるようにするかというのを考えていて、このようなセットアップスクリプトを用意するようにしている。参考になればと思う。