TT Lab
ブログ

한국어 日本語 中文

はじめる
ブログ

ブログ

KubeVirt ソースコードリーディング 1: リポジトリマップ — どこから読むべきか

ステータス: ドラフト (2026-10-17)、ソース + 読み取り専用の実測。 基準は KubeVirt v1.9.0(コミット 79d34c17)です。「実測」の表示は、v1.9.0 がインストールされた小さなクラスターで閲覧のみにより確認した値です。ビルドとテストは実行していません(下記の「制限」)。

KubeVirt ソースコードリーディング 1: リポジトリマップ

目次

1. イントゥスイッション: Kubernetes に紐づく 5 つのプログラム

KubeVirt は Kubernetes を改変しません。CRD(VirtualMachine、VirtualMachineInstance など)を追加し、その CRD を監視するプログラムをいくつかクラスター上で起動するだけです。リポジトリを読む際も、この 5 つのプログラムを基準に分類すれば迷子になりません。

プログラム 実行場所 一行の役割
virt-operator コントロールプレーン (Deployment) 残りのコンポーネントをインストールし、基盤を立ち上げる
virt-api コントロールプレーン (Deployment) Webhook でリクエストを検証し、console や start などのサブリソースを提供する
virt-controller コントロールプレーン (Deployment、リーダー 1 つ) VM を監視して VMI を、VMI を監視して Pod を作成する
virt-handler ノードごと (DaemonSet) 自ノードに割り当てられた VMI を実際のドメインに合わせる
virt-launcher VM ごとに 1 つ (Pod) VMI を libvirt ドメイン XML に変換し、QEMU を起動する

「学生 VM が起動するまで」第 2 編(../kubevirt-lab-vm/02-kubevirt-inside.md)がこれら 5 つの役割をユーザーの視点で説明しているならば、この記事では その役割がリポジトリのどのフォルダにあるのかを見ていきます。

2. 図: フォルダと実行場所

kubevirt/kubevirt 저장소 지도 (v1.9.0) 왼쪽은 폴더, 오른쪽은 그 코드가 실제로 도는 자리 cmd/ 바이너리 입구 — main 만 얇게 pkg/virt-api 웹훅 · 서브리소스 API pkg/virt-controller VM·VMI 컨트롤러 · 파드 템플릿 pkg/virt-operator 설치 · 업그레이드 pkg/virt-handler 노드 데몬 · 장치 · 네트워크 pkg/virt-launcher 도메인 XML · libvirt 호출 pkg/network · storage … 여러 구성요소가 함께 쓰는 부품 staging/…/api 타입 정의 · client-go 와 짝 tests/ 기능 시험(ginkgo, 진짜 클러스터) hack/ · Makefile 빌드 · 코드 생성 · 개발 클러스터 컨트롤 플레인 virt-api ×2 Deployment virt-controller ×2 리더 1 + 대기 1 virt-operator ×2 Deployment 노드마다 virt-handler DaemonSet VM 마다 virt-launcher 파드 virt-launcher-monitor → virt-launcher → QEMU 실측(v1.9.0 소스, 시험·생성 파일 제외한 Go 줄 수) virt-launcher 26.9k virt-handler 24.5k virt-controller 23.3k virt-operator 21.3k virt-api 13.5k api 타입 11.8k
図: kubevirt/kubevirt のフォルダとそのコードが実行される場所

3. フォルダを一つずつ

cmd/ — エントリポイントは薄い

cmd/ 以下のフォルダにはそれぞれ main が一つずつあり、大部分は数行程度です。virt-controller はこれがすべてです (cmd/virt-controller/virt-controller.go:26).

func main() {
	watch.Execute()
}

本体は pkg/virt-controller/watch/application.go の Execute() (:303)です。フラグを読み込み、インフォーマーを作成し、リーダー選挙に勝利すると onStartedLeading() (:609)で VM・VMI・マイグレーションなどのコントローラーをゴルーチンで実行します。例外はノード側の 2 つのプログラムです。 cmd/virt-handler/virt-handler.go の Run() (:209)と cmd/virt-launcher/virt-launcher.go の main()(:347)は、セットアップコードが長いため cmd/ の中にも読みどころが多くあります。第 4・5 編でこれら 2 つを追っていきます。

