TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

KubeVirtのライブマイグレーション実測 2: ビジーなメモリ、ノードのドレイン、同時移行制限

ステータス: 実測(2026-10-31)。 第1部と同じネストされたクラスター(TT Labの検証用VM3台、KubeVirt v1.9.0)で測定した値です。 ポリシーのテストは条件ごとに1~3回、drainはシナリオごとに1回、同時制限は制限ごとに1回です。作成ルール:実測データを基本とし、測定できなかったものは「未測定」、 原因を確認できなかった解釈は「推定」と表記します。

目次

1. メモリを継続的に書き換えるVM

第1部のVMは何も作業を行っていませんでした。実際のVMはメモリを使用します。事前コピーは「送信中に変更されたページを再送する」という仕組みであるため、 ゲストが書き換える速度が送信速度と同等であれば終わりません。これを実際に再現してみました。

テスト 負荷 ポリシー 結果 所要時間 ゲストの停止時間 サービス切断(新規接続 / 維持接続)
light-1 128MB なし Failed Live migration has been aborted 302秒 なし(移行元で稼働継続)
heavy-1 512MB なし Failed 301秒 なし
heavy-2 512MB bandwidthPerMigration: 32Mi Failed 301秒 なし
heavy-3 512MB allowAutoConverge: true Succeeded 33秒 566ms 2807ms / 2805ms、切断あり
uffd-3 512MB allowAutoConverge: true Succeeded 36秒 547ms 1604ms / 1603ms、切断あり
heavy-5 512MB 32Mi + autoConverge Succeeded 43秒 433ms 4287ms / 4384ms、切断あり
heavy-4 512MB allowPostCopy: true Failed Postcopy is not supported: Userfaultfd not available: Operation not permitted 2秒 なし
heavy-6 512MB 32Mi + postCopy Failed(同上の理由) 1秒 なし
uffd-1 512MB allowPostCopy: true、ノード vm.unprivileged_userfaultfd=1 Succeeded(PostCopy) 303秒 未測定 2204ms / 3006ms、切断あり
uffd-4 512MB 同上 Succeeded(PostCopy) 304秒 未測定 6214ms / 6670ms、切断あり
uffd-2 512MB 32Mi + postCopy、ノード設定有効 Succeeded(PostCopy) 306秒 未測定 6211ms / 6213ms、切断あり
메모리를 계속 쓰는 VM: 정책별 결과 1Gi 게스트에 512MB 쓰기 부하, 결과가 날 때까지(실측) 기본(정책 없음) 실패 · 301초 대역폭 32Mi 실패 · 301초 autoConverge 성공 3/3 · 33–43초 postCopy, 노드 설정 없음 실패 2/2 · 1–2초 postCopy, 노드 설정 켬 성공 3/3 · 303–306초 0초 100초 200초 300초 왜 기본값으로는 끝나지 않나 게스트가 더럽히는 속도 74–92MiB/s ≈ 보내는 속도 → 매 반복 같은 양이 다시 남아 멈출 순간이 오지 않는다
図:メモリ書き込み負荷におけるポリシー別の結果と所要時間

1.1 なぜデフォルト値では終了しないのか

進行中のlibvirtのタスク情報を5秒ごとに確認したところ、収束しなかった実行では300秒間にわたり事前コピーが184~244回繰り返されていました。残量まりは15~90MiBの間を行き来し、これを送信するのにかかる予想停止時間は1,782~1,913msでした。目標(300msから開始して最大900ms)に到達できませんでした。ゲストがダーティにする速度は毎秒約19,000~23,000ページ(74~92MiB/s)であり、送信速度とほぼ同じでした。毎回の反復で同じ量が残り続けるということです。

128MBの書き込みを続けるだけでも失敗しました。 その間、ゲストは移行元で正常に稼働していたためサービス切断はありませんでした。ただし、VMが移行されないためそのノードをドレインできません(第2節)。

1.2 ポリシー別の整理

