コンテンツにスキップ

分散ポーラー

ポーリングは、状態を持たないポーラーのプールで、台数を増やして規模を広げられます。プローブを 監視対象の機器の近くに置けるので、ネットワークが切れても監視は続きます。

このページでは、その挙動を説明します。割当、フェイルオーバー、バスの保護、そして store-and-forward のバッファです。手順を追ったデプロイ手引きは、 インストールガイドのセクション Dにあります。

ここで言う分散は、独立した「分散モード」ではありません。単一ノードのインストールでも、ここで 説明する仕組みそのままに、"default" プールでポーラーが 1 台動いています。分散化とは、構造を 変えることではなく、ポーラーとプールを増やすことです。単一ノード構成も分散構成も、同じイメージ で動きます。

すべてのノードは pool 属性を持ちます(既定は "default")。

ポーラーは、変わらない ID(YAGRA_POLLER_ID)と、担当するプール(YAGRA_POLLER_POOL)で自分を 名乗ります。そしてバス経由でハートビートを送ります。

この ID は変わらないことが前提です。v0.3.2 から、中央デプロイの中に居るポーラーについては配布する compose がそれを保証します。名前は local です。何も指定しないとポーラーはコンテナのホスト名を使い ますが、この名前は Compose がコンテナを作り直すたびに Docker が新しく作ります。そのためアップグレード のたびに設定 ▸ ポーラーへ死んだ行が 1 つ増えていました。それらの行はオフラインなので削除して 問題ありません。動いているのは local という名前のポーラーです。

コアのコーディネーターは、そのハートビートを見ています。そして各プールのノードを、稼働中の ポーラーへコンシステントハッシュで割り当てます。この方式なら、ポーラーが増えても失われても、 動かすノードは最小限で済みます。プール全体を配り直したりはしません。

各ポーラーは、自分の割当を作業セットとしてバス経由で受け取ります。最初に全体のスナップショット が届きます。以後は、ノードの追加・移動・再割当に応じて差分だけが届きます。

ポーラーは、その作業セットを見て自分のプローブの実行時刻を決めます。コアが 1 本 1 本のチェックを 指示することはありません。再起動して接続し直したポーラーには、全体が改めて届きます。ですから 再起動をまたいで、担当のいないノードが生まれることはありません。

障害時の扱いも同じ仕組みから導かれます。

  • ポーラーが離脱した場合。 ハートビートが止まります。コーディネーターは、そのノードを同じ プールで生き残っているポーラーへ自動的に引き継がせます。

    v0.2.3 からは、引き継ぎ方が変わりました。移ってきたノードを新規ノードのように間隔全体へ散らす のではなく、無理のないレートで始めます(YAGRA_ADOPT_RATE_PER_SEC、既定は 200 チェック/秒)。 数十ノードの引き継ぎなら 1 秒未満で終わります。以前は最大で 1 間隔ぶん待つことがありました。 なお、コールドスタートは従来どおり間隔全体に広がります。

  • ポーラーが参加した場合。 プールは新しい構成に合わせて配り直します。このときも動かすのは 最小限だけです。配り直しは、次の定期スイープを待たずにすぐ走ります。

  • プールに稼働ポーラーが 1 台もない場合。 コアは、そのプールのジョブをバス経由で 1 件ずつ配る 経路に切り替えます。作業セットが生まれる前からある経路です。

    これはローリングアップグレードの安全網です。ポーラーが再起動中のプールも、まだ前のリリースを 動かしているプールも、監視が止まらずにノードを見続けられます。

死活と割当の状態は、任意で使う Redis のミラーに置かれます。これはいつでも作り直せるので、失っても 永続的なものは何も損なわれません。

プールを増強するのは簡単です。同じ YAGRA_POLLER_POOL を持ち、YAGRA_POLLER_ID が異なるポーラー を、さらに動かすだけです。

プールの割り当てと、担当ポーラーの確認

Section titled “プールの割り当てと、担当ポーラーの確認”

ノードが実際に属するプール(実効プール)は、次の順で決まります。

  1. ノード自身に設定されたプール
  2. プールを設定している、いちばん近い親フォルダ
  3. どちらも無ければ "default"

プールは WebUI から編集できます。ノード単体、フォルダ単体のほか、インベントリツリーで右クリック すると、既存のプール一覧に加えて継承と任意名の入力欄が出ます。