cmd/ には 5 つ以外にも小さなヘルパーが多くあります。 virt-launcher-monitor(launcher をラップして最後まで見守る PID 1)、 virt-chroot (handler が別の名前空間でコマンドを実行するとき)、 virt-tail(シリアルコンソールログをストリーミングするサイドカー)、 virtctl(ユーザー CLI)などです。

pkg/virt-* — 5 つのコンポーネントの本体

フォルダ 最初に見るファイル 扱う編
pkg/virt-api api.go, webhooks/validating-webhook/admitters/, rest/ 2
pkg/virt-controller watch/vm/vm.go, watch/vmi/lifecycle.go, services/template.go 3
pkg/virt-handler vm.go, cache/domain-watcher.go, device-manager/ 4·7
pkg/virt-launcher virtwrap/manager.go, virtwrap/converter/converter.go 5
pkg/virt-operator resource/generate/components/(CRD・Webhook・DaemonSet をコードで作成する) 2

pkg/ の残りの部分 — 共通で使われる部品

コンポーネントフォルダ以外のパッケージは、「誰が呼び出すか」という観点で見ると分かりやすいです。 pkg/network は virt-handler(Pod ネットワークの準備)と virt-launcher(ドメインの <interface>)が一緒に使用します。 pkg/controller はインフォーマーファクトリーや期待値(expectations)などのコントローラー共通ツール、 pkg/virt-config は KubeVirt CR の設定とフィーチャーゲート、 pkg/hypervisor はハイパーバイザーごとの差異(KVM と新しく追加された MSHV)です。第 3 編のメモリオーバーヘッドの計算はこの pkg/hypervisor/kvm にあります。 pkg/libvmi は VMI を作成するビルダーであり、テストコードで多く使用されます。

staging/src/kubevirt.io/ — 別途配布される 2 つのモジュール

API タイプ(kubevirt.io/api)とクライアント(kubevirt.io/client-go)は他のプロジェクトでも流用されるため、独立した Go モジュールになっています。Kubernetes と同様の方法で、ルートの go.mod がこれらを replace としてリポジトリ内の staging/ フォルダにまとめています。そのため、VM のフィールドを修正する PR は staging/src/kubevirt.io/api/core/v1/types.go を修正し、生成コードを再作成して一緒にコミットします(第 2 編)。

tests/ — 実際のクラスターで実行される機能テスト

単体テストはコードの隣にある *_test.go であり(実測: pkg/ 以下 717 個)、Ginkgo・Gomega で記述され、フェイククライアントで実行されます。 tests/ は 機能テスト(functional test) です。実際のクラスターに KubeVirt をインストールし、VM を起動して検証します。テストごとに decorators.SigCompute のようなラベルが付いており、SIG ごとに選択して実行できます。

hack/ と Makefile — ビルドはコンテナ内で

Makefile のほぼすべてのターゲットが hack/dockerized を経由します。ビルダーコンテナ内で Bazel(または KUBEVIRT_NO_BAZEL=true の場合は go)でビルドするため、手元のマシンには Docker(または Podman)と rsync さえあれば十分です。

コマンド 実行内容 場所
make フォーマット調整 + Bazel ビルド + マニフェスト Makefile:17
make generate 生成コードの全面的な再作成(第 2 編) Makefile:53
make test / make go-test 単体テスト(Bazel / go) :93 · :90
make cluster-up · cluster-sync kubevirtci を使用して VM 内に開発用クラスターを立ち上げ、自分のビルドをデプロイする :173
make functest そのクラスターでの機能テスト :101

機能テストの一部のみを実行する場合は、 FUNC_TEST_ARGS='--focus-file=vmi_networking' make functest のように Ginkgo のフィルターを渡します (docs/getting-started.md の Testing セクション)。開発用クラスターはノードを VM として起動するため、 ネストされた仮想化が可能な Linux マシンが必要です。Mac ではビルドはできても、 cluster-up は困難です。

4. 実測: クラスターで確認した 5 つのプログラム

v1.9.0 がインストールされた小さなクラスターの kubevirt 名前空間を読み取りました(2026-10-17)。

