Skip to content

Forklift — 系統架構

1. 專案概述

Forklift(又稱 Migration Toolkit for Virtualization, MTV)是一套 Kubernetes Operator,用於將虛擬機器從多種虛擬化平台遷移至 KubeVirt 環境。它支援 vSphere、oVirt/RHV、OpenStack、Hyper-V、OVA 及 OCP-to-OCP 等遷移來源,並整合 CDI(Containerized Data Importer)完成磁碟資料搬移與 virt-v2v 完成 Guest OS 轉換。

項目說明
模組路徑github.com/kubev2v/forklift
語言版本Go 1.24.0
授權條款Apache License 2.0
架構模式Kubernetes Operator + Controller-Runtime
來源平台vSphere、oVirt、OpenStack、Hyper-V、OVA、OCP
目標平台KubeVirt(OpenShift Virtualization / 上游 KubeVirt)

關鍵依賴

依賴版本用途
github.com/vmware/govmomiv0.50.0vSphere API 互動(SOAP / REST)
github.com/ovirt/go-ovirtv0.0.0-20230808oVirt Engine SDK
github.com/gophercloud/gophercloudv1.14.1OpenStack API 客戶端
github.com/masterzen/winrmv0.0.0-20250927Hyper-V WinRM 遠端管理
kubevirt.io/apiv1.6.0-betaKubeVirt VirtualMachine CRD
kubevirt.io/containerized-data-importer-apiv1.63.1CDI DataVolume CRD
sigs.k8s.io/controller-runtimeOperator 框架
github.com/gin-gonic/ginv1.10.0REST API 路由(OVA Provider)

2. 系統架構圖

Forklift 系統架構圖

遷移管線流程

Forklift 遷移管線流程


3. Binary 與元件

Forklift 在 cmd/ 目錄下定義了 14 個入口點:

Binary說明關鍵細節
forklift-controller核心控制器,啟動 controller-runtime Manager註冊 6 個主控制器 + 3 個 Inventory 控制器;Metrics :2112,pprof :6060
forklift-apiREST API + Admission WebhooksServices 埠 8444、Webhooks 埠 8443;均啟用 TLS
virt-v2vGuest OS 轉換引擎支援遠端檢視、就地轉換、標準轉換三種模式;整合 virt-customize
virt-v2v-monitorvirt-v2v 進度監控解析 stdin 輸出,匯出 v2v_disk_transfers Prometheus 指標至 :2112
populator-controllerVolume Populator 總控制器管理 oVirt (:8080)、OpenStack (:8081)、vSphere XCOPY (:8082) 三種 Populator
ovirt-populatoroVirt 磁碟下載器呼叫 ovirt-img download-disk,匯出 ovirt_progress 指標
openstack-populatorOpenStack Image 下載器支援多種認證方式,匯出 openstack_populator_progress 指標
vsphere-copy-offload-populatorvSphere XCOPY 磁碟搬移支援 9 種企業儲存陣列(Ontap、PowerMax、PureFlashArray 等);TLS Metrics :8443
ova-provider-serverOVA Provider HTTP APIGin 框架;提供 Inventory 與 Appliance 端點;預設 catalog 路徑 /ova
ova-proxyOVA 反向代理透過 K8s Service Discovery 路由請求至對應 Provider Pod
hyperv-provider-serverHyper-V Provider HTTP 伺服器提供 /healthz/validate-disks 端點;埠 8080
image-converter磁碟映像格式轉換工具包裝 qemu-img convert;支援 Block / Filesystem 模式
kubectl-mtvkubectl CLI 外掛委派至 github.com/yaacov/kubectl-mtv/cmd
provider-common共用函式庫(非獨立 Binary)提供 Settings、OVF 解析、認證、Inventory API Handler

forklift-controller 註冊的控制器

go
// 檔案: pkg/controller/controller.go
// Main Controllers(MainRole)
migration.Add(mgr)  // Migration CR 調和
plan.Add(mgr)       // Plan CR 調和(核心遷移邏輯)
network.Add(mgr)    // NetworkMap CR 調和
storage.Add(mgr)    // StorageMap CR 調和
host.Add(mgr)       // Host CR 調和
hook.Add(mgr)       // Hook CR 調和

// Inventory Controllers(InventoryRole)
provider.Add(mgr)   // Provider CR 調和(vSphere/oVirt/OpenStack Inventory)
ova.Add(mgr)        // OVA Provider 控制器
hyperv.Add(mgr)     // Hyper-V Provider 控制器

forklift-api Webhook 路徑

go
// 檔案: pkg/forklift-api/webhooks/webhooks.go
// Validating Webhooks
"/secret-validate"    → SecretAdmitter
"/plan-validate"      → PlanAdmitter
"/provider-validate"  → ProviderAdmitter
"/migration-validate" → MigrationAdmitter

// Mutating Webhooks
"/secret-mutate"      → SecretMutator
"/plan-mutate"        → PlanMutator
"/provider-mutate"    → ProviderMutator

4. 目錄結構

Forklift 專案目錄結構