このなかで重要なのはフォルダです。ツリーには複数選択がありません。ですから拠点まるごとのノードを 一度に移す手段は、フォルダからの継承だけです。

どの選択肢にも、そのプールに稼働中のポーラーがいるかが表示されます。これは見た目以上に大事 です。登録済みのポーラーがいないプールにノードを割り当てると、そのジョブは誰も聞いていないバス サブジェクトへ流れます。そのノードは、黙って監視されなくなります。

逆に「このノードは誰が見ているのか」は、ノード詳細が答えます。プールの欄は実効プールとその 由来を示します。ポーリング元の欄は、実際に担当しているポーラーを示します。状態は 5 つです。

  • 割当済み — 担当が決まっている
  • 保留 — 割当がまだ配られていない
  • レガシー fan-out — 上で説明した、ポーラー 0 台のときのフォールバック
  • Meraki — クラウドから集めるので、リングの割当対象外
  • 不明

この答えは、ハッシュリングから計算し直したものではありません。コアが実際に配った作業セットを 読んでいます。ですから、スイープが除外したノードに存在しない担当者を作ってしまうことがなく、 ポーラー側のノード一覧と食い違うこともありません。設定 ▸ ポーラーは逆向きで、各ポーラーの 担当ノード一覧をその場で開けます。

アップグレードも、同じ性質に支えられています。バスは隣り合うリリース同士で互換なので、新しい コアは前のリリースのポーラーと問題なく動きます。ですからまずコアを、次にポーラーを上げて ください。リモート拠点も含めて、1 台ずつ、順序は自由です。

ポーラーは状態を持たないので、入れ替えに代償はありません。一時的にポーラーが 0 台になったプール は、アップグレードされたポーラーが登録し直すまで、ジョブを 1 件ずつ配る経路で凌ぎます。手順の 全体はアップグレードとバックアップに あります。

ポーラーを失ったプールを肩代わりする

Section titled “ポーラーを失ったプールを肩代わりする”

あるプールのノードを誰もポーリングしなくなったとき、設定 ▸ ポーラーが「別のプールに肩代わり させる」操作を出します。いちばん分かりやすいのは、デプロイを新しいサーバへ移したあとです。拠点は バンドルを再発行するまで付いてきません。移す前にノードとフォルダをすべて記録するので、元に戻す を押せば、割り当てを継承していただけのものも含めて、一つひとつが元の担当へ戻ります。

拠点に寄せる(ロケーションアフィニティ)

Section titled “拠点に寄せる(ロケーションアフィニティ)”

プールは、拠点にそのまま対応させられます。ポーラーは状態を持たず、中央のバスへ自分から つなぎに行きます。ですからリモート拠点に必要なのは、外向きの許可 1 本だけです。内向きの穴は 要りません。NAT やファイアウォールの内側にあるポーラーも、そのまま動きます。

拠点ごとにプールを 1 つ作り(「tokyo」「osaka」、クラウドリージョンなど)、その拠点のノードを 割り当ててください。プローブは拠点の中に留まります。ICMP と SNMP のトラフィックが WAN を越える ことはありません。コアへ戻るのは、結果・イベント・ハートビートだけです。

受信の窓口もプールに従います。 拠点のポーラーは、その拠点のパッシブなデータを受け止める場所 でもあります。

任意で使う UDP リスナー — syslog、SNMP トラップ、NetFlow/IPFIX、sFlow — が、拠点の機器の出力を 受け取ります。送信元ごとと全体のレート制限を拠点側でかけ、同じ認証済みバスでイベントを持ち帰り ます。

フローのデータグラムは、さらに拠点側でまとめてからコアへ送ります。まとめ方は、決まった長さの 時間で区切り、エクスポーターごとにバイト数の多い順に上位を残す形です。これが、忙しい拠点のフロー 量を回線に載る範囲に収めているしくみです。

リモートポーラーの構成は、ホストネットワークの上で動きます。パッシブイベントは、データグラムの 送信元 IP でノードに突き合わせるからです。ブリッジの NAT は、そのアドレスを書き換えてしまいます。

拠点の回線は、実際にそこを通る量を見込んで選んでください。ポーラーは、解析したイベントと並べて、 受け取った元のバイト列も運びます。あとで転送が、機器の送った ものをそのまま中継できるようにするためです。フローでは、おおむね 1,000 flows/s あたり 1 Mbit/s になります。

