新しく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 admin@example.com --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.rb
とapp/services/search_service.rb
Mastodon本体のコードにも修正が必要です。
app/chewy/statuses_index.rb
とapp/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さんが編み出した手法をお借りしています。めっちゃスマートな解法です。