Solr Operatorを利用したKubernetes上での検索システムの構築について

エンジニアの竹田です。
BUYMAの検索システムやMLOps基盤の開発・運用を担当しております。

今回はSolr Operatorによる検索システム構築を行いましたので、その実施内容と得られた知見についてご紹介したいと思います。

はじめに

昨期から今期にかけて、オンプレミスのシステムからの脱却、およびマイクロサービス化を目指し、商品検索システムのリプレイスを進めていました。
エニグモでは機能毎にApache Solrを用いた複数の検索システムを保持しており、クラウド移行に伴い、構築面や運用面の負担は大幅に軽減できております。

なお、リプレイスを行った商品検索システムの構成も下記の記事と大きくは変わっていません。 tech.enigmo.co.jp

今回フォーカスする検索システムの課題

検索システムの運用には、開発案件や障害対応、システムのバージョンアップやシステム増強作業などがあります。
中でも開発案件は、本番と同等のデータを利用したシステムにて検索の並び順や検索ヒット内容の検証が必要となる場合があります。

今まではオンプレミス環境にそのシステムを構築していましたが、今回の商品検索のクラウド移行に合わせ、同環境をクラウド上に構築することになりました。

システムのライフサイクルが短いため、より簡素に構築・廃棄を行えるようにしたいという課題があり、そこで案として出たのがSolr Operatorの利用です。
結果次第ではサービス運用でも利用できる可能性も考慮してSolr Operatorを利用した構築の検証を行いました。

なお、本記事ではある程度KubernetesApache Solrのことをご存知の方を対象としている点をご容赦ください。

Solr Operatorについて

Welcome - Apache Solr Operator
Solr OperatorはKubernetesのCRD(Custom Resource Definition)として提供されているもので、SolrCloudやZookeeperClusterといったkindによりSolrシステムを一元管理するイメージという理解で良いかと思います。 2023/04/24にv0.7.0がリリースされています。

Solr Operatorの概要や簡素な構築方法については、Google CloudのShimojo様が非常に分かりやすいブログ記事を公開されていますので是非ご参考にしてみてください。

  • Solr Operator を利用して SolrCloud クラスタを GKE Autopilot に構築する (前編) zenn.dev

  • Solr Operator を利用して SolrCloud クラスタを GKE Autopilot に構築する (後編) zenn.dev

構築時の簡単な構成は、以下のようになっています。
Zookeeper Operatorについては特に触る必要がなかったため、本記事では触れていません。

構成図

Solr Operator CRDの各リソース項目について

Solr OperatorはCustom Resource Definition(CRD)として提供されており、項目に合わせて定義を埋めていく形になります。
構成管理を考えた場合、helm installでSolrCloudクラスタを構築する際に適宜パラメータとして指定するよりも、Kubernetesマニフェストとして管理するのが望ましいと思われます。 ※helm installではなく、マニフェストを作成してkubectl apply -f <作成したマニフェストのyamlファイル>で構築する方式

以下に、kind: SolrCloudにおいて利用頻度が高いと見込まれるパラメータを列挙してみました。

spec配下の設定項目 内容 備考
solrImage 利用するsolrのコンテナイメージを指定 独自ビルドしたイメージも指定可能
solrOpts solr起動時のパラメータを指定
solrJavaMem javaのヒープサイズを指定
solrAddressability solrの解放ポートや外部接続定義を指定
solrGCTune GarbageColleciton用のチューニングパラメータを指定
customSolrKubeOptions solrのカスタム項目を指定 (※1)
updateStrategy solrの更新方式をを指定 未指定時のデフォルトがrollingUpdateのため注意
dataStorage solrのデータ格納先ストレージ persistentにして永続ディスクを利用
replicas solr podのレプリカ数

(※1) 以下、customSolrKubeOptions配下の項目

spec.customSolrKubeOptions配下の設定項目 内容 備考
ingressOptions 外部にingressを利用している場合に利用 annotationsでBackendConfigを指定するなどで利用
configMapOptions providedConfigMapにカスタムConfigMapを指定 solr.xmllog4j2.xmlを定義できる
podOptions solr podに対するオプション項目 (※2)

(※2) 以下、podOptions配下の項目

spec.customSolrKubeOptions.podOptions配下の設定項目 内容 備考
resources CPUやメモリのlimits/requestsを設定
livenessProbe Solrが動作しているかどうか 指定しないとhealthcheckが通らず、podが起動しない
readinessProbe Solrがトラフィックを受けられるかどうか 指定しないとhealthcheckが通らず、podが起動しない
initContainers Solr PodのinitContainersを定義できる
sidecarContainers Solr Podに設置するサイドカーコンテナを定義できる

あくまでサンプルですが、以下のようなマニフェストになるかと思います。