一時的な急増は、送信元ごと・全体それぞれの受信レート制限で抑えられます。設定値は 設定リファレンスにあります。

典型的なマルチ拠点構成は次のようになります。

拠点 プール ポーラー
データセンター / 本社 default コアと同居
東京支社 tokyo 支社 LAN 上にリモートで 1〜2 台
大阪支社 osaka 支社 LAN 上にリモートで 1〜2 台

プールの中では、冗長化は単に台数の話です。拠点のプールでポーラーを 2 台動かせば、片方が落ちても もう片方がそのノードを引き継ぎます。

上で説明した「稼働ポーラー 0 台のときのフォールバック」を、拠点の冗長化と取り違えないでください。 あれはアップグレードの互換のための経路です。拠点の冗長化は、2 台目のポーラーです。

1 つだけ性質が違うのが、Cisco Meraki の監視です。これは拠点の機器をプローブしません。組織単位で Meraki のクラウド API をポーリングします。

このクラウド収集のジョブは、YAGRA_MERAKI_POOL(既定は default)で指定したプールへ回されます。 インターネットへ外向きに通信できるプールを指定してください。

ポーラーは、WebUI の**設定 ▸ ポーラー ▸「ポーラーを登録」**から登録します。

このダイアログは、リモートホスト用の .env をそのまま使える形で生成します。中身は、リモート ポーラーが必要とする 3 つの変数です。YAGRA_POLLER_ID(変わらない、一意の値)、 YAGRA_POLLER_POOL、そして tls:// で始まるバスの URL です。

そのポーラーに専用のバストークンを発行すると、もう一歩進みます。.env、固定するバス証明書、この core のイメージから取り出した docker-compose.poller.yml、そして README が、1 つのアーカイブで落ちて きます。拠点側の作業は、展開して docker compose up -d するだけになります。トークンは SHA-256 の ダイジェストしか保存されないので、表示は 1 回きりで復元できません。

この .env は、docker-compose.poller.yml の隣(ネイティブなら環境変数として)にそのまま置け ます。イメージも YAGRA_IMAGE_TAG でそこに固定してください。

ポーラーは起動から数秒でこのページに現れます。そこからコアが、そのプールのノードを割り当て 始めます。

設定 ▸ ポーラーページは、ポーリング層全体を見渡すビューでもあります。ポーラーごとに次を 表示します。

  • 死活 — 現在のステータスと、最後に受信したハートビート。
  • 割当 — 担当するプールと現在の作業セットのサイズ。プールのノードがどう分散しているかが 分かります。
  • バージョン — そのポーラーが動かしているバージョン。ロールアウトの途中で役立ちます。
  • 監視ギャップ — コアがポーラーとの連絡を失っていた直近の期間(どのポーラーか、どのプールか、 いつ、どれだけの長さか)。監視が見えていなかった時間帯が一目で分かり、メトリクスが後から 補完されたことも確認できます。

ノードはあるのに稼働ポーラーがいないプールがあれば、警告も表示します。デプロイ手順の全体 — compose ファイル、ホストネットワーク、受信リスナーの 1024 未満ポートに関する注意 — は インストールガイドのセクション Dにあります。

プールを作り、ポーラーをそこへ移す

Section titled “プールを作り、ポーラーをそこへ移す”

v0.3.4 より前は、プールは「ノードの割り当て欄に未知の名前を打つ」という副作用でしか生まれません でした。Settings ▸ Pollers の上部にあるプール帯から、意図してプールを作れるようになりました。 各カードの ⋮ から説明の編集・名前の変更・削除ができます。ノード・フォルダ・ポーラーのいずれかが まだそのプールを名乗っているあいだ、削除はできません。default プールは説明だけ編集でき、 名前の変更と削除はできません。名前がコード側で固定されているためです。

ポーラーの移動も同じ画面から行います。行のつまみをプールのカードへドラッグするか、プール列の 移動を使います。何も再起動しません。 どのプールを担当するかは core が持ち、次の ワーキングセットでポーラーに伝わり、ポーラーはバスの購読先をその場で張り替えます。 YAGRA_POLLER_POOL は「core が初めてそのポーラーを見たときの行き先」を決めるだけで、以後は 参照されません。コンテナを作り直しても移動は戻りません。

