
Elasticsearch
イベント
該当するコンテンツが見つかりませんでした
マガジン
技術ブログ
はじめに 検索基盤チームの mrkm4ntr です。以前、 CPU 使用率による Elasticsearch の autoscaling について書きました。ピーク時間帯に合わせて確保していたリソースを、トラフィックに合わせて増減することで、Elasticsearch のコストを約 40% 削減できました。 この autoscaling には、まだコストを削る余地が残っていました。この記事では、そのために行った 2 つの改善を紹介します。 scale-out の高速化 : shard のコピー待ちをなくすために、PVC に shard を事前に同期しておく仕組みを作りました。 HPA の tolerance の調整 : 1 のおかげで HPA の CPU threshold を高くできるようになった結果、tolerance が新しい問題になりました。これを HPA ごとの設定と CronJob で解消しました。 課題 scale-out が間に合わない Elasticsearch のノードを増やすと、新しいノードには他のノードから shard が複製されます。これが Peer Recovery で、大きく 2 つのステップに分かれます。 ファイルコピー : primaryが持つ segment ファイルを、ネットワーク越しに新しいノードへ丸ごとコピーします。 差分の追い付き : コピーしている間にも更新は続くので、その間に発生した変更を translog から再生して追い付きます。 時間がかかるのはほとんどが 1 です。私たちのクラスタは 1 shard が大きく、コピーが終わるまで 10 分以上かかります。その間、新しいノードは検索を処理できません。 threshold を下げて凌いでいた HPA は、負荷が上がったことを検知してから台数を増やします。ノードが使えるようになるまで 10 分以上待つことになると、急なトラフィック増には間に合いません。 そこで、HPA の CPU 使用率の threshold をあえて 65% 前後と低めに設定し、まだ余裕があるうちに早めに scale-out を始めるようにしていました。scale-out の遅さを、平常時の余裕で補っていたことになります。 安全ではありますが、その余裕のぶん、autoscaling で得られるコスト削減は小さくなります。 改善 1: PVC 事前同期で scale-out を高速化する アイデア Peer Recovery が遅いのは、新しいノードのディスクにデータがなく、ステップ 1 のファイルコピーが避けられないからです。それなら、あらかじめデータを持ったディスクを用意しておけばよいはずです。 そこで Replicator という Pod を常駐させます。Replicator は次のような役割の Pod です。 通常のノードと同じように shard の replica を持ち、PVC にデータを同期し続ける。 検索リクエストは受けない。 scale-out するときは、Replicator を通常ノードに昇格させます。PVC にはすでに shard の実体があるので、ファイルコピーは不要です。起動後は、同期が止まっていた間の更新を取り込むだけの Local Recovery で済みます。 回復方法 ファイルコピー 差分の追い付き Peer Recovery(従来) 必要(shard 全量) 必要 Local Recovery(今回) 不要 必要 Replicator の数は shard 数と同じです。各 Replicator が、ちょうど 1 つの shard を持つ構成(1 ノードあたり 1 shard)を前提にしています。つまり Replicator 全体で、インデックスの全 shard を 1 セット余分に持ち、いつでも通常ノードに昇格できる状態で待機することになります。 ただし通常ノードより小さいリソースで動かすので、常駐させるコストは抑えられます。ところが、この「小さいリソースで動かす」という点で、Kubernetes の制約にぶつかります。 壁: StatefulSet の Pod は全部同じサイズ 通常ノードと同じサイズで Replicator を常駐させてしまうと、インデックスのコピー 1 セット分のリソースを丸ごと余分に確保することになり、コスト削減になりません。Replicator は検索を処理しないので、本来 CPU も memory も少なくて済みます。 ところが、Elasticsearch を StatefulSet で動かしていると、これが簡単ではありません。StatefulSet 配下の Pod は、すべて同じ Pod テンプレートから作られるため、サイズも同じになります。Replicator だけ小さくする方法がありません。別の StatefulSet に分ける方法もありますが、PVC の名前が StatefulSet ごとに決まるため、昇格のたびに PVC の付け替えが必要になります。 そこで、Replicator と通常ノードを 同じ StatefulSet に置いたまま 、Pod の作成時に MutatingWebhook でサイズを書き換えることにしました。StatefulSet のテンプレートは通常ノードのサイズのままで、特定の Pod だけ、作られる瞬間に Replicator 用の設定に差し替えます。 アーキテクチャ StatefulSet の Pod には、 es-data-0 、 es-data-1 、… のように、名前の末尾に 0 からの連番が付きます(この番号を ordinal と呼びます)。この番号を使って、通常ノードと Replicator を見分けます。 shard が 12 個で、1 ノードに 1 shard の構成を例にします。 es-data-0 〜 es-data-11 : 通常ノード(各 1 shard) es-data-12 〜 es-data-23 : Replicator(各 1 shard の replica) StatefulSet の replicas は 24 になります。番号が小さい方から通常ノード、それ以降が Replicator、という分け方です。 【図 1: 定常状態。通常ノード 12 台と Replicator 12 台が同じ StatefulSet に並び、それぞれ PVC を持つ】 Webhook は、Pod の番号が通常ノードの台数以上であれば、その Pod を Replicator として次のように書き換えます。 対象 変更内容 ラベル Replicator であることを示す role ラベルを付与 リソース Elasticsearch コンテナと、ECK が注入する initContainer の request / limit を縮小 ES_JAVA_OPTS heap サイズを、縮小した memory に合わせて再計算 ノード属性 検索から除外する属性を付与 initContainer のリソースも書き換えているのは、Pod 全体の実効的な request が、initContainer の request の影響も受けるためです。ここを残すと、Pod のサイズが小さくならないことがあります。 通常ノードの台数は、controller が ScalableElasticsearchNodeSet に記録し、Webhook はそれを見て境界を判断します。HPA が指定する台数と、実際の通常ノード数は、shard 数との兼ね合いで切り上げられてずれることがあるためです。 Replicator に配置される shard と、検索の除外については、Elasticsearch 側にも手を入れています。 shard の配置(plugin) : Pod 名の末尾の番号から、どの shard を持つかが決まるようにする plugin を作りました(番号を shard 数で割った余りが shard ID です)。たとえば es-data-12 は shard 0 を持ちます。これにより、各 Replicator は必ず 1 つの shard を持ち、他の Replicator と重複しません。 検索の除外(patch) : 検索リクエストの宛先から、先ほどのノード属性を持つノードを外すよう、Elasticsearch 本体にパッチを当てています。 昇格・降格のフロー scale-out(通常ノード 12 台 → 24 台) controller が、通常ノードの台数を 24 に更新する。 es-data-12 〜 es-data-23 の Replicator の Pod を削除する。 StatefulSet が Pod を再作成する。このとき Webhook は、通常ノードの設定(元の大きなサイズ)を適用する。 PVC には shard のデータが残っているので、Local Recovery だけで検索を受けられるようになる。 続いて、StatefulSet の replicas を 24 から 36 に増やす。新しく作られる es-data-24 〜 es-data-35 は、新しい Replicator として起動する。 index の replica 数を増やす。 この順序は入れ替えられません。先に replicas を増やしてしまうと、新しい Pod が古い台数の情報を読んでしまい、Webhook が誤った設定を適用します。 新しい Replicator は Peer Recovery でデータを全量コピーしますが、検索を受けないので、新しい Replicator のコピー完了を待たずに、昇格した通常ノードで検索を提供できます。コピーの待ち時間が、検索を受ける経路から外れたことになります。 ノードに空きがない場合 昇格のときは、Pod を大きなサイズで作り直します。元のノードに空きがあれば、同じノードにそのまま再作成されます。空きがなければ、別のノードに Pod がスケジュールされ、Kubernetes の Attach/Detach controller が PV を新しいノードに付け替えます 。 どちらの場合も、shard のコピーは発生しません。コピーされるのではなく、PV そのものが移動します。PV の detach から attach までにかかる時間は 1 分程度で、shard を丸ごとコピーするのに比べれば、はるかに短く済みます。 scale-in(通常ノード 24 台 → 12 台) scale-out の逆の順序で戻します。 index の replica 数を減らし、shard の再配置が終わるのを待つ。 通常ノードの台数を 12 に更新する。 es-data-12 〜 es-data-23 の Pod を削除する。再作成されるとき、Webhook は Replicator の設定(小さなサイズ)を適用する。 StatefulSet の replicas を 36 から 24 に減らし、 es-data-24 〜 es-data-35 を削除する。 降格した Pod は、PVC のデータを持ったまま Replicator になります。そのため、次の scale-out に向けた準備が、そのまま整った状態になります。 HPA との連携 HPA は、 ScalableElasticsearchNodeSet の scale subresource を見て、台数と CPU 使用率を判断します。Replicator は検索を受けず、リソースのサイズも通常ノードとは違うので、これを一緒に数えたり平均に混ぜたりすると、scale の判断が狂います。 そこで、HPA に見せる値からは Replicator を除きます。 台数( status.count )と ready な台数( status.readyCount )から、Replicator を引く。 Pod を選択するセレクタに、Replicator ではないことを条件として加える。 これで、HPA は通常ノードだけを見て判断できます。 改善 2: HPA の tolerance をピークに合わせて切り替える threshold を上げると tolerance が効いてくる 改善 1 で scale-out の待ち時間が短くなったので、HPA の CPU 使用率の threshold を、65% 前後から 80% 前後まで引き上げられるようになりました。threshold を上げれば、同じトラフィックを少ない台数でさばけます。 ところが、threshold を上げると、新しい問題が出てきました。HPA の tolerance です。 HPA は、現在の指標が target に対してどれだけ離れているかを比で計算し、その比が 1 ± tolerance の範囲内であれば、何もしません。小さな変動のたびに台数が増減するのを防ぐための仕組みで、デフォルトは 0.1(10%)です。 target が 65% のとき、scale-out が始まるのは、約 71.5% を超えたときです。target との差は 6.5 ポイントです。target が 80% のときは、88% を超えるまで scale-out しません。差は 8 ポイントで、target を上げるほど、tolerance が作る不感帯の幅(ポイント換算)は広がります。scale-in も同様に、72% を下回るまで起きません。 さらに、HPA には stabilizationWindow があります。短時間の揺れで台数が増減しないよう、一定期間の推奨台数を見てから判断する仕組みです。私たちはスラッシング防止のために、もともとこの窓を設けていました。tolerance を超えてからさらにこの窓の分だけ待つことになり、遅れが二重に積み重なります。threshold を上げて余裕を削ったぶん、この遅れの影響が大きくなりました。 かといって、tolerance や窓を単純に小さくすると、今度は台数が頻繁に増減するスラッシングが起きます。私たちが絶対に避けたいのはこれで、台数が増減するたびに shard の再配置や昇格・降格が走るためです。 HPA ごと・方向ごとに tolerance を設定できるようになった tolerance は、以前は kube-controller-manager の --horizontal-pod-autoscaler-tolerance フラグで指定する、クラスタ全体に一律の値でした。特定の HPA だけ変える方法がありません。 これが KEP-4951 で変わりました。 HPAConfigurableTolerance という feature gate として Kubernetes v1.33 で alpha、v1.35 で beta となり、v1.37 で GA になっています。 これにより、HPA の spec.behavior.scaleUp.tolerance と spec.behavior.scaleDown.tolerance で、HPA ごと、さらに scale-out と scale-in の方向ごとに tolerance を指定できます。beta になった v1.35 以降であれば、デフォルトで有効です。 CronJob で切り替える 反応の速さとスラッシングの回避は、一律の設定では両立しません。そこで、トラフィックの向きに合わせて、tolerance と stabilizationWindow を 1 日のなかで切り替えることにしました。 トラフィックには、ピークに向かって上昇する時間帯と、ピークを過ぎて下降する時間帯があります。考え方は、 今のトレンドと逆向きの操作を抑える ことです。 ピークに向かう間 : scale-out はしやすくする( scaleUp.tolerance を小さく、 scaleUp.stabilizationWindowSeconds を短く)。scale-in はしにくくする( scaleDown.tolerance を大きく、 scaleDown.stabilizationWindowSeconds を長く)。上昇中に scale-in すると、すぐに scale-out が必要になるため。 ピークを過ぎた後 : scale-in はしやすくする。scale-out はしにくくする。再び上昇傾向に入るまでは、下降中に scale-out しても、すぐ scale-in が必要になるため。 切り替えは、決まった時刻に CronJob が HPA の behavior を patch することで行っています。 効果 2 つの改善の結果、次のようになりました。 項目 改善前 改善後 scale-out の所要時間 12 分 2 分 HPA の CPU threshold 65% 80% ファイルコピーの待ちがなくなったことで、scale-out は 2 分で終わるようになりました。その結果 threshold を引き上げられるようになり、同じトラフィックをより少ない台数でさばけています。 tolerance と stabilizationWindow の切り替えにより、threshold を上げても、スラッシングは起きていません。 まとめ この記事では、Elasticsearch の autoscaling を改善するために行った 2 つの取り組みを紹介しました。 StatefulSet の Pod は全部同じサイズ、という制約を MutatingWebhook で回避し、PVC に事前に shard を同期した Replicator を常駐させることで、scale-out から shard のコピー待ちをなくしました。 その結果 HPA の threshold を引き上げられるようになり、顕在化した tolerance の問題を、HPA ごと・方向ごとの tolerance と stabilizationWindow の設定、および CronJob による切り替えで解消しました。 Kubernetes 側の Pod 制御と、Elasticsearch 側の shard 配置・検索対象の制御を組み合わせることで、検索を提供するまでの経路から全量コピーの待ち時間を切り離しました。同じように、StatefulSet の制約や HPA の挙動に悩んでいる方の参考になれば幸いです。
要約 :Elastic Agent Builder 9.5(Elastic Stack 9.5.4 / 9.5.5)で、AI エージェントの安全対策を、実際に環境を作って試しました。ツールを絞る設定、ロールの権限(DLS / FLS)、実行前の人の承認は、製品の機能で実現できました。一方で、Trace(エージェントの実行の記録)にツールの詳細を記録する設定を ON にすると、顧客データを見る権限の無い人にも、Trace から顧客データが見えました。本文、設定、クエリ、画面へのたどり方は GitHub にまとめています。 ▶ 記事を読む(GitHub): https://github.com/SIOS-Technology-Inc/elastic-blogs/tree/main/2026-10-agent-builder-security AI エージェントは、ツールを使って実際に操作をします。そのため、従来の LLM 対策だけでは足りません。前半の記事「 AIエージェントはなぜ危険になる?仕組みから考えるセキュリティの4原則 」では、そのための 4 つの原則を紹介しました。後半のこの記事では、4 つの原則を Elastic Agent Builder 9.5 で実際に試しました。 検証の条件 製品:Elastic Stack 9.5.4 / 9.5.5(セルフマネージド、Docker)、Trial ライセンス 検証期間:2026 年 10 月 5 日〜8 日 モデル:主に Elastic Inference Service(EIS)を Cloud Connect 経由で利用 シナリオ:社内マニュアルを検索して答えるエージェントを作り、マニュアルの 1 件に「顧客情報を外へ送れ」という指示を仕込みました データ:すべて架空のデータです。メールは本物を送らず、専用の Index への書き込みを「送信」としました 分かったこと ツールを絞る :新しいエージェントでは、Elastic capabilities が OFF でも、Tools タブにツールが選ばれていることがありました。使わないツールは、手で外す必要があります。 権限で守る :今回の ES|QL ツールでは、使う人の Elasticsearch の権限(Index・DLS・FLS)が、エージェント経由でもそのまま効きました。守っているのは LLM ではなく Elasticsearch です。ただし、FLS で隠した項目を ES|QL の KEEP で名指しすると、ツール全体がエラーになりました。 人が承認する :9.5.5 では、ツールの「Require user confirmation」を Always にすると、人が Allow を押したときだけ送信のツールが動きました。9.5.4 では、Workflow の承認ステップで止められました。ただし、Tools API から直接ツールを実行すると、Agent Builder の確認画面は出ません(公式ドキュメントより)。 記録と検知 :Trace の初期設定では、自分で作ったツールやエージェントの名前が「custom」と記録されました。Trace を見張る ES|QL のアラートルールで、送信の Workflow の起動を約 28 秒で検知できました。ただし、Workflow の承認画面で Decline した操作でもアラートは鳴りました。今回の設定では、誰が使ったか、本当に送信したかは、Trace だけでは分かりませんでした。 記録と権限がぶつかる :Trace にツールの詳細を記録すると、顧客 Index を読めないユーザーでも、Trace を読めれば顧客データを読めました。FLS でツールの結果の項目は隠せましたが、同じ顧客データが chat span の入力メッセージ(gen_ai.input.messages)にも入っていて、そこからは読めました。 モデル :同じエージェント・同じ指示文でも、モデルによって反応が違いました。1 回の質問でも、選んだモデル以外が呼ばれていました。モデルが断ってくれることだけには頼れません。 この記事で分かること(設定の場所と確かめ方) 記事では、検証の結果だけでなく、Agent Builder の安全対策を「どこで設定し、どう確かめるか」も、画面へのたどり方と一緒に載せています。画面の名前や場所は、Elastic Stack 9.5.4 / 9.5.5 で確かめたものです。 Elastic Agent Builder で、エージェントが使えるツールを絞るには? エージェントの設定の Tools タブで、使わないツールを外します。ツールは、Agent Builder → Manage components → Tools で作ります(2 章)。 エージェントを使える人を決めるには? エージェントの設定の Access control で、Public / Shared / Private から選びます。今回の環境では、新しいエージェントの初期値は Public でした(2 章)。 ※ Access control はエージェントの公開範囲を制御する設定であり、Agent Builder 自体の利用権限は Kibana のロールでも管理されます。 文書ごと・項目ごとにデータを隠すには(DLS / FLS)? Stack Management → Security → Roles でロールを開き、Index privileges の行で設定します。DLS は「Grant read privileges to specific documents」、FLS は「Grant access to specific fields」です(3 章)。 送信の前に人が承認するようにするには? 9.5.5 では、ツールの作成画面で「Require user confirmation」を Always にします。9.5.4 では、Workflow に承認ステップ(waitForApproval)を入れ、承認されたときだけ送信のステップを動かす条件(if)を付けます(4 章)。 エージェントの実行の記録(Trace)を設定するには? Stack Management → AI → GenAI Settings → Agent Builder Traces で設定します。Advanced privacy settings で、記録する内容(ツールの詳細、本当の名前など 7 つ)を選べます。初期値はすべて OFF です(5 章、7 章)。 危険な操作でアラートを出すには? Stack Management → Alerts and Insights → Rules → Create rule → Elasticsearch query で、Trace を ES|QL で見張るルールを作ります(6 章)。 どのモデルが使われたかを確かめるには? Trace の chat span に記録されたモデル ID で確かめます。機能ごとのモデルの割り当ては、Stack Management → Model Management → Feature settings で見られます(8 章)。 設定が効いているかを確かめるには? 制限したユーザーで、Discover の ES|QL や、Elasticsearch の _search で実際に検索します。今回は、ES|QL で null と表示された項目を、_search では読めました(7 章)。 こんな方におすすめ Elastic Agent Builder の導入を考えている方 AI エージェントの権限、承認、記録のしくみを決める方 Elasticsearch の DLS / FLS をすでに使っている方 検証の結果より、まず設定の場所と確かめ方を知りたい方 関連記事 前半: AIエージェントはなぜ危険になる?仕組みから考えるセキュリティの4原則 Trace の開き方と読み方: AI エージェントの「中で何が起きたか」を見える化する 参考(公式ドキュメント) Permissions and access control in Elastic Agent Builder Tools(Elastic Agent Builder) Collect traces(Elastic Agent Builder) Role management using Kibana ※ 2026 年 10 月時点で、上の環境と今回のシナリオで試した結果です。バージョンや設定によって、動きは変わることがあります。 The post Elastic Agent Builder 9.5 で AI エージェントの安全対策を試した:できたこと、できなかったこと first appeared on Elastic Portal .
目次 TL;DR はじめに Kibana v9.5.x での表示 移行対策 1. Elastic が用意しているモデルを利用する場合 2. 自作の OpenAI 互換 Connector (LM Studio 等)を利用する場合 まとめと今後の展望 TL;DR Kibana v9.5.0 以降、従来の AI Connector が非推奨(deprecated)となりました。 今後は Kibana / Elasticsearch の Inference Service および Inference Endpoint(_inference API)への移行が推奨されます。 本記事では、v9.5.x における表示の変化と、OpenAI 互換(LM Studio等)を含む移行・設定手順を解説します。 はじめに v9.4.x までは、 Kibana 上で AI 機能に接続するための設定として AI Connector が使用されていました。 しかし、v9.5.0 より AI Connector は deprecated (非推奨)となっています。 既存の AI Connector を利用中の方や、今後ローカル LLM 等に接続したい方向けに、推奨される代替機能 (Inference Endpoint) への移行手順を説明します。 Kibana v9.5.x での表示 Kibana v9.5.5 で確認したところ、Stack Management > Connectors 画面において、 既存の AI Connector (独自に追加した OpenAI 互換のローカル LLM 用 Connector を含む)に、DEPRECATED バッジが表示されます。 ※現時点 (v9.5.x) では非推奨表示がされるのみで機能自体は利用可能ですが、将来のバージョンで廃止される可能性があるため、早めの移行をおすすめします。 ※Stack Management > Connectors 画面の例 移行対策 1. Elastic が用意しているモデルを利用する場合 Elastic が公式に提供しているモデルを利用する場合には、Inference Service を利用します。 確認画面 : Stack Management > Elastic Inference 一覧から利用可能なモデルを確認できます。 Stack Management > Elastic Inference 画面の抜粋 ※注意 : 画面上に Deprecated や End of life と表示されている項目がある場合、それは Connector の機能ではなく、モデル自体が古くなっていることを示しています。 2. 自作の OpenAI 互換 Connector (LM Studio 等)を利用する場合 自分で作成した OpenAI 互換の Connector (LM Studio や Ollama など)については、Inference Endpoint を作成して移行します。 ※Elastic Inference Service を利用せずに、外部の LLM 用の API を利用する場合も同様です。 設定例: コンテナ上の Elasticsearch からホスト上の LM Studio で動作する google/gemma-4-e4b に接続する場合 Kibana の Dev Tools Console から以下の API リクエストを発行します。 PUT _inference/chat_completion/lmstudio_google_gemma_4_e4b { "service": "openai", "service_settings": { "api_key": "<YOUR_LM_STUDIO_API_KEY>", "model_id": "google/gemma-4-e4b", "url": "http://host.docker.internal:11434/v1/chat/completions" }, "task_settings": { "headers": { "content-type": "application/json" } } } 参考URL: https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-openai Inference Endpoint を追加すると、Stack Management > External Inference 画面に、追加された Endpoint が表示されます。 Stack Management > Feature settings 画面の Global model の選択肢にも追加された Inference Endpoint が表示されるようになります。 まとめと今後の展望 Kibana v9.5.0 における AI Connector の非推奨化は、Elastic Stack における AI 接続基盤が _inference API へと一元化・進化していることを示しています。 従来個別に管理されていた AI 接続が整理されることで、公式サービス(Inference Service)とローカルLLM等の外部環境(Inference Endpoint)の管理がより明確かつシンプルになりました。 DEPRECATED バッジが表示されている環境をお持ちの方は、ぜひ本記事の手順を参考に、スムーズな移行を試みてください。 The post Kibana の AI Connector 非推奨化 (deprecated) に伴う Inference Endpoint への移行手順 first appeared on Elastic Portal .












