Skip to content
Published on

Live Migration 1:migration CRDからtarget Pod作成まで

Authors

はじめに

ライブマイグレーションを理解する際、多くの人がすぐにpre-copyやダーティページに入っていく。しかしその前にもっと重要な質問がある。**誰がtarget Podを作り、いつsource VMにhandoffをかけ、どのポリシーでマイグレーション開始を許可するのか?**これはデータプレーンではなくコントロールプレーンの問題である。

本記事はpkg/virt-controller/watch/migration/migration.goを中心に、migration CRが作成されてからtarget Podが準備されるまでのオーケストレーションを見る。

マイグレーションはAPIアクションではなく作業オブジェクトである

前の記事で見たように、ユーザーがmigrateを要求するとvirt-apiは直接移行しない。代わりにVirtualMachineInstanceMigrationオブジェクトを作成する。

その後はvirt-controllerのmigration controllerがこのオブジェクトを監視する。この設計の利点は明確である。

  • 作業が独立して追跡される
  • コントローラが非同期に処理する
  • 失敗、pending、abortを別々のライフサイクルで扱える

つまりマイグレーションは「関数呼び出し」ではなくKubernetesオブジェクトベースのオーケストレーションである。

migration controllerが見ているもの

NewControllerのシグネチャを見ると、migration controllerはかなり多くのinformerとstoreを持っている。

  • VMI informer
  • Pod informer
  • Migration informer
  • Node store
  • PVC store
  • Storage class store
  • Storage profile store
  • Migration policy store
  • Resource quota informer
  • KubeVirt CR store

なぜこんなに多いのか?ライブマイグレーションは単にソースとターゲットが合えばいい作業ではないからである。

  • target Podがスケジュール可能か
  • ストレージがターゲットからも見えるか
  • クラスタ全体の同時マイグレーション制限はどうか
  • マイグレーションポリシーがどのタイムアウトと帯域幅を要求するか
  • リソースクォータがtarget Pod作成をブロックしないか

つまりmigration controllerはポリシーと容量の中央判断機である。

priority queueを使う理由

興味深い点は、migration controllerが通常のworkqueueではなくpriority queueを使っていることである。コメントを見ると、アクティブなマイグレーションにより高い優先度を与え、容量待ちのマイグレーションがアクティブなマイグレーション処理を遅らせないようにする意図が見える。

これは重要な設計ポイントである。マイグレーションは一度始まると継続的に状態を追跡する必要があるため、pendingとactiveを同じようにキューイングするのは望ましくない。

target Podはどう作られるか

migration controllerも直接raw Pod specを組み立てず、template serviceを使う。インターフェースにRenderMigrationManifestがあることから、migration target Podは通常のlauncher Podに似ているが別のレンダリングパスを持つことがわかる。

つまりcontrollerのフローは次の通り。

  1. migration CRを検出
  2. 該当VMIのマイグレーション可否を検討
  3. target Podが必要ならマイグレーション用launcherマニフェストをレンダリング
  4. target Podを作成
  5. ソースとターゲットの状態を追跡してhandoff

つまりマイグレーションの最初のステップは「メモリをコピーする」ではなく新しいlauncher Podを立ち上げられるかどうかである。

なぜtimeoutがこんなに多いのか

migration.goにはいくつかのtimeout定数が見える。

  • unschedulable pending timeout
  • catch-all pending timeout

これはtarget Podが単に遅いのと、事実上不可能な状態を区別するためである。

例えば:

  • ノードが一時的に不足している場合
  • 特定リソースが永遠に合わない場合
  • PVC attachに時間がかかる場合

これらをすべて同じ失敗として処理すると運用者が原因を把握しにくい。そのためcontrollerはpendingの意味を細分化している。

migration policyとcluster configはどこで反映されるか

migrationPolicyStoreclusterConfigがcontrollerにある理由は、マイグレーションがVMIごとに同じポリシーで動くわけではないからである。

代表的にポリシーは以下に影響する。

  • 同時マイグレーション数
  • ノードごとのoutboundマイグレーション数
  • 帯域幅制限
  • 進捗タイムアウト
  • 完了タイムアウト
  • post-copy許可の有無
  • TLS無効化の有無

つまり「マイグレーションする」という言葉の裏には常にポリシーレイヤーが隠れている。

ストレージとクォータがマイグレーションコントロールプレーンに入る理由

運用者の立場からはネットワークとCPUだけを考えがちだが、target Podを実際に立ち上げるにはストレージとクォータも重要である。

ストレージ

ターゲットノードで必要なボリュームが準備されていなければマイグレーションは始まることもできない。

クォータ

新しいtarget launcher Podを作成する必要があるため、namespaceリソースクォータに引っかかる可能性がある。

つまりマイグレーションコントロールプレーンはゲストメモリコピーよりはるかにKubernetesらしい問題を先に解決する必要がある。

handoffはいつ起こるか

migration.goにはhandOffMapのような構造も見える。これはソース側でvirt-handlerに渡す瞬間を管理するための仕組みである。簡単に言えばcontrollerは永遠にすべてを抱え込まない。一定段階を過ぎるとnode-local実行プレーンがより大きな役割を担う。

この分離が必要な理由は次の通り。

  • controllerはクラスタ全体の状態判断に強い
  • 実際のマイグレーション実行はソースとターゲットノードのvirt-handlerとlauncherがよりよく理解している

つまりライブマイグレーションはコントロールプレーンと実行プレーンが段階的に責任を分担する構造である。

自動マイグレーション要求と動的ネットワーク変化

pkg/network/migration/evaluator.goは別の興味深い事実を見せる。セカンダリネットワークのhotplugやunplug、NAD変更はmigration required conditionを作ることができる。

これはマイグレーションが必ずしもユーザーが「今移して」と言って起こるだけではなく、現在のPodで安全に反映しにくいネットワーク変化がある際の再配置手段としても使われることを意味する。

つまりマイグレーションコントロールプレーンはメンテナンス機能であると同時にconfiguration convergenceメカニズムでもある。

よくある誤解

誤解1:マイグレーションはソースQEMUがターゲットQEMUと直接やり取りすれば終わる

いいえ。その前にmigration CR、target Pod作成、スケジューリング、ポリシー、クォータ、ストレージ準備がある。

誤解2:migration target Podは既存のPodを再利用するだけ

いいえ。別途のtarget launcher Podが新たに作成される可能性がある。

誤解3:マイグレーション失敗はほとんどデータプレーンの問題

いいえ。実際の運用ではコントロールプレーンでpending、unschedulable、クォータ、ポリシーmismatchでブロックされるケースも多い。

運用者がまず確認すべきこと

  • migration CRが作成されたか
  • target Podが作成されたか
  • target Podがpendingかrunningか
  • マイグレーションポリシーとクラスタ全体のconcurrency制限はどうか
  • namespaceクォータとストレージの可視性は問題ないか

これらのステップが通過してはじめて、次の記事のpre-copyとpost-copyが意味を持つ。

まとめ

KubeVirtライブマイグレーションのコントロールプレーンはmigration CR作成から始まり、virt-controllerがポリシー、クォータ、ストレージ、スケジューリング状態を見てtarget Podを準備する過程へと続く。つまりマイグレーションはlibvirtデータ転送の前にすでにKubernetesオーケストレーションの問題である。この観点を把握してこそ、実際の運用でなぜマイグレーションが始まりもせずpendingで止まるのかを理解できる。

次の記事では、このコントロールプレーン準備が終わった後に実際のメモリとディスク状態を移すpre-copy、post-copy、ダーティページモデルを説明する。