動かすポーラーが元のプールで最後の生きた 1 台で、そのプールにまだノードがあるときは、移動が 止まって尋ねます —— ノードも行き先へ一緒に移す(1 つのトランザクションなので監視は止まりません) か、残して監視が止まることを受け入れるか。オフラインのポーラーと、ビルドが v0.3.4 より古い ポーラーは移動できません。中途半端に動かす代わりに、画面が理由を表示します。

ジョブのメッセージは、デバイスの認証情報を平文で運びます。ポーラーがプローブするのに必要だから です。単一ホストの中だけなら問題ありません。バスは内部の Docker ネットワークから出ないからです。

しかしバスが信頼境界を越えてリモート拠点へ届く瞬間から、TLS の暗号化と認証が必須になります。 しかも先に設定してください。NATS の :4222 を平文で公開してはいけません。

必要な設定はスイッチ 1 つです。**設定 ▸ ポーラー ▸「リモートポーラーを受け入れる」**に、拠点が 接続する宛先を渡します。その宛先でバス証明書を再発行し、TLS とバスのパスワードを有効化し、バスの ポートを公開し、同じ変更で同居するコアとポーラーを tls:// に移します。手順は インストールのセクション D、ステップ 1に あります。

各ポーラーは、YAGRA_BUS_CA_FILE でサーバー証明書を固定します。ですからリモート拠点が信頼するの は、システムの CA ストア全体ではなく、ちょうど 1 つのバスの接続先だけです。

同梱の NATS 設定では、core ユーザーにすべての権限を、poller ユーザーには最小限だけを与えます。 poller が publish できるのは結果・イベント・ハートビート、subscribe できるのはジョブと作業セット の割当だけです。

ただし、限界も知っておいてください。専用トークンを持たないポーラーは、デプロイ全体のブートストラップ シークレットで通ります。その方法で通ったポーラーは、どのプールの割当でも読めます。つまりこの共通 シークレットは、ポーラー群を認証はしますが、拠点どうしを隔てるテナント境界にはなりません。

これを狭めるものが 2 つあります。台帳に無いポーラー id は、どんなシークレットを示しても拒否されます。 ですから漏れた .env で他拠点の id を名乗ることはできません。そして専用トークンを発行したポーラーは、 共通シークレットではもう通りません。トークンの発行が形式ではなく、拠点ごとに爆風半径を狭める作業に なるのはこのためです。

プールの分離が問題になる構成では、次に説明するポーラー単位の認証情報スコープを使ってください。

ポーラー単位の認証情報スコープ

Section titled “ポーラー単位の認証情報スコープ”

任意で、コアをバスの認証サービス(NATS Auth Callout)として動かせます。すると各ポーラーに、 自分のプールのサブジェクトだけに限った、接続ごとの認証情報を発行できます。

流れはこうです。ポーラーが共有のブートストラップシークレット(YAGRA_NATS_POLLER_PASSWORD)で 接続してきます。コアはそれを検証し、そのポーラー自身の ID とプールに対応するサブジェクトだけを 許可する認証情報を発行します。許可するのは、自分のジョブのストリームと、自分の割当サブジェクト だけです。それ以外は何も許可しません。

効果は次のとおりです。侵害されたリモート拠点が見られるのは、自分のプールのジョブとデバイス 認証情報だけになります。全体に手の届く共有アカウントではありません。

しかも、各ポーラーが何を読めるかを決めるのはコアです。接続のたびに中央で決めます。拠点ごとに NATS サーバーの設定を書き換える必要はありません。

v0.3.2 以降、リモートポーラーの受け入れと一緒に有効になります。設定する物はありません。 コアが 署名に使うアカウント鍵は初回起動時に生成され、データベースに封じられます —— 他のすべての秘密と 同じ封筒暗号です。公開鍵のほうは、バスの残りの設定を書くのと同じ 1 回の実行でバス自身の設定に 書き込まれます。運用者が 2 つを歩調合わせする代わりに、食い違いようのない 2 つになります。

バスがホストの外に出ない環境では応答役は起動せず、NATS は上で説明した静的アカウントを使います。 リモートポーラーを受け入れるまで、何も変わりません。詳しくは セキュリティを見てください。

v0.3.2 より前、これは手作業 4 手順で、最後は同梱の NATS 設定ファイルの編集でした。あのファイルは 起動のたびにイメージから入れ直されるので、編集は次の起動までしか残りませんでした。もし実際に 設定していた場合、YAGRA_NATS_CALLOUT_SEED_FILE は今も優先されるので壊れません。