5. 建置系統

Makefile 關鍵 Target

Forklift 使用單一 Makefile 管理完整的建置、測試、映像打包與部署流程。

makefile
# 檔案: Makefile

# === CI / 測試 ===
ci:          all tidy vendor generate-verify lint validate-forklift-controller-crd
test:        generate fmt vet manifests validation-test  # 單元測試 + 覆蓋率
integration-test:                                        # envtest 整合測試
lint:                                                    # golangci-lint v1.64.2

# === E2E 測試(Ginkgo)===
e2e-sanity-ovirt:               # Focus: ".*oVirt.*|.*Forklift.*"
e2e-sanity-vsphere:             # Focus: ".*vSphere.*"
e2e-sanity-openstack:           # Focus: ".*Migration tests for OpenStack.*"
e2e-sanity-openstack-extended:  # 單執行緒擴充測試
e2e-sanity-ova:                 # Focus: ".*OVA.*"

# === 映像建置 ===
build-all-images:               # 建置所有 16 個容器映像
push-all-images:                # 推送所有映像至 Registry
push-all-images-manifest:       # 建立並推送 multi-arch manifest

# === 部署 ===
deploy-operator-index:          # 部署 OLM CatalogSource(單架構)
deploy-operator-index-multiarch: # 部署 OLM CatalogSource(多架構)
deploy-ocp:                     # 部署至 OpenShift
deploy-k8s:                     # 部署至 Kubernetes

多架構支援

makefile
# 檔案: Makefile
PLATFORM ?= linux/amd64          # 可切換 linux/arm64
PLATFORM_ARCH = amd64             # 自動從 PLATFORM 擷取
PLATFORM_SUFFIX = -amd64          # 附加至映像 Tag

# amd64-only 映像(依賴不支援 arm64):
#   virt-v2v, virt-v2v-xfs, ovirt-populator

映像建置採用 PLATFORM_FLAG --platform $(PLATFORM) 進行目標架構編譯,再透過 manifest create-amd64-arm64 映像合併為統一 manifest。

Container 映像總覽

makefile
# 檔案: Makefile
REGISTRY ?= quay.io
REGISTRY_ORG ?= kubev2v
REGISTRY_TAG ?= devel
# 組合:quay.io/kubev2v/<component>:devel-<arch>
映像架構基礎映像
forklift-controlleramd64, arm64UBI9-minimal
forklift-apiamd64, arm64UBI9-minimal
forklift-operatoramd64, arm64ansible-operator
forklift-validationamd64, arm64OPA + UBI9-minimal
forklift-virt-v2vamd64 onlyCentOS Stream 9
forklift-virt-v2v-xfsamd64 onlyCentOS Stream 9
populator-controlleramd64, arm64UBI9-minimal
ovirt-populatoramd64 onlyCentOS Stream 9
openstack-populatoramd64, arm64UBI9-minimal
vsphere-copy-offload-populatoramd64, arm64UBI9-minimal
ova-provider-serveramd64, arm64UBI9-minimal
ova-proxyamd64, arm64UBI9-minimal
hyperv-provider-serveramd64, arm64UBI9-minimal
forklift-cli-downloadamd64, arm64UBI9/nginx
forklift-operator-bundleamd64, arm64operator-sdk-builder
forklift-operator-indexamd64, arm64operator-framework/opm

6. Itinerary 狀態機

Itinerary 是 Forklift 遷移流程的核心架構模式,定義於 pkg/lib/itinerary/。每個遷移類型(Cold / Warm / Live)擁有獨立的 Itinerary,由一系列 Step 組成,搭配 Predicate 旗標在執行期動態篩選步驟。

核心結構

go
// 檔案: pkg/lib/itinerary/simple.go
type Step struct {
    Name string   // 步驟名稱(Phase 常數)
    All  Flag     // 所有旗標皆須滿足才納入此步驟
    Any  Flag     // 任一旗標滿足即納入此步驟
}

type Itinerary struct {
    Pipeline  // []Step — 有序步驟清單
    Predicate // 條件評估介面
    Name string
}

type Predicate interface {
    Evaluate(Flag) (bool, error)
    Count() int
}

執行流程:List() 方法遍歷 Pipeline,對每個 Step 先執行 hasAny() 再執行 hasAll(),僅保留通過篩選的步驟。Next(name) 依據目前 Phase 回傳下一個有效步驟。

Predicate 旗標

go
// 檔案: pkg/controller/plan/migrator/base/doc.go
HasPreHook              Flag = 0x01  // VM 定義了 PreHook
HasPostHook             Flag = 0x02  // VM 定義了 PostHook
RequiresConversion      Flag = 0x04  // Provider 需要 Guest OS 轉換且未跳過
CDIDiskCopy             Flag = 0x08  // 使用 CDI 複製磁碟
VirtV2vDiskCopy         Flag = 0x10  // 使用 virt-v2v 複製磁碟
OpenstackImageMigration Flag = 0x20  // OpenStack Snapshot 轉換
VSphere                 Flag = 0x40  // 來源為 vSphere
RunInspection           Flag = 0x80  // 執行 Preflight 檢視