apiVersion: solr.apache.org/v1beta1
kind: SolrCloud
metadata:
  name: example
  namespace: solr
spec:
  replicas: 3
  solrImage:
    tag: 9.2.1
    pullPolicy: IfNotPresent
  solrGCTune: -XX:NewRatio=3 -XX:SurvivorRatio=4
  solrJavaMem: -Xms2048M -Xmx2048M
  solrAddressability:
    commonServicePort: 8983
  updateStrategy:
    method: StatefulSet
  dataStorage:
    persistent:
      pvcTemplate:
        spec:
          resources:
            requests:
              storage: 100Gi
      reclaimPolicy: Retain
  customSolrKubeOptions:
    configMapOptions:
      providedConfigMap: solr-config-map # configMapは先に作成・適用しておく必要がある
    ingressOptions:
      annotations:
        cloud.google.com/backend-config: '{"ports": {"8983":"solrcloud-backend-config"}}'
        cloud.google.com/neg: '{"ingress": true}'
    podOptions:
      resources:
        limits:
          cpu: 2
          memory: 6Gi
        requests:
          cpu: 2
          memory: 6Gi
      livenessProbe:
        initialDelaySeconds: 30
        periodSeconds: 10
        httpGet:
          scheme: HTTP
          path: /solr/admin/info/health
          port: 8983
      readinessProbe:
        initialDelaySeconds: 15
        periodSeconds: 5
        httpGet:
          scheme: HTTP
          path: /solr/admin/info/health
          port: 8983

補足となりますが、Solrが起動しない場合は、概ね以下の方法で原因を特定できます。

  • Solr Podをkubectl describeで確認
    kubectl describe pod example-solrcloud-0 -n solr
  • solr-operator Podをkubectl logsで確認
    kubectl logs solr-operator-xxxxxxxxxx-xxxx -n solr

マニフェスト適用後は、solrスキーマ定義やsolrconfig.xmlの配置、コレクションの作成と進めて検索できる状態にします。
こちらの作業についての手順は割愛します。

Solr起動後の管理画面等への接続については、上記で図示した通りingress経由としました。

実際に構築してみた所感

まだ検証段階ではありますが、以下の恩恵を得られるものと思います。

  • Zookeeperを特に意識しなくて良い
  • ディレクトリ構成も基本的には意識しなくて良い
    • SolrCloudを構築する上でのSolrの学習コストが下がる
  • マニフェストさえ用意しておけばSolrCloudシステムの作成、削除がkubectlコマンド一発で完遂する
    • CRDの項目が充実しており、かなり細かい点まで定義可能

苦労した点としては以下になります。

  • マニファストの設定誤りや漏れがあると結構ハマる
    • 特にヘルスチェック、リソース定義周りの定義誤りは何が問題なのか分かり辛い
  • CRDはかなり長大なマニフェストのため読み解くのが大変
  • 日本語での参考文献がほとんどない

運用利用に当たっては以下の項目を意識・検討する必要があることも分かりました。

  • Solr Operatorで構築できるのはSolrのインフラ面のみ
    • Solrのスキーマ定義や構成ファイルの配置はconfigsets APIzkCliコマンドを利用する必要がある
  • アクセス周りのセキュリティを気にしておく必要がある
  • 監視関連の定義は別途検討の必要がある
    • エニグモでは検索システムの監視にDatadogを利用しているため、対応方法を調査・検討する必要あり
    • Solr Prometheus Exporterを利用する方法もある
  • 用途の異なる検索システムを1つのSolrCloud kindに集約しない方が良いかもしれない
    • Solr Podの名称がprefix固定の連番suffix(例: xxx-solrcloud-1xxx-solrcloud-2)での管理となるため、Pod名称から用途が判別し辛い
  • 実サービスでの利用はAutopilotクラスタよりStandardクラスタの方が良いかもしれない
    • オートスケールに時間を要するため、ある程度リソースが確保された状態でないと運用は難しそう
  • Solr Operator自体のバージョンアップへの追従

また、合わせてSolr構成も見直した方が良いと感じました。

  • NRTや全TLOGのレプリカタイプでコレクションを作成した方が良い
    • 1podがダウンしても更新や検索に影響のないシステム構成にする必要あり
    • 必然的にDataImportHandlerのようにデータをpullする方式の採用は難しくなる

検証用途には手順を圧縮できるため便利に感じる一方、サービス運用には検討すべきことが多いという印象でした。
業務等でSolr Operatorの利用を検討されているようでしたら、本記事が一助になれば幸いです。

最後に

弊社では、本記事に記載したような新しい取り組みや、より良いシステムを作りを一緒に進めていくためのメンバーを随時募集しています!

株式会社エニグモ すべての求人一覧

hrmos.co