コアから切り離されたリモートポーラーも、監視を続けます。WAN の障害でも、ファイアウォールの一時的な 不調でも同じです。その場で機器のポーリングを続け、結果を捨てずに 2 段構えでためます。

  1. メモリ上のリングバッファ(既定で 20,000 件)。ためる処理が、ポーリングのループを止めることは ありません。
  2. リングが埋まったら、ディスクへ書き出します。書き出し先は /var/lib/yagra/buffer の下です (Compose では pollerbuf ボリューム)。ですから障害の途中でポーラーが再起動しても、たまった データは残ります。

バッファには、あらゆる軸で上限があります。溢れたときの方針は、どこでも古いものから捨てるです。 ですからポーラーのディスクを埋め尽くすことは決してありません。

上限 既定 変数
マスタースイッチ 有効 YAGRA_STORE_FORWARD(off で無効化)
メモリ上のリング 20,000 件 YAGRA_STORE_FORWARD_MEM_MAX
ディスクスピルの合計 512 MB — 超えた分は最も古いセグメントから破棄 YAGRA_STORE_FORWARD_DISK_MAX_MB
最大保持期間 24 時間 — これより古い結果は再送時に破棄 YAGRA_STORE_FORWARD_MAX_AGE_SECS
空き容量の下限 1 GB — 空きがこれを下回るとスピルを停止 YAGRA_STORE_FORWARD_DISK_FREE_FLOOR_MB
スピルのセグメントサイズ 16 MiB — ディスク上限の粒度 YAGRA_STORE_FORWARD_SEGMENT_MB
スピル先ディレクトリ /var/lib/yagra/buffer YAGRA_STORE_FORWARD_DIR

バッファは、失敗するのではなく静かに機能を落とします。書き出し先のディレクトリを作れず、読めもし ない場合、ポーラーは警告をログに出し、メモリだけでためて動き続けます。ストレージの問題が、 ポーリングを止めることはありません。

つながり直すと、ポーラーは専用のバックフィル経路でバッファをまとめて送り直します(この経路は、 保護されたバスでも poller アカウントに許可されています)。コアはメトリクスを元の時刻のまま 取り込みます。ですからグラフと履歴は、偽のスパイクを作らずに障害期間を埋めます。

送り直すのは、測定した記録そのものだけです。具体的にはメトリクスのサンプルと、インターフェースの メタデータです。それ以外はありません。ディスク上で待っているデータに、シークレットは含まれません。

アラートは決して埋め戻しません。 アラートの評価は、つながり直した後の「今」から再開します。

これは意図的です。ドウェル時間によるヒステリシスは、サンプルの数を基準にしています。ですから たまった古いサンプルを再生すると、ありもしない状態の変化を作り出し、すでに解消済みの古いアラート で画面を埋め尽くしてしまいます。

その結果、回線が復旧しても、過去のインシデントが鳴り直すことはありません。履歴だけが戻ります。 そして復旧した障害期間は、それぞれ監視ギャップとして設定 ▸ ポーラーに記録されます。誰も 呼び出されなかったとしても、見えていなかった時間帯は見える形で残ります。

store-and-forward は既定で有効です。YAGRA_STORE_FORWARD=off を設定すると、その場で送るだけ の挙動に戻ります(バスに届かなければ結果は捨てられます)。上限値はすべて 設定リファレンスにあります。

ポーリング層は 3 つの角度から観測できます。

  • 設定 ▸ ポーラー — ポーラーごとの健全性です。ステータス、プール、バージョン、作業セットの 大きさ、最後のハートビート、プールの警告、そして上で説明した直近の監視ギャップの一覧が出ます。
  • ダッシュボード — 作業セットの分布ウィジェットが、各プールのノードがポーラー間にどう散らばって いるかを示します。偏ったプールや弱ったプールが一目で分かります。
  • Prometheus — 各ポーラーは :9100 で自分の /metrics を出します。コアは API のポートで自分の メトリクスを出します。ですから既存の監視系で、監視する側を監視できます。詳しくは 可観測性を見てください。

これらと監視ギャップの一覧を合わせると、運用の問いに順番に答えられます。すべてのプールに担当が いるか → どのノードを誰が持っているか → いつ見えていなかったか、そしてそれは埋め戻されたか。