課題の背景とコンテキスト
Kubernetes コントローラーは Informer キャッシュからオブジェクトを読み取り、希望する状態(desired state)を API サーバーに書き込みます。高負荷、watch の遅延、または再起動が発生すると、キャッシュが API サーバーより遅れることがあります。その結果、コントローラーが書き込みを重複して実行したり、不適切なスケーリングを行ったり、古い Lease を期限切れとして扱ったりする可能性があります。影響を受けるオブジェクトのみをブロックする、古さ(staleness)の検出と緩和策を設計してください。
これは、プラットフォームエンジニアリング、SRE、およびクラウドネイティブのコントローラー開発の役割に関連します。Kubernetes v1.36 および KEP 5647 では、AtomicFIFO、LastStoreSyncResourceVersion()、書き込みのリソースバージョンの追跡、古いキーのスキップと再キューイング、ならびに DaemonSet、StatefulSet、ReplicaSet、Job コントローラーへの適用について説明されています。これは公開情報に基づく設計演習であり、特定企業の面接設問集を主張するものではありません。
面接官が評価するポイント
面接官は、結果整合性を持つキャッシュの境界を理解しているか、そして「十分に新しい」という状態をテスト可能なリソースバージョンの条件に落とし込めるかを確認しようとしています。優れた回答には、キャッシュ同期、read-after-write、キーごとのキュー、バックオフ、再起動、モニタリング、およびフィーチャーゲートが含まれます。不十分な回答では、すべての reconcile 呼び出しで API サーバーから直接読み取りを行い、負荷や整合性のコストを無視してしまいます。
明確化のための質問
- Pod の削除、スケールダウン、リーダーの交代、通常のステータス更新のうち、どれが破壊的な決定に該当しますか?
- 許容される古さのウィンドウはどのくらいですか?また、重要な操作において API サーバーからの読み取りを1回行う余裕はありますか?
- 単一オブジェクトに対する read-after-write が必要ですか、それとも複数オブジェクトにわたる因果的順序付けが必要ですか?
- 再起動、watch の再接続、または API サーバーの障害後、コントローラーは保守的に待機すべきですか、それとも制限付きの性能低下を許容すべきですか?
30秒での回答
「私なら Informer キャッシュをデフォルトの読み取りパスとして維持し、AtomicFIFO と最新の観測リソースバージョンを使用して進行状況を測定します。重要なオブジェクトを書き込んだ後、コントローラーはそのターゲットバージョンを記録します。キャッシュが追いつくまで、該当するキーのみをスキップして指数バックオフで再キューイングします。破壊的なアクションには、制限付きのライブリードまたはサーキットブレーカーを追加します。メトリクスでは、キャッシュの遅延、スキップされた reconcile、キューの滞留時間を公開します。再起動時は保護状態を維持し、キャッシュ同期を完了させてから処理を再開します。」
ステップごとの解決策
まず古さを定義します。Informer Store には watch イベントを通じてデータが投入されますが、キャッシュの再構築中には遅延、順序の入れ替わり、または一時的な不完全さが発生する可能性があります。Kubernetes v1.36 の AtomicFIFO は、初期リストのバッチ処理を増分イベントに対してアトミックにし、それらが交差することによるキャッシュの不整合を防ぎます。LastStoreSyncResourceVersion() は、Store によって観測された最新のバージョンを公開します。
重要な書き込みごとに objectKey -> resourceVersion を保持します。DaemonSet が Pod を更新する場合、API サーバーから返されたバージョンを記録します。Pod informer の各イベントは、観測された最大バージョンを進めます。DaemonSet は、観測されたバージョンが最後の書き込みに達した場合にのみ、新しい状態に依存する次の reconcile を実行できます。達していない場合は、通常の指数バックオフを用いてそのキーを再キューイングします。ワーカープール全体を停止させてはなりません。
書き込みとチェックはべき等である必要があります。リソースバージョンの競合リトライを使用し、繰り返される reconcile が余計な副作用を持たないようにします。再起動するとインメモリのマッピングが失われるため、起動時は informer キャッシュの同期を待ってから、オブジェクトのステータスやキューイベントから保護状態を再構築します。マッピングが不完全な場合は、最新であると仮定するのではなく、破壊的な処理を遅延させます。
時間に敏感な決定にはサーキットブレーカーを追加します。高速パスにはキャッシュを使用し、ターゲットバージョンが不明な場合や遅延がしきい値を超えた場合は、API サーバーから1回だけ制限付きのライブリードを実行します。失敗した場合は、そのキーのみを一時停止して理由を記録します。ライブリードをデフォルトにすると、API サーバーの QPS、レイテンシー、障害の影響範囲が増大します。
コントローラーごとに、informer のリソースバージョン、ターゲット書き込みバージョン、遅延時間、スキップされた reconcile 数、キューの滞留時間、ライブリード成功率、サーキットブレーカーの発動数を公開します。ログにはオブジェクトキー、バージョン、アクションを含め、Secret の値は絶対に含めません。アラートでは、API サーバーの遅延、watch の切断、ホットキー、コントローラーの処理遅延を区別できるようにします。
フィーチャーゲートとカナリアリリースを用いてリリースします。競合の多いコントローラー1つと小規模なノードプールで有効化し、スキップ後の収束、再起動からの回復、キューの枯渇がないことを検証します。API サーバーの負荷が許容範囲内であることを確認した上でのみ展開を拡大します。ロールバック時は、メトリクスとオブジェクトの状態を維持しつつ新しい整合性パスを無効化します。保護マッピングを一括削除してはなりません。
模範解答
キャッシュ優先の読み取り、リソースバージョンゲート、キーごとの再キューイング、重要なアクション向けのサーキットブレーカーという4つのレイヤーを実装します。AtomicFIFO により初期リストの処理と増分イベントの整合性が保たれ、Store は最新の観測リソースバージョンをレポートします。書き込み後、コントローラーはターゲットバージョンを記録し、キャッシュがそのバージョンに達した後にのみキーを処理します。達していない場合はバックオフ付きで再キューイングします。
削除、スケールダウン、Lease の決定では、キャッシュの新しさが不明な場合やしきい値を超えている場合に制限付きのライブリードを使用し、失敗時はそのキーを一時停止します。メトリクスはバージョン遅延、スキップされた処理、キューの滞留時間、ライブリード率をカバーします。再起動時はマッピングを復元する前にキャッシュ同期を待ちます。カナリア展開により収束、回復、API サーバーの負荷を検証し、保護状態を一括クリアすることはありません。
よくある間違い
- 間違い → すべての reconcile で API サーバーからライブリードを行う。失敗する理由 → QPS とレイテンシーが増加し、キャッシュの目的が失われる。修正方法 → 重要なアクションまたはバージョンが不明な場合にのみライブリードを行う。
- 間違い → 1つのオブジェクトが古い場合にすべてのワーカーを一時停止する。失敗する理由 → 1つのホットキーによって全体的な障害が発生する。修正方法 → オブジェクトキー単位でスキップおよび再キューイングを行う。
- 間違い → ローカルのタイムスタンプのみを比較する。失敗する理由 → クロックのずれにより watch の因果関係を証明できない。修正方法 → API のリソースバージョンを比較する。
- 間違い → 再起動後にすべての保護をクリアする。失敗する理由 → キャッシュの再構築中に処理が実行されてしまう可能性がある。修正方法 → 同期を待ち、バージョンチェックを行って状態を復元する。
フォローアップの質問
なぜローカルタイムスタンプよりもリソースバージョンの方が安全なのですか?
API サーバーのオブジェクト変更シーケンスに由来しており、キャッシュが特定の書き込みを観測したことを証明できるためです。ローカル時間はクロックのずれ、ネットワーク遅延、プロセスの停止による影響を受けます。リソースバージョンはオブジェクトをまたぐトランザクションシーケンスではないため、複数オブジェクトの整合性には依然として明示的な設計が必要です。
1つのキーが古い状態のままの場合、スタベーション(飢餓状態)をどのように防ぎますか?
指数バックオフに上限を設定し、他のキーの実行を許可しつつ最大待機時間に対してアラートを発報します。しきい値を超えた後は、低頻度のポーリングまたは1回のライブリードに切り替えます。急激なリトライによって API サーバーに過負荷がかからないよう、連続スキップ回数をカウントします。
操作を拒否すべきなのはどのような場合ですか?
削除、スケールダウン、フェイルオーバー、または Lease の期限切れに関する決定において、新しさが不明でライブリードが失敗した場合、そのキーを一時停止して保護を維持します。通常のステータスレポートは明示的な許容ウィンドウ内であれば継続できますが、ステータスやメトリクスにおいて性能低下(degraded)状態であることを記録する必要があります。