設問と背景
Kubernetes v1.36 で宣言的バリデーションが GA に昇格し、DeclarativeValidation フィーチャーゲートがデフォルトで有効化されました。ルールは型定義の隣に +k8s: マーカーとして記述され、validation-gen によって生成されます。この質問では、API コントラクト、コードジェネレータ、互換性、およびリリース運用を結びつけて考えられるかがテストされます。
面接官が評価するポイント
- 手書きのバリデーションにおける保守性と一貫性のリスクを説明できるか。
- 宣言的ルール、生成されたコード、OpenAPI への公開、ランタイムでの拒否を区別できているか。
- ambient ratcheting が古いオブジェクトの更新にどのように影響するかを正しく説明できるか。
- ルールの厳格化によって保存済みオブジェクトが壊れないよう、テスト、ロールバック、段階的な移行を設計できるか。
最初に確認すべき質問
API が Kubernetes のネイティブ型なのか CRD なのか、クライアントが OpenAPI に依存しているか、そして制約が新規追加、緩和、または厳格化のいずれであるかを確認します。また、古いオブジェクトに過去に受け入れられた値が含まれているか、どのジェネレータ、リンター、サーバーのバージョンが相互運用する必要があるかも確認します。
30秒の簡潔な回答
宣言的バリデーションは、型定義の隣に制約を配置し、単一のジェネレータで一貫したコードを生成し、OpenAPI でルールを利用可能にします。計画には、ルールの設計、生成と静的チェック、サーバーのランタイムバリデーション、古いオブジェクトの互換性、およびロールバックを含める必要があります。ルールを厳格化する際、ambient ratcheting は変更されていない既存フィールドを保護しますが、新しい値については互換性のレビューと段階的なバリデーションが依然として必要です。
ステップごとの詳細解説
1. ルールソースの定義
+k8s:required、+k8s:minimum=0、列挙型制約などのマーカーを使用して、フィールドの隣でルールが把握できるようにします。複数フィールドにまたがる不変条件については、ビジネスロジックをジェネレータの外部に隠すのではなく、不変条件、エラーメッセージ、サポートされるバージョンを文書化します。
2. 生成と検証
validation-gen はマーカーを解析し、Go のバリデーション関数を生成して API スキームに登録します。CI はジェネレータ、単体テスト、kube-api-linter、OpenAPI の差分チェックを実行し、マーカー、生成されたコード、公開スキーマに乖離が生じないようにします。生成されたファイルは再現可能である必要があり、手動で編集してはなりません。
3. バージョンの進化への対応
制約を追加する前に、保存されているオブジェクトとクライアントの挙動を評価します。ambient ratcheting は古いオブジェクトと新しいオブジェクトを比較します。フィールドが意味的に変更されていない場合、新しいルールはその古い値を理由に更新をブロックしません。フィールドが変更された場合は、新しいルールが適用されます。厳格化には依然として移行ツール、監査メトリクス、明確なエラーが必要です。
4. リリースとロールバック
段階的なロールアウトの前に、互換性テストスイートやシャドウバリデーションで拒否率を測定します。API エラーコード、リソースバージョン、クライアントのリトライを監視します。エラー率が急上昇した場合は、受け入れ済みのオブジェクトを読み取り可能な状態に維持しつつ、ジェネレータまたはルールのバージョンをロールバックします。GA となりフィーチャーゲートがデフォルトで有効化されても、移行テストが不要になるわけではありません。
優れた回答例
私はバリデーションをバージョニングされた API コントラクトとして扱います。+k8s: などのマーカーでフィールド制約を表現し、validation-gen で再現可能な Go コードを生成し、CI では単体テスト、リンター、OpenAPI の差分を使用して3つの視点の整合性を保ちます。複数フィールドにまたがる不変条件には専用のテストと安定したエラーが必要であり、生成されたファイルを手動で編集してはなりません。
ルールを厳格化する前に、保存されたオブジェクトを再生してクライアントの挙動を測定します。ambient ratcheting は変更されていない既存値のみを免除します。ユーザーがそのフィールドを編集すると新しいルールが適用されるため、移行ツールと段階的ロールアウトは引き続き必須です。ローンチ後は拒否率、バージョン分布、リトライを監視し、必要に応じてルールのバージョンをロールバックします。GA は統一されたメカニズムを提供するものであり、互換性ガバナンスの代わりになるものではありません。
よくある間違い
- ジェネレータを単なるフォーマットツールとして扱い、サーバーのランタイム動作における役割を見落とすこと。
- 生成されたサーバーコードやバージョン互換性を無視し、OpenAPI のみを唯一のバリデーションポイントとして扱うこと。
- 編集されたフィールドには新しいバリデーションが適用されるにもかかわらず、ambient ratcheting を恒久的な緩和と誤解すること。
- 保存済みオブジェクトに対する移行計画、ロールアウトメトリクス、ロールバックパスなしにルールを追加すること。
フォローアップの質問と回答
なぜ手作業でバリデーション関数を書き続けないのですか?
手書きのロジックは分散し、発見しにくく、リソース間で挙動の不一致が生じやすいためです。マーカー、ジェネレータ、リンターを使用することで、ルールのレビューや再現が容易になり、OpenAPI を介した公開もスムーズになります。
最小値を厳格化すると、古いオブジェクトはすぐに壊れますか?
フィールドを変更しない更新であれば、ambient ratcheting によって過去の値を維持できます。オブジェクトの新規作成やそのフィールドの編集時には新しいルールを満たす必要があるため、オブジェクトの読み取り、コピー、再書き込みを行うクライアントは引き続き確認が必要です。
生成されたコードに乖離がないことをどのように証明しますか?
CI でジェネレータのバージョンを固定して生成を実行し、作業ツリーに変更が生じた場合は失敗させます。OpenAPI、単体テスト、エンドツーエンドの拒否動作を比較し、ジェネレータのアップグレードをロールアウトする前に生成された diff をレビューします。