TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

誰も使っていないWebhookを6秒ごとに探していたoperator: KubeVirt本体のPRが2日16時間でマージされるまで

結果: マージ (2026-10-20 16:05, kubevirt/kubevirt#19499). 2026-10-29時点では、この変更を含むリリースはまだありません。 実はGitHubのPR・レビュー・インラインコメント・タイムライン・検査記録、KubeVirtのソース(PRのベースコミット 580886af)、そしてコントリビューション台帳の実測ローデータ(operator指標の元の値、reconcileの間隔)とドラフトから持ってきたものです。時刻は韓国時間です。

目次

一言まとめ

PR kubevirt/kubevirt#19499 virt-operator: stop GETting the disabled ContainerPath webhook on every reconcile
変更点 3つのファイル。起動前の同期リストに1行追加、直接GETしていた12行を削除、既存の単体テストを拡張。10行追加、13行削除
反応 レビュアーがコメントを1つ外すようインラインコメントを残して承認、そのコードを最初に入れたapproverが /approve
結果 PR公開 10-17 23:37 → レビュー 10-19 16:54 → 承認 22:23 → マージ 10-20 16:05、約2日16時間27分。42個の検査に合格
꺼진 웹훅을 reconcile 마다 찾던 길 KubeVirt v1.9.0 리더 virt-operator, 59일 누적 카운터(실측) ① 고치기 전: 게이트가 꺼져 있으면(기본값) reconcile 인포머 캐시 조회 없음 → 직접 GET API 서버 404 약 6초마다 한 번 (중앙 6.055초, 236구간) GET mutatingwebhookconfigurations 404 843,995 LIST nodes(reconcile 마다 한 번, 비교용) 843,995 operator 전체 요청 15,509,446 중 404 가 5.4% ② 고친 뒤(#19499) 시작 전에 웹훅 인포머 동기화 캐시만 믿고 조회 없음 → 요청 없음 있음 → 지움 게이트를 켰다 끈 경우 웹훅은 캐시에 보이므로 예전처럼 지운다
図: 無効なWebhookをreconcileごとに探していたパスと修正後

1. 何が問題だったのか: 59日間で843,995回の404

TT Labでは受講者の実習用VMをKubeVirtで立ち上げます。2026-10-17にTT LabクラスタのKubeVirt構成要素を読み取り専用コマンドでざっと確認しつつ (コントリビューション台帳の measure/kv)、リーダーであるvirt-operatorが出力する kubevirt_rest_client_requests_total 指標をそのまま受け取りました。 バージョンはKubeVirt v1.9.0、Kubernetes v1.34.10であり、そのoperatorは59日目から稼働していました。カウンターはプロセスが起動した後に蓄積された値です。

リクエスト 59日間の累積
GET mutatingwebhookconfigurations → 404 843,995
LIST nodes → 200 (reconcileごとに1回、比較用) 843,995
operatorのすべてのRESTリクエスト 15,509,446
2xxではないoperatorのリクエスト 843,999

404を受け取るGETの数が、reconcileごとに1回行う LIST nodes と一桁まで一致していました。reconcile 1回につき404が正確に1回発生していることを意味します。この404はoperator全体のリクエストの5.4%(843,995 ÷ 15,509,446)であり、2xxではない応答843,999個のうち4個を除いたすべてです。

同日、リーダーoperatorのログの「Handling KubeVirt resource」237行を集計したところ、reconcileの間隔は最小6.007秒、中央値6.055秒、最大6.088秒(236区間)でした。59日を6.055秒で割ると約84万2千回となり、カウンターと大きくずれはありません(計算)。reconcileが6秒ごとに回ること自体はLease更新に起因する別の問題としてすでにIssue(#19342)と#19417修正PR(

, 2026-10-29時点でオープン)が存在していました。私たちが確認したのはその上に重なった別の問題でした。reconcileが何秒ごとに回ろうと、このGETは最初から行う必要のないリクエストでした。 VirtOperatorRESTErrorsBurst 目立った被害はありませんでした。しかしPRの本文に書いた通り、これらの404は

アラートが監視するエラー率の下に常に5%程度のベースを敷いてしまいます。アラートの閾値(80%)には遠く及ばないためアラートは鳴りませんが、ダッシュボード上の本物のエラーを隠してしまいます。

2. 原因: ソースのどの行か 580886af 行番号はPRのベースコミット

それでは、「キャッシュが一杯になっていないかもしれない」という懸念は正しい懸念でしょうか。コントローラーは作業を開始する前に複数のインフォーマーの同期を待ちます。 kubevirt.go 169–194行 の hasSynced のリストです。ここに検証Webhookインフォーマー(180行目 ValidationWebhook)はあるのに変異Webhookインフォーマー(MutatingWebhook)だけが抜けていました。そのため、キャッシュを信頼できなかったことには理由があり、修正すべき箇所はGETではなく同期リストのようでした。

この直接的なGETはWebhookとともに #16662(VEP 165、2026-02-24マージ)で導入されました。

3. 何を変更したか:diffの要旨

 # pkg/virt-operator/kubevirt.go: 시작 전에 기다리는 인포머 목록
 			informers.ValidationWebhook.HasSynced() &&
+			informers.MutatingWebhook.HasSynced() &&

 # pkg/virt-operator/resource/apply/admissionregistration.go
-	// Feature gate is disabled, delete the webhook if it exists
+	// Feature gate is disabled, delete the webhook if it exists.
 	_, exists, _ := r.stores.MutatingWebhookCache.Get(webhook)
-	if !exists {
-		// Also check directly in case cache is not populated
-		_, err := r.k8sClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(
-			context.Background(), webhook.Name, metav1.GetOptions{})
-		... (404 면 nil, 그 밖의 오류면 반환, 있으면 exists = true)
-	}

キャッシュが信頼できるようになると、キャッシュに存在しないということは削除すべきものがないという意味になるため、APIリクエストを行いません。ゲートを有効にしてから無効にした場合、operatorが managed-by のラベルが付いているためキャッシュに表示され、以前のように削除されます。PRの本文には、この選択の代償についても記載しました。誰かが手動でそのラベルを外すと、operatorはWebhookを確認できず削除しません。operatorがラベルで選択する他のオブジェクトも同様に扱われます。「最初の同期前までのみGETを残す」という案も考えましたが、状態を余分に持たなければならないため、1行の同期追加を選択しました。

テストは、既存の単体テスト「should not create virt-launcher-pod-mutator webhook when disabled」を拡張しました。ダミーのクライアントに対してこのWebhook名で get が1回でも記録されたら失敗するようにしました。PRの本文に記載した結果は次のとおりです(Go 1.27.2、linux/amd64、 GOFLAGS=-mod=vendor、main 6e80bca).

テスト 結果
テストのみ変更して修正していない状態、「ContainerPathVolumes feature gate」のグループ 3つ中1つ失敗
修正後の同じグループ 合格
go test ./pkg/virt-operator/... 合格

1回は ./pkg/virt-operator/resource/apply/ の TestInstallStrategy が失敗しましたが、修正版と未修正版のどちらでも再実行したところ再現しなかったことも、本文にそのまま記載しました。この出力の元のファイルは記録に別途残していません。修正したoperatorをTT Labクラスターにデプロイして404が消えるところまでは再測定していません(未測定)。TT Labクラスターはまだv1.9.0であり、この変更を含むリリースが存在しないためです。

AIの使用については次のように明らかにしました。KubeVirtの AI貢献ポリシーでは、AIツールを使用した場合はコミットのフッター(Assisted-by:·Co-authored-by:·Generated-by:)で明らかにすることを推奨しており、DCOの署名はそのまま求められます。コミットには Assisted-by: Claude と Signed-off-by を付与し、PRテンプレートの「AI Contributions」欄に記入したうえで、本文の最後に「指標から原因を追跡し、変更とテストのドラフトを作成するにあたってClaudeの助けを借り、すべての行を確認し、上記の数値は自分のクラスターで測定した」という段落を追加しました。1点、原則通りにいかなかったことがあります。レビューを反映して再作成したコミット 47a37b0a は、GitHub上で署名なしコミット(unsigned)として表示されます。原則3のSSH署名が、書き直されたコミットから抜けてしまったようです。

4. 反応:インラインコメント1件、承認2件

時刻 日
10-17 23:37 PR公開。prowが size/S·area/operator·sig/control-plane ラベル、レビュワー2名を指定
10-17 23:38 CodeRabbitは「このリポジトリは自動レビューが無効になっている」としてスキップ。prowは「信頼されていない作成者は /ok-to-test でテストを開始できない、コラボレーターが /test all を実行する必要がある」と案内
10-19 16:52 レビュワーのインラインコメント。16:54のレビューで /test all とともにアプルーバー1名を /cc
10-19 22:03 コメントを修正したコミットで再プッシュ、22:13にインラインコメントへ返信
10-19 22:23 レビュワーの承認、 lgtm ラベル
10-19 23:27 アプルーバーが /approve、ボットが2段階e2e 8個(sig-network·storage·compute·operator、Windows、vGPU、IPv6)を実行
10-20 16:05 マージ

レビューの内容はインラインコメントが1件でした。最初にアップロードしたバージョンには、削除したGETの位置に5行のコメントがありました。「コントローラーはWebhookインフォーマーの同期を待ち、Webhookは常にラベルを持っているため、キャッシュに存在しない場合は削除するものがない。ここでAPIサーバーに問い合わせると、ゲートを使用していないすべてのクライアントでreconcileごとに404 GETが発生する」という説明でした。レビュワーは、これがそれほど大きな問題だったのか分からないと述べました。Webhookが作成または削除されたらイベントハンドラーが検知して再度キューイングするはずなので、コメントは削除してもよいのではないかという意見でした。

その通りでした。同期前の短い隙間にキャッシュが空であったとしても、Webhookが出現した瞬間にインフォーマーが再度reconcileを呼び出します。コメントはこのGETの有用性を誇張していたことになります。5行のコメントを削除してコミットを修正し再アップロードした上で、「インフォーマーが追加・削除時にどうせ再びキューに入れるため、コメントが大げさに言っていたので削除した」と簡潔に返信しました。その結果、PRのコードは1行の追加とGETブロックの削除のみとなりました。

アプルーバーは virt-operator ディレクトリのOWNERSに記載されている人物であり、この直接的なGETを追加した#16662の作成者でもあります。残された言葉は /approve と感謝の1行でした。2段階e2eを含む42個の検査がすべて合格し、翌日の午後にtideによってマージされました。記録には、このPRがKubeVirtを主軸とすることを決定した後に本体リポジトリにマージされた最初のPRとして記載されています。

5. 学んだこと:オープンソース貢献のコツ

Titiの一言。 門番のおじさんが6秒ごとに倉庫の扉を叩いて「ここに箱はありますか?」と尋ねたそうです。倉庫には最初からその箱などなかったのですが。メモを見ればわかるはずなのに、メモのリストにその倉庫だけが抜けていたため、信用できなかったのです。メモに1行書き加えてあげたところ、2ヶ月間に84万回以上も叩いていた作業がなくなりました。「なぜノックが必要だったのか」を長々と書き留めていたメモは、「それは外してもいいですよ」と言われたので剥がしたそうです。

リンク

すべての資料は2026年10月29日に閲覧しました。

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

コメント

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

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