TT Lab
ブログ

한국어 English 日本語

はじめる
ブログ

ブログ

KubeVirt ソースコード読み解き 2: API と CRD — 型、生成コード、Webhook

ステータス: ドラフト (2026-10-17)、ソース + 読み取り専用の実測。 基準は KubeVirt v1.9.0(コミット 79d34c17)です。Webhook の警告文はソースから読み取ったものであり、実際の kubectl 画面で確認したものではありません(VM を新しく作成しませんでした)。

KubeVirt ソースコード読み解き 2: API と CRD

目次

1. 直感: 3 つの場所で決まる

VM の YAML の 1 行が受け入れられるまでに 3 つの場所が関与します。

  1. 型 — types.go の Go 構造体がフィールド名と形を決定します。
  2. スキーマ — その構造体から生成された OpenAPI スキーマが CRD に載せられ、kube-apiserver が形の誤ったリクエストを事前にフィルタリングします。
  3. Webhook — 形は合っていても意味が誤っているリクエスト(同時に使用してはいけないフィールド、無効化された機能ゲート)は virt-api の Webhook が弾きます。拒否せずに 警告のみ を付与することも可能です。

2. 型: types.go

staging/src/kubevirt.io/api/core/v1/ 以下の types.go という 1 ファイルは 4,090 行あります。まずは 2 つの構造体だけを探せば十分です。