対象 数量 イメージ
virt-operator Deployment 2/2 quay.io/kubevirt/virt-operator:v1.9.0
virt-api Deployment 2/2 quay.io/kubevirt/virt-api:v1.9.0
virt-controller Deployment 2/2 quay.io/kubevirt/virt-controller:v1.9.0
virt-exportproxy Deployment 2/2 quay.io/kubevirt/virt-exportproxy:v1.9.0
virt-handler DaemonSet 5/5(各ワーカーノード) quay.io/kubevirt/virt-handler:v1.9.0
virt-launcher 稼働中の VM 数と同数(3 個) VMI status の launcherContainerImageVersion: …virt-launcher:v1.9.0

と同じ名前空間に virt-template-apiserver·virt-template-controller(v0.2.2)も見られます。これは VM テンプレートを扱う独立したプロジェクトであり、リポジトリには hack/virt-template/sync.sh としてマニフェストのみが同期されます。このシリーズでは扱いません。

フォルダ別の規模。 テストと生成ファイルを除いた Go の行数です(v1.9.0、 find … ! -name '*_test.go' ! -name '*generated*').

フォルダ ファイル 行数 テストファイル テスト行数
pkg/virt-launcher 119 26,910 128 32,700
pkg/virt-handler 74 24,520 62 17,174
pkg/virt-controller 42 23,313 44 34,602
pkg/virt-operator 57 21,260 48 14,596
pkg/storage 45 18,007 47 24,614
pkg/virt-api 49 13,514 43 20,893
staging/…/api 55 11,831 2 52
pkg/network 75 9,913 74 16,213

virt-controller は 42 ファイルに 23,000 行とファイルサイズが大きいです。 watch/vm/vm.go の一つは 3,640 行もあります。逆に virt-launcher は小さなファイルが多くなっています。テストの行数が本文よりも多いフォルダが 4 つあることも注目に値します。レビューで「まずテストを見せてほしい」という意見がよく出る理由です(第 8 編)。

ログからソースへジャンプする方法。 KubeVirt コンポーネントのログは JSON であり、 "pos" フィールドに 파일:줄 が含まれています。実測したログの pos を v1.9.0 のソースと突き合わせたところ、すべて一致していました。例えば virt-handler の "pos":"vm.go:1459" は pkg/virt-handler/vm.go:1459 の VMI is in phase: … | Domain status: … のログ行であり、virt-launcher の "pos":"manager.go:1651" は Domain defined. です。 初めてコードを読むときは、 ログを 1 行選び、その行番号から 逆方向にたどるのが最も早いです。ただし、バージョンが異なれば行番号も異なるため、クラスターのバージョンと一致するタグを開いてください。

5. どこから読むべきか

VM が 1 つ起動するフローに沿って読む順序を推奨します。各段階で「入力は何か、そして何を作り出すのか」だけを押さえれば十分です。

  1. staging/src/kubevirt.io/api/core/v1/types.go — VirtualMachine(1942 行)、 VirtualMachineInstance(47 行)、phase リスト(1098 行)。 フィールド名がそのまま YAML の名前になります。
  2. pkg/virt-controller/watch/vm/vm.go の execute()(357 行)→ sync()(3215 行)→ syncRunStrategy()(970 行)。VM → VMI。
  3. pkg/virt-controller/watch/vmi/lifecycle.go の sync()(66 行)と services/template.go の renderLaunchManifest()(395 行)。VMI → Pod。
  4. pkg/virt-handler/vm.go の execute()(321 行)→ sync()(1433 行)。ノードにおける Pod → ドメイン。
  5. pkg/virt-launcher/virtwrap/manager.go の SyncVMI()(1380 行)と converter/converter.go の Convert_v1_VirtualMachineInstance_To_api_Domain()(967 行)。ドメイン → QEMU。

docs/components.md も良い出発点ですが、バージョンが少し古いです。Pod 内で動作する libvirt デーモンを libvirtd と記述していますが、 v1.9.0 の virt-launcher はモノリシックな libvirtd の代わりに virtqemud を起動します (cmd/virt-launcher/virt-launcher.go:432)。 実測でも Pod 内のプロセスは virtqemud と virtlogd でした(第 5 編)。

6. 制限

一言メモ。 9,000 個ものファイルがあるなんて怖じけづきますか? しかし、VM が 1 つ通過するパスには 5 つのプログラムしかありません。ログから pos を 1 行選び、その行から逆向きに読んでみてください。マップがすぐに頭の中に描かれます!

参考

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

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

コメント

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

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