Cold Migration(冷遷移)

VM 先關機再搬移磁碟,適用於所有來源平台。

go
// 檔案: pkg/controller/plan/migrator/base/migrator.go
Pipeline{
    {Name: PhaseStarted},
    {Name: PhasePreHook, All: HasPreHook},
    {Name: PhaseStorePowerState},
    {Name: PhasePowerOffSource},
    {Name: PhaseWaitForPowerOff},
    {Name: PhaseCreateDataVolumes},
    {Name: PhaseCopyDisks, All: CDIDiskCopy},
    {Name: PhaseAllocateDisks, All: VirtV2vDiskCopy},
    {Name: PhaseCreateGuestConversionPod, All: RequiresConversion},
    {Name: PhaseConvertGuest, All: RequiresConversion},
    {Name: PhaseCopyDisksVirtV2V, All: RequiresConversion},
    {Name: PhaseConvertOpenstackSnapshot, All: OpenstackImageMigration},
    {Name: PhaseCreateVM},
    {Name: PhasePostHook, All: HasPostHook},
    {Name: PhaseCompleted},
}

Cold Migration 狀態機

Warm Migration(暖遷移)

VM 持續運行,透過 Snapshot 增量複製磁碟(Precopy Loop),直到觸發 Cutover 才關機並完成最終同步。

go
// 檔案: pkg/controller/plan/migrator/base/migrator.go
Pipeline{
    {Name: PhaseStarted},
    {Name: PhasePreHook, All: HasPreHook},
    {Name: PhaseCreateInitialSnapshot},
    {Name: PhaseWaitForInitialSnapshot},
    {Name: PhaseStoreInitialSnapshotDeltas, All: VSphere},
    {Name: PhasePreflightInspection, All: RunInspection},
    {Name: PhaseCreateDataVolumes},
    // === Precopy Loop ===
    {Name: PhaseCopyDisks},
    {Name: PhaseCopyingPaused},
    {Name: PhaseRemovePreviousSnapshot, All: VSphere},
    {Name: PhaseWaitForPreviousSnapshotRemoval, All: VSphere},
    {Name: PhaseCreateSnapshot},
    {Name: PhaseWaitForSnapshot},
    {Name: PhaseStoreSnapshotDeltas, All: VSphere},
    {Name: PhaseAddCheckpoint},
    // === Cutover ===
    {Name: PhaseStorePowerState},
    {Name: PhasePowerOffSource},
    {Name: PhaseWaitForPowerOff},
    {Name: PhaseRemovePenultimateSnapshot, All: VSphere},
    {Name: PhaseWaitForPenultimateSnapshotRemoval, All: VSphere},
    {Name: PhaseCreateFinalSnapshot},
    {Name: PhaseWaitForFinalSnapshot},
    {Name: PhaseAddFinalCheckpoint},
    {Name: PhaseFinalize},
    {Name: PhaseRemoveFinalSnapshot, All: VSphere},
    {Name: PhaseWaitForFinalSnapshotRemoval, All: VSphere},
    {Name: PhaseCreateGuestConversionPod, All: RequiresConversion},
    {Name: PhaseConvertGuest, All: RequiresConversion},
    {Name: PhaseCreateVM},
    {Name: PhasePostHook, All: HasPostHook},
    {Name: PhaseCompleted},
}

Warm Migration 狀態機

Live Migration(OCP-to-OCP 即時遷移)

在來源與目標皆為 OpenShift 叢集時,VM 無需關機,透過 KubeVirt 的 Live Migration 機制直接遷移。

go
// 檔案: pkg/controller/plan/migrator/ocp/live.go
const (
    FlagPreHook      Flag = 0x01
    FlagPostHook     Flag = 0x02
    FlagSubmariner   Flag = 0x04  // 啟用 Submariner 多叢集網路
    FlagIntercluster Flag = 0x08  // 來源與目標為不同叢集
)

Pipeline{
    {Name: Started},
    {Name: PreHook, All: FlagPreHook},
    {Name: CreateSecrets},
    {Name: CreateConfigMaps},
    {Name: EnsurePreference},
    {Name: EnsureInstanceType},
    {Name: EnsureDataVolumes},
    {Name: EnsurePersistentVolumeClaims},
    {Name: CreateTarget},
    {Name: SetOwnerReferences},
    {Name: CreateServiceExports, All: FlagSubmariner | FlagIntercluster},
    {Name: WaitForTargetVMI},
    {Name: CreateVirtualMachineInstanceMigrations},
    {Name: WaitForStateTransfer},
    {Name: PostHook, All: FlagPostHook},
    {Name: Completed},
}

Live Migration 狀態機


相關章節

  • 核心功能分析 — 遷移流程、Provider 抽象層、磁碟轉換、演算法分析
  • 控制器與 API — Controller 架構、CRD 型別、Webhook、REST API
  • 外部整合 — KubeVirt / CDI / vSphere / oVirt / OpenStack / Hyper-V 整合

基於 Apache 2.0 授權