BETA

ElasticsearchをMastodonとは別のサーバに設置する

投稿日:2019-04-19
最終更新:2019-09-09

新しくVPSを借りたので、そこにElasticsearchのサーバをたてたい! という話がありました。

よい機会なので、Elasticsearchのインストールからsudachiを使えるようにする設定変更まで、ざっくり記録しておこうと思います。

Elasticsearchをインストールする

説明のために、サーバはUbuntu 18.04という前提で話を進めますが、動けばなんでもOKです。

まずはjavaの実行環境から

さくっとOpenJDK 11を入れます。

sudo apt install openjdk-11-jre  

Elasticsearchを入れる

記事執筆時点では、elasticsearch 7.3.1が最新です。aptにパッケージの取得元と鍵を追加してinstallします。

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -  
sudo apt install apt-transport-https  
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list  
sudo apt update  
sudo apt install elasticsearch  

環境変数JAVA_HOMEを設定しておきます。

echo "JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64" | sudo tee -a /etc/default/elasticsearch  
echo "JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64" | sudo tee -a /etc/environment    
source /etc/environment   

elasticsearch.ymlに設定を追加します。

  • クラスタ名を何か付ける(例:mastodon-search
  • ノード名を${HOSTNAME}にする(識別できれば何でもOK)

複数のサーバを設置してクラスタを構成することで、負荷を分散したり、レプリカを持たせたりできますが、ここでは1台だけで構成します。

cat <<-_EOS_ | sudo tee -a /etc/elasticsearch/elasticsearch.yml  
cluster.name: mastodon-search  
node.name: ${HOSTNAME}  
_EOS_  

jvm.optionsにJVMのヒープサイズの設定をします。サーバのメモリの35%50%ぐらいを割り当てるのが目安だそうです。ここでは、2GBのVPSという想定で、既存の設定をコメントアウトして、新たに512MBずつ割り当てます。

sudo sed -i -E 's/-Xms/#&/;s/-Xmx/#&/' /etc/elasticsearch/jvm.options  
cat <<-_EOS_ | sudo tee -a /etc/elasticsearch/jvm.options  
-Xms512m  
-Xmx512m  
_EOS_  

analysis-sudachiを入れる

必要なファイルを取ってきて、analysis-sudachiをインストールします。辞書を取ってきて/etc/elasticsearch/に展開。sudachi.jsonを作成して、使用する辞書の指定と、いくつかの補助設定をしておきます。

wget https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v7.3.1-1.3.0/analysis-sudachi-elasticsearch7.3.1-1.3.0.zip  
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install file://${PWD}/analysis-sudachi-elasticsearch7.3.1-1.3.0.zip  
sudo apt install unzip  
wget https://object-storage.tyo2.conoha.io/v1/nc_2520839e1f9641b08211a5c85243124a/sudachi/sudachi-dictionary-20190718-full.zip  
unzip sudachi-dictionary-20190718-full.zip  
sudo mv sudachi-dictionary-20190718/system_full.dic /etc/elasticsearch/  
sudo chown root:elasticsearch /etc/elasticsearch/system_full.dic  
cat <<-_EOS_ | sudo tee -a /etc/elasticsearch/sudachi.json  
{  
    "systemDict" : "/etc/elasticsearch/system_full.dic",  
    "userDict" : [],  
    "inputTextPlugin" : [  
        { "class" : "com.worksap.nlp.sudachi.DefaultInputTextPlugin" },  
        { "class" : "com.worksap.nlp.sudachi.ProlongedSoundMarkInputTextPlugin",  
          "prolongedSoundMarks": ["ー", "-", "", "", ""],  
          "replacementSymbol": "ー"}  
    ],  
    "oovProviderPlugin" : [  
        { "class" : "com.worksap.nlp.sudachi.MeCabOovProviderPlugin" },  
        { "class" : "com.worksap.nlp.sudachi.SimpleOovProviderPlugin",  
          "oovPOS" : [ "補助記号", "一般", "*", "*", "*", "*" ],  
          "leftId" : 5968,  
          "rightId" : 5968,  
          "cost" : 3857 }  
    ],  
    "pathRewritePlugin" : [  
        { "class" : "com.worksap.nlp.sudachi.JoinNumericPlugin",  
          "joinKanjiNumeric" : true },  
        { "class" : "com.worksap.nlp.sudachi.JoinKatakanaOovPlugin",  
          "oovPOS" : [ "名詞", "普通名詞", "一般", "*", "*", "*" ],  
          "minLength" : 3  
        }  
    ]  
}  
_EOS_  

ユーザー辞書を追加すると良いのですが、ここでは説明を割愛します。テーマサーバでは、語彙を増やしておきたいですね!

起動する

systemctlで起動します。

また、バージョンが変わる時にsudachi等のプラグインを再インストールする必要があるので、aptで勝手に更新されないようにロックしておきます。

sudo systemctl start elasticsearch  
sudo apt-mark hold elasticsearch  

外から繋げられるようにリバースプロキシとファイアウォールを設定する

elasticsearchには、ノード間の通信とREST APIにTLSを適用するオプションがありますが、REST APIについてはnginxなどリバースプロキシでhttps接続できるようにする方が設定が簡単で安全と思われます。

REST APIはポート9200を使いますが、伏せる意味でもあえて異なるポート(ここでは9100)で受け付け、ファイアウォールで接続元をMastodonサーバに限定します。

というわけで、ここではnginxとcertbot、ufwを使います。インストールからざっと説明しますが、既に入っている場合は設定だけ参考にしてください。

なお、ここではDNSにcloudflareを使っているという想定で、certbotのdnsプラグインも追加しておきます。ご自身の環境に合わせて選択してください。(このあたりについてはLet's Encrypt(certbot)で、TLS-SNI-01の削除により証明書の更新に失敗する問題への対応の中で説明しています)

ufwは、ssh(22)と、9100ポートへの接続を許可します。
sshに22以外を使っている場合は各自変更してください。他の必要なポートがある場合も忘れずに開放しておきましょう。

sudo apt install nginx certbot python3-certbot-dns-cloudflare ufw  
sudo ufw allow 22/tcp  
ufw enable  

で、Mastodonを実行しているサーバからだけ、elasticsearchの9100ポートに接続を許可します。

sudo ufw allow from (Mastodonを実行しているサーバのIPv4アドレス) to any port 9100 proto tcp  
sudo ufw allow from (Mastodonを実行しているサーバのIPv6アドレス) to any port 9100 proto tcp  

certbotはdns-01で認証します。/etc/letsencrypt/.cloudflare_credentialsにアカウントとAPI Keyが保存されている想定です。

certbot certonly --dns-cloudflare --rsa-key-size 4096 --dns-cloudflare-credentials /etc/letsencrypt/.cloudflare_credentials -d example.com -m [email protected] --manual-public-ip-logging-ok --agree-tos --no-eff-email  

nginxの設定は、/etc/nginx/sites-available/elasticsearch.confに書いて、

cat <<-_EOS_ | sudo tee -a /etc/nginx/sites-available/elasticsearch.conf  
map $http_upgrade $connection_upgrade {  
  default upgrade;  
  ''      close;  
}  

server {  
  listen 9100 ssl http2;  
  listen [::]:9100 ssl http2;  
  server_name example.com;  

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;  
  ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;  
  ssl_prefer_server_ciphers on;  
  ssl_session_cache shared:SSL:10m;  

  ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;  
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;  

  location / {  
    proxy_pass http://127.0.0.1:9200;  
    proxy_buffering off;  
    proxy_redirect off;  
    proxy_http_version 1.1;  
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection $connection_upgrade;  

    tcp_nodelay on;  
  }  

  location /statuses_ {  
    if ( $request_method ~ ^(PUT)$ ) {  
      rewrite ^(.+)$ $1?include_type_name=true break;  
    }  
    proxy_pass http://127.0.0.1:9200;  
    proxy_buffering off;  
    proxy_redirect off;  
    proxy_http_version 1.1;  
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection $connection_upgrade;  

    tcp_nodelay on;  
  }  

  location ~ _search$ {  
    rewrite ^(.+)$ $1?rest_total_hits_as_int=true break;  
    proxy_pass http://127.0.0.1:9200;  
    proxy_buffering off;  
    proxy_redirect off;  
    proxy_http_version 1.1;  
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection $connection_upgrade;  

    tcp_nodelay on;  
  }  
}  
_EOS_  

/etc/nginx/sites-enabled/elasticsearch.confにシンボリックリンクを張ります。

cd /etc/nginx/sites-enabled  
sudo ln -s /etc/nginx/sites-available/elasticsearch.conf  

nginxの設定に記述間違いがないかテストして

sudo nginx -t  

nginxを再起動(起動してなければstart、起動していればreloadの方が良い)

systemctl restart nginx  

動作確認

そもそもサービスが起動しているのか確認

sudo systemctl status elasticsearch  

ダメっぽかったらjournalを見る

sudo journalctl -ru elasticsearch  

リアルタイムにモニターする場合はこう

sudo journalctl -fu elasticsearch  

ダメならログをみる

sudo less /var/log/elasticsearch/mastodon-search.log  

ローカルからREST APIで状態を確認。バージョンとか色々でる。

curl http://localhost:9200/   

リバースプロキシにhttpsで接続

curl https://example.com:9100/   

インデックスの一覧をみる(今は何もないけど見出しだけ出る)

curl https://example.com:9100/_cat/indices?v  

Mastodon側の設定

elasticsearchのサーバに繋がるかどうか真っ先にテストしておきましょう。

curl https://example.com:9100/   

.env.production

.env.productionで、elasticsearchを有効にし、サーバとポートを指定し、プリフィックスを指定します。

プレフィックスを指定すると、elasticsearchが他のMastodonサーバの検索など他の役割を引き受けている場合にインデックスを区別できます。

ES_ENABLED=true  
ES_HOST=https://example.com  
ES_PORT=9100  
ES_PREFIX=example  

app/chewy/statuses_index.rbapp/services/search_service.rb

Mastodon本体のコードにも修正が必要です。

app/chewy/statuses_index.rbapp/services/search_service.rbを、sudachiを活用するように修正します。具体的な内容は、githubのコミットを参照してください。
https://github.com/noellabo/mastodon/commit/e2214ec9844d1e17c219065e1034814077b39119

こちらをgit cherry-pickするか、差分を見ながら自分で修正してください。

sudo -iu mastodon  
cd ~/live  
git remote add noellabo https://github.com/noellabo/mastodon.git  
git fetch noellabo  
git cherry-pick e2214ec9844d1e17c219065e1034814077b39119  

この変更で、sudachiの力によって日本語を適切に扱えるようになります。また、IDでソートすることで、検索結果の表示を最新順にしています。

Mastodon側からdeployする

過去の記事をインデックスし、検索できるようにします。

tootctlに専用のコマンドがあります。mastodonのliveディレクトリにて、

bin/tootctl search deploy  

を実行します。投稿が多数蓄積されているサーバでは時間がかかるので覚悟した方が良いです。tmux等でssh接続が切れても大丈夫なように対策しておきましょう。

設定に不備があったりすると早めにエラー終了するので、内容に応じて対処してください。

Mastodonの再起動

.env.productionとコードの変更を反映させるため、再起動します。deployの時点で書き間違え等によるエラーはあらかた出尽くしているかと思いますが、ちゃんと動くかどうか色々確かめてください。

sudo systemctl restart mastodon-*  

【オマケ】elasticsearchをアップデートする

遠からず、elasticsearchのアップデートに対応する時が来ると思います。その際の手順の参考です。

  • elasticsearchのプラグインはバージョンチェックが厳密で、本体のバージョンと完全一致したものを使う必要があり、毎回削除して入れ直しが必要
  • なので、本体だけうっかりアップデートすると死ぬので、普段はapt-markでholdしておくこと
  • https://github.com/WorksApplications/elasticsearch-sudachi/releases からanalysis-sudachiの最新リリースをチェックし、対応版がでてから切り替えるのが吉
    • 自分でpom.xmlを書き換え、関連する箇所を修正してビルドしても良いが、ここでは割愛する

analysis-sudachiのv7.0.1-1.3.0にアップデートする例を挙げておきます。実際に適用する際は、zipファイルのファイル名nalysis-sudachi-elasticsearch7.0.1-1.3.0.zipとURLhttps://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v7.0.1-1.3.0/analysis-sudachi-elasticsearch7.0.0-1.3.0.zipの記載箇所を入れ替えて実行してください。

sudo /usr/share/elasticsearch/bin/elasticsearch-plugin remove analysis-sudachi  
sudo apt-mark unhold elasticsearch  
sudo apt install elasticsearch  
sudo apt-mark hold elasticsearch  
wget https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v7.0.1-1.3.0/analysis-sudachi-elasticsearch7.0.1-1.3.0.zip  
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install file://${PWD}/analysis-sudachi-elasticsearch7.0.1-1.3.0.zip  
sudo systemctl restart elasticsearch  

謝辞・参考資料

MastodonでのElasticsearchの設定方法については、なんと言ってもクラゲ丼のぜまさんの記事が先駆けです。私も大変お世話になりました。本記事の設定部分の記述については、ほぼそのままお借りしています。

また、nginxの設定の箇所で採用した、Elasticsearch 7.xに対応するための互換オプションをnginxでrewriteするという手法は、Balさんが編み出した手法をお借りしています。めっちゃスマートな解法です。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@noellaboの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!