ポリシー 512MBの負荷時 代償
なし(デフォルト) 収束せず約300秒後に断念 ノードをドレインできない
帯域幅制限 32Mi 同様に断念 制限を設定したものの実際の転送量は制限を超過(下記)
autoConverge 33~43秒で成功(3/3)、停止時間 433~566ms ゲストCPUを徐々にスロットリングして書き換え速度を低下させる。ゲストのスループットがどれだけ低下するかは測定していない(未測定)
postCopy 成功(3/3)だが、事前コピーの制限時間を使い切った後にPostCopyへ移行。サービス切断 2.2~6.7秒 ノードに vm.unprivileged_userfaultfd=1 が必要。ポストコピー中に移行元または移行先がダウンするとゲストが失われる(ドキュメント基準)

autoConvergeはその名の通り「収束させる」ための機能です。進行が滞るとQEMUがゲストのvCPUを少しずつ抑え込んで書き換え速度を落とします。今回の負荷では、これ単体で結果が失敗から30秒台での成功に変わりました。

postCopyはその逆方向です。まずゲストを移行先で稼働させ、まだ転送されていないページはゲストがアクセスした瞬間に移行元から取得します。Linuxのuserfaultfdでその瞬間を捉えるためノードのカーネルが許可している必要があり、Ubuntuのデフォルト値は0でした(ネストされたワーカーも0)。有効にすると成功しましたが、KubeVirtは事前コピーの制限時間を使い切ってからPostCopyに移行しました。また、ポストコピー中はゲストのメモリが2つのノードに分散するため、どちらかがダウンするとゲストが失われます。 ビジーなVMが存在する環境ではautoConvergeから 有効にしてみるのが、今回の実測から得られた順序です。

1.3 帯域幅制限が守られなかった

bandwidthPerMigration: 32Mi を設定した際、設定はすべてのレイヤーに反映されていました。VMIの適用設定に32Mi、QEMUの max-bandwidth: 33554432, virsh migrate-getspeed に32がともに記録されていました。しかしQEMUの info migrate のスループットは630.76Mbps(約75MiB/s)であり、10秒間の処理量も17.316GiBから18.040GiBへと約73.5MiB/sでした。転送はmultifdの8チャネルで行われました。制限がない場合(86~90MiB/s)とほぼ同じです。

multifdと速度制限の関係によるものか、KubeVirt側の設定によるものかは、multifdを無効にした比較テストを行わないと切り分けられません(未測定)。そのため現時点では「制限を設定すれば回線が保護される」と過信せず、実際の転送量を virsh domjobinfo で確認することをお勧めします。ちなみにユーザーガイドに記載されているデフォルトの帯域幅64MiB/sは古い値であり、v1.9.0の実際のデフォルト値は無制限(0)でした。ドキュメントを修正するPRはすでにオープンされています。

1.4 ポリシーを設定する方法

MigrationPolicy は、ネームスペースまたはVMIのラベルで対象を選択します。ビジーなVMが集まったネームスペースにautoConvergeのみを有効にする例です。

apiVersion: migrations.kubevirt.io/v1alpha1
kind: MigrationPolicy
metadata:
  name: busy-vms-auto-converge
spec:
  allowAutoConverge: true
  selectors:
    namespaceSelector:
      kubernetes.io/metadata.name: busy-vms

適用されたかどうかは、マイグレーション後のVMIの status.migrationState.migrationConfiguration と status.migrationState.migrationPolicyName で確認します。

2. ノードのドレイン(drain)

ライブマイグレーションが最も多用されるのはノードをドレインするときです。VMに evictionStrategy: LiveMigrate を指定しておくと、 kubectl drain はこのVMを停止せずに移行します。このパスを4つのシナリオでテストしました。

노드 비우기(drain)가 VM 을 옮기는 길 KubeVirt v1.9.0, evictionStrategy: LiveMigrate(실측) kubectl drain 파드 축출 요청, 5초마다 다시 승인 웹훅이 축출을 거절 PDB 가 아니다. VMI 에 축출 표시를 남김 축출 마이그레이션 생성 동시 한도(노드당 2)를 따른다 성공 원본 파드가 사라져 다음에 통과 실패하면 다시, 또 다시 수렴 못 함: 약 5분마다 포기 받는 노드 메모리 부족: 5분 Pending 뒤 실패 옮길 수 없는 VM: 끝없이 거절 실측: 한 대 22초, 다른 한 대 13초 되돌려도(uncordon) 축출 표시가 남는다 status.evacuationNodeName 이 그대로라 마이그레이션이 계속 생기고, 결국 VM 이 되돌린 노드를 떠났다 virtctl evacuate-cancel (v1.9.1 이상 virtctl)
図:drainがVMを移行させる流れ:退去要求、承認ウェブフックの拒否と退去マイグレーション、成功と失敗、戻した後も残る退去マーク
シナリオ 内容 結果
A 512MBの負荷がかかったVM(LiveMigrate)が存在するノードをdrain(制限600秒) drain失敗(600.9秒)。 ウェブフックが Evacuation in progress: Eviction triggered evacuation of VMI … で拒否して退去マイグレーションを作成するが、収束しないため約5分ごとに断念して再作成を繰り返す
B ディスクがRWOであるにもかかわらず evictionStrategy: LiveMigrate であるVMが存在するノードをdrain(制限120秒) drain失敗(120.8秒)。 VMI … is configured with an eviction strategy but is not live-migratable で拒否し続ける
C A・Bの実行後、ノードを再度スケジュール可能に設定(uncordon) 退去が停止しなかった。 元に戻した後も退去マイグレーションが2回余分に発生し、負荷を停止すると最後の移行が成功してVMが 復旧元のノードから離れた
D 負荷を停止したVM3台(LiveMigrate)と1台(evictionStrategy None)が存在するノードをdrain(制限400秒) 2台は 22秒・13秒 で移行された。NoneのVMは7.4秒で停止し、17.9秒で別のノード上で新しいVMIとして起動した(再起動)。残りの1台は移行先のノードのメモリ要求量が98%であったため Insufficient memory、5分後に失敗して再試行を繰り返した末に drainが400秒でタイムアウト

2.1 PDBではなくウェブフックである

drain中の kubectl get pdb -A は No resources found でした。ユーザーガイドのノード保守ドキュメントには「VMIごとにPodDisruptionBudgetを作成する」と記載されていますが、v1.9.0ではvirt-launcherポッドの退去要求を 承認ウェブフック(virt-launcher-eviction-interceptor.kubevirt.io)で受け取ります。ウェブフックは退去を拒否しつつVMIに退去マーク(status.evacuationNodeName)を残し、virt-controllerがそれを検知して退去マイグレーション(kubevirt-evacuation-…)を作成します。drainは5秒ごとに再び退去を要求し、マイグレーションが完了して元のポッドが消滅した時点で通過します。このドキュメントとの相違について修正のPRを提出しました(user-guide#1051).

したがって、drainが完了するかどうかは そのノードのすべてのVMが移行されるかどうかにかかっています。

2.2 戻しても残る退去表示

シーン C が最も意外でした。drain が失敗してノードを uncordon したのに、VMI の status.evacuationNodeName がそのまま残っていました。virt-controller はこの表示を見て退去マイグレーションを作り続け(2 回 uncordon したのにその後さらに 2 回作成された)、負荷を止めるとそのうちの 1 つが成功して VM が たった今戻したノードを離れました。「とりあえず drain を止めて戻そう」と思っても、VM は引っ越し中のままというわけです。

この表示を消すコマンドは virtctl evacuate-cancel です。しかし、v1.9.0 の virtctl で実行するとこのように失敗しました。

Internal error occurred: the server rejected our request due to an error in our request

サーバー(virt-api)は「現在退去中のノード名がリクエストと一致する場合のみ消去する」という条件を設けていますが、v1.9.0 の virtctl がリクエストにノード名を含めないために発生するバグです。同じリクエストに本文 {"evacuationNodeName": "<노드>"} を入れて送信すると 200 で消去されました。すでに修正されており(kubevirt#17008、release-1.9 バックポート #18864) v1.9.1 以降の virtctl を使えば解決します。サーバーが v1.9.0 であっても、virtctl さえ新しければ問題ありません。

3. 同時マイグレーションの制限

cirros VM 6 台を 1 つのノードに集めた後、VMIM 6 個を同時に作成しました。KubeVirt CR の parallelOutboundMigrationsPerNode のみを変更し、クラスターの制限(parallelMigrationsPerCluster: 5)はそのままにしました。

ノードあたりの制限 6 台すべてが完了するまで 同時に Running の最大数 1 件あたりの Running → Succeeded
1 33.9 秒 1 2~6 秒
2(デフォルト) 22.3 秒 2 3~4 秒
4 23.2 秒 4 8~9 秒

制限を 2 から 4 に増やしても速くなりませんでした。1 つのノードが送信できる帯域(約 90MiB/s)を分け合うため、1 件あたりの処理がその分遅くなります。小さな VM が多数ある場合は 1 から 2 に増やすときのメリット(34 秒 → 22 秒)が大きいですが、それ以上は 回線が上限になります。

マイグレーション専用ネットワーク(spec.configuration.migrations.network)は測定できませんでした(未計測)。ネストされたノードに NIC が 2 つしかなく、Multus がないため別ネットワークを作成できませんでした。この構成では、マイグレーション、NFS ディスク、サービス トラフィックのすべてが約 800Mbps の回線を共有しました。本番環境で VM が大きい場合や数が多い場合は、専用ネットワークの用意が先であり、制限の調整はその次です。

# KubeVirt CR 의 일부. 비워 두면 위 기본값(클러스터 5, 노드당 2, 대역폭 무제한)
spec:
  configuration:
    migrations:
      parallelMigrationsPerCluster: 5
      parallelOutboundMigrationsPerNode: 2

4. 本測定の限界

数値を参考にする前に条件をご確認ください。

5. まとめ:ライブ マイグレーションを信頼する前に

チェック項目 理由(第 1・2 回の実測値)
ディスクが RWX、ネットワークが masquerade ではない場合、Webhook が VMIM の作成時点ですべて拒否する
CPU モデルをノード間で共通の名称モデルにする host-model は True と表示されても 5 分後に失敗する
負荷の高い VM に autoConverge を適用する デフォルトでは 128MB の書き込みでも 300 秒後に断念するが、autoConverge なら 33~43 秒で完了する
postCopy を使用するにはノードの sysctl の設定から行う 設定がないと 1~2 秒で失敗する
帯域幅の制限は実際の転送量で確認する 32Mi に設定したのに 75MiB/s が出た
移動できない VM には evictionStrategy None を設定する LiveMigrate のままだと drain が終わらない
受信側ノードのメモリの空き容量 98% だと 5 分ごとに失敗と再試行を繰り返す
v1.9.1 以降の virtctl uncordon 後も残る退去表示を消去するには
クライアントの再接続 サービスの断絶時間はゲストの停止時間より何倍も長い

実際に試してみたい場合は、TT Lab のハンズオンコース「KubeVirt ライブ マイグレーション」(サイトパス /course/kubevirt-live-migration)が、本測定と同じ VM セットおよび同じバージョンで用意されています。共通 CPU モデルの選択から、移行と停止時間の読み取り、RWO 拒否の確認、drain まで全 8 ステップです。

ティーティーの一言。 荷造りをしている最中に部屋を散らかし続ける友達がいると、引っ越しはいつまで経っても終わりません。そんなときは、その友達の作業をゆっくり優しく(autoConverge)してあげれば 30 秒で終わります。そして、引っ越しをキャンセルしたからといって終わりではありません。ドアに貼った「引っ越し中」のメモ(evacuationNodeName)を剥がさないと、荷物が勝手に外に出ていってしまいますよ!

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

コメント

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

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