Running フィールドには Deprecated: コメントが付いています(:2010)。それでも削除せずに残しておいた理由は 1 つのメソッドに表れています。2 つのフィールドを 1 つの実行戦略にまとめる RunStrategy() (:1957です。

RunStrategy := RunStrategyHalted
if vm.Spec.Running != nil {
	if (*vm.Spec.Running) == true {
		RunStrategy = RunStrategyAlways
	}
} else if vm.Spec.RunStrategy != nil {
	RunStrategy = *vm.Spec.RunStrategy
}

出典: kubevirt/kubevirt v1.9.0 types.go 1961–1968 行(Apache-2.0)。コントローラーはこのメソッドのみを呼び出すため、 running: true はコード内で直ちに Always になります。実行戦略の定数はドキュメントに 5 つ記載されていますが、コードには 6 番目の WaitAsReceiver (:1995も存在します。クラスター間マイグレーションを受け取る側の VM のための値であり、機能ゲートが有効な場合のみ Webhook が受け入れます(以下の第 4 節)。

VMI のフェーズ一覧(:1098)は、第 3・4 回を読む際の地図になります。 Scheduled に付いているコメントが「ここで virt-controller の責任が終了し、virt-handler に引き継がれる」と述べています(:1109).

3. 生成コード: 手を加えないファイル群

types.go 한 파일에서 생겨나는 것들 make generate → hack/generate.sh. 생성 파일은 손으로 고치지 않는다 staging/src/kubevirt.io/api/core/v1/types.go Go 구조체 + 주석 마커(+genclient, +kubebuilder…) · 4,090줄 deepcopy-gen deepcopy_generated.go 7,410줄 swagger-doc types_swagger_generated.go 1,312줄 openapi-gen openapi_generated.go 40,507줄 · client-go/api client-gen client-go 클라이언트 kubevirt.io/client-go controller-gen crd → crd-validation-generator controller-gen 결과는 virt-operator 의 validations_generated.go(33,701줄)로 들어가 설치 때 CRD 의 openAPIV3Schema 가 된다(4절 그림의 ③ 관문). CI 는 make generate 뒤 차이가 있으면 떨어뜨린다(generate-verify).
図: types.go の 1 つから生成されるファイル群

make generate(Makefile:53)はビルダーコンテナー内で hack/generate.sh を実行します。このスクリプトが順番に呼び出すジェネレーターは以下の通りです。

ジェネレーター 入力 出力 実測行数
swagger-doc types.go のコメント types_swagger_generated.go(API ドキュメントの説明) 1,312
deepcopy-gen(generate.sh:27) +k8s:deepcopy-gen マーカー deepcopy_generated.go 7,410
defaulter-gen デフォルト値関数 zz_generated.defaults.go —
openapi-gen 型全体 client-go/api/openapi_generated.go 40,507
client-gen +genclient マーカー client-go の型付きクライアント —
controller-gen crd(:139) +kubebuilder: マーカー CRD YAML → crd-validation-generator(:177) → virt-operator/…/validations_generated.go 33,701

最後の行が特徴的です。KubeVirt は CRD YAML をリポジトリに保存せず、controller-gen が生成したスキーマを Go の文字列に変換して virt-operator の中に埋め込みます。virt-operator がインストール時に NewVirtualMachineCrd() (crds.go:187)で CRD をコードとして構築し、 CRDsValidation["virtualmachine"] (validations_generated.go:4444)を openAPIV3Schema として付加します。そのため、 フィールドを 1 つ追加する PR では、types.go の 1 行に対して数百行の生成ファイルが追随します。 レビュワーは生成ファイルを読み込まず、CI が make generate を再実行して差分がないかどうかだけを確認します(generate-verify)。手動で修正された生成ファイルはここで弾かれます。

4. Webhook: リクエストが通過する 5 つの関門

VM 하나를 apply 하면 — API 서버 안의 관문 왼쪽이 kube-apiserver 의 순서, 오른쪽이 그 관문을 맡은 KubeVirt 코드 ① 인증 · 인가 RBAC ② 변형 웹훅 기본값 채우기 virt-api /virtualmachines-mutate VMsMutator.Mutate ③ 스키마 검증 CRD 의 openAPIV3Schema virt-operator CRD 를 설치 validations_generated.go ④ 검증 웹훅 허용 · 거절 · 경고 virt-api /virtualmachines-validate VMsAdmitter.Admit ⑤ etcd 에 저장 그 뒤 컨트롤러가 본다 ④ 가 돌려준 경고는 kubectl 에 「Warning:」 줄로 보인다 spec.running is deprecated, please use spec.runStrategy instead. 두 웹훅 모두 failurePolicy: Fail — virt-api 가 응답하지 않으면 VM 을 만들지도 고치지도 못한다(실측: 검증 23개 · 변형 4개 모두 Fail)
図: apply された VM が kube-apiserver 内で通過する関門とそのコード

誰が Webhook を登録するのか

Webhook 設定オブジェクト(ValidatingWebhookConfiguration)も virt-operator がコードで作成します。 NewVirtAPIValidatingWebhookConfiguration()(webhooks.go:296)はこのパスごとに Webhook を 1 つずつ配置し、 failurePolicy を Fail に設定します。VM のパスは定数 VMValidatePath = "/virtualmachines-validate" (:945)です。反対側で virt-api が同じ定数で HTTP ハンドラーを登録します(api.go:994)。パス名を片方だけで変更すると Webhook が 404 を受け取り、 Fail ポリシーのために誰も VM を作成できなくなってしまいます。2 つのファイルが同じ定数を使用している理由はここにあります。

VMsAdmitter.Admit() を 1 行ずつ

vms-admitter.go:87 の Admit() は以下の順序で検証を行います。

  1. リクエストされたリソースが実際に virtualmachines であるか、スキーマに適合しているか(ValidateSchema).
  2. 削除中の VM であれば即座に許可します。他の削除処理との競合を避けるためです。
  3. コピーに instancetype と preference を適用し、デフォルト値を埋めた上でその結果を検証します。コメントには「保存したくないためコピーに適用する」と記載されています。つまり、検証は「実際に起動する VMI」を基準に行われますが、etcd にはユーザーが送信したそのままの内容が格納されます。
  4. 作成時(Create)のみ: 機能ゲートが無効化されたフィールドを使用していないか、ネットワーク設定が正しいか。
  5. ValidateVirtualMachineSpec() — テンプレート、メタデータ、VMI スペック全体、DataVolume の枠組み、実行戦略、ライブアップデート機能。
  6. ストレージ関連の検査(storageadmitters.Admit)とボリューム要求。
  7. 通過すると警告を収集して許可します。

最後のステップが spec.running の警告が発生する箇所です(:175–178).

warnings := warnDeprecatedAPIs(&vm.Spec.Template.Spec, admitter.ClusterConfig)
if vm.Spec.Running != nil {
	warnings = append(warnings, "spec.running is deprecated, please use spec.runStrategy instead.")
}

出典: kubevirt/kubevirt v1.9.0 vms-admitter.go 175–178 行(Apache-2.0)。拒否ではなく AdmissionResponse.Warnings であるため VM はそのまま作成され、kubectl はレスポンスヘッダーの警告を Warning: 行で表示します。 warnDeprecatedAPIs() (vmi-create-admitter.go:141)は、非推奨状態になった機能ゲートをスペックが使用している場合に警告を追加します。

実行戦略の検査

validateRunStrategy()(:231)では 3 つの点を確認します。 running と runStrategy を同時に使用している場合は拒否、両方とも指定されていない場合は「RunStrategy must be specified」として拒否、そして runStrategy の値が許可リスト validRunStrategies(:53)の 5 つのいずれかであるかです。 WaitAsReceiver はこのリストに含まれておらず、 DecentralizedLiveMigration 機能ゲートが有効な場合のみ個別に通過します。

Webhook 以外のもう一つの入口: サブリソース

virt-api は Webhook サーバーでありながら 集約 API サーバー(v1.subresources.kubevirt.io)でもあります。 virtctl start は VM を直接修正するのではなく …/virtualmachines/<이름>/start を呼び出します。ハンドラー StartVMRequestHandler() (lifecycle.go:43)は実行戦略を確認し、 Halted の場合は VM の spec.runStrategy(または旧 spec.running)を JSON パッチに変換し、 Manual·RerunOnFailure の場合は status に起動リクエストを挿入します。 Always のようにすでに起動していなければならない戦略には意味がないとコメントに記載されています。結局のところ、サブリソースも VM オブジェクトを修正するだけであり、実際に VMI を作成する作業は第 3 回の VM コントローラーが行います。

5. 実測

v1.9.0 がインストールされた小規模なクラスターで読み取りました(2026-10-17)。

6. 制限事項

ティティの一言。 フィールドを 1 つ追加する PR が数百行に及んでいても驚かないでください。実際に人間が書いたのは types.go の数行だけで、残りは機械が書いたものです。レビューする際は types.go と Webhook、そしてテストを見るだけで十分です!

参考

すべて 2026-10-17 に閲覧しました。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます