# VMware migrate to Harvester 透過 VM Import 的功能,使用 vm-import-controller 插件,使用者可以將 VMware 和 OpenStack 中的虛擬機器匯入到 Harvester 中。 ## Harvester VM Import 啟用 vm-import-controller 功能 ![image](https://hackmd.io/_uploads/rJdio-3Zbx.png) 在遷移過程中,大型虛擬機器的節點可能會耗盡此掛載點的空間,導致後續調度失敗。 為避免這種情況,建議使用者啟用 PVC 支援的儲存並自訂所需的儲存容量。最佳實踐是,PVC 的大小應該是待遷移虛擬機器中最大虛擬機器大小的兩倍。這一點至關重要,因為 PVC 用作臨時空間來下載虛擬機器並將磁碟轉換為原始鏡像檔案。 ![image](https://hackmd.io/_uploads/Hyp_ez2ZWe.png) > 這邊是設定 vm-import-controller 他自己要的 pvc 大小,這是遷移 vm 時會暫時儲存的地方 ``` hx-1:~ # kubectl -n harvester-system get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE harvester-vm-import-controller Bound pvc-a6ff1269-6b71-4e21-a9d4-83b6f26f60ba 200Gi RWO new-sc <unset> 39s ``` ## 遷移目標 * 將在 VC 上的 ubuntu server、windows server 和一做 k8s 叢集都遷移至 harvester ![image](https://hackmd.io/_uploads/SkiP4rTZZl.png) * VSphere 相關資訊 - DC 名稱:Datacenter - VC FQDN:`vcbm.bbg.com` ![image](https://hackmd.io/_uploads/B1eCGuQ2W-g.png) ## 開始遷移 ### 遷移前準備 * 需確認 harvester 與 VC 網路是互通的 ``` hx-1:~ # ping -c 1 vcbm.bbg.com PING vcbm.bbg.com (172.20.0.10) 56(84) bytes of data. 64 bytes from 172.20.0.10 (172.20.0.10): icmp_seq=1 ttl=64 time=0.696 ms --- vcbm.bbg.com ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.696/0.696/0.696/0.000 ms ``` * 先把要遷移的 vm 都關機 ![image](https://hackmd.io/_uploads/HJQOVrTZZx.png) ### 在 harvester 設定 vmware 資訊 ``` $ vim vmsource.yaml apiVersion: migration.harvesterhci.io/v1beta1 kind: VmwareSource metadata: name: vcsim namespace: default spec: # 設定 VC 位置 endpoint: "https://vcbm.bbg.com/sdk" # 選擇要遷移 VM 所在的 datacenter 名稱 dc: "Datacenter" credentials: name: vsphere-credentials namespace: default --- apiVersion: v1 kind: Secret metadata: name: vsphere-credentials namespace: default stringData: "username": "<VC username>" "password": "<VC password>" ``` ``` $ kubectl apply -f vmsource.yaml ``` * 部署後確認狀態是否 ready,代表可以開始遷移 vm ``` $ kubectl get vmwaresource.migration NAME STATUS vcsim clusterReady ``` ### 遷移 ubuntu linux vm * ubuntu 規格: - 4 core cpu - 8g RAM - 使用兩顆 30g 硬碟 - 網路介面名稱:Internal VM Network ![image](https://hackmd.io/_uploads/ryy6ZX2-Wg.png) * ubuntu 遷移前可以先設定固定網卡名稱,可以[參考](https://hackmd.io/@wu-andy/ry11wzTW-e) * 定義要 import ubuntu 的 yaml 資訊 ``` $ vim vmimport-ub.yaml apiVersion: migration.harvesterhci.io/v1beta1 kind: VirtualMachineImport metadata: name: ubuntu-test-import namespace: default spec: # vmware 上的 vm 名稱 virtualMachineName: "ubuntu-test" networkMapping: # vmware 上的 vm 所使用的網路介面 - sourceNetwork: "Internal VM Network" # 這邊要改成在 Harvester 上實際建立的網路名稱 destinationNetwork: "default/bridge" sourceCluster: name: vcsim namespace: default kind: VmwareSource apiVersion: migration.harvesterhci.io/v1beta1 ``` > 注意:遷移的 vm 名稱中不能有 `.` 和空格 ``` $ kubectl apply -f vmimport-ub.yaml ``` * 部署後看到狀態是 ready,此時會開始遷移 vm,這會需要一段時間 ``` $ kubectl get virtualmachineimport.migration NAME STATUS ubuntu-test-import sourceReady ``` * 可以檢查遷移 vm 時的 log ``` $ kubectl -n harvester-system logs harvester-vm-import-controller-bdd8c546d-gtz4f ...... time="2025-12-02T08:18:38Z" level=info msg="Shutting down guest OS of the source VM" name=ubuntu-test-import namespace=default spec.gracefulShutdownTimeoutSeconds=60 spec.sourceCluster.kind=VmwareSource spec.sourceCluster.name=vcsim spec.virtualMachineName=ubuntu-test time="2025-12-02T08:18:39Z" level=info msg="Importing client disk images ..." name=ubuntu-test-import namespace=default spec.virtualMachineName=ubuntu-test time="2025-12-02T08:18:39Z" level=info msg="Importing client disk images ..." name=ubuntu-test-import namespace=default spec.virtualMachineName=ubuntu-test time="2025-12-02T08:18:39Z" level=info msg="Exporting source VM" name=ubuntu-test-import namespace=default spec.sourceCluster.kind=VmwareSource spec.sourceCluster.name=vcsim spec.virtualMachineName=ubuntu-test time="2025-12-02T08:18:39Z" level=info msg="Origin spec of the volumes to be imported" name=ubuntu-test-import namespace=default spec="[{\"deviceId\":\"/vm-35/ParaVirtualSCSIController0:0\",\"path\":\"disk-0.vmdk\",\"size\":64424509440,\"cimType\":0,\"create\":false,\"URL\":{\"Scheme\":\"https\",\"Opaque\":\"\",\"User\":null,\"Host\":\"10.10.7.3\",\"Path\":\"/nfc/528911aa-344b-88ef-45d7-5096e6125187/disk-0.vmdk\",\"RawPath\":\"\",\"OmitHost\":false,\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"}},{\"deviceId\":\"/vm-35/ParaVirtualSCSIController0:1\",\"path\":\"disk-1.vmdk\",\"size\":64424509440,\"cimType\":0,\"create\":false,\"URL\":{\"Scheme\":\"https\",\"Opaque\":\"\",\"User\":null,\"Host\":\"10.10.7.3\",\"Path\":\"/nfc/528911aa-344b-88ef-45d7-5096e6125187/disk-1.vmdk\",\"RawPath\":\"\",\"OmitHost\":false,\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"}},{\"deviceId\":\"/vm-35/nvram\",\"path\":\"disk-2.nvram\",\"size\":270840,\"cimType\":0,\"create\":false,\"URL\":{\"Scheme\":\"https\",\"Opaque\":\"\",\"User\":null,\"Host\":\"10.10.7.3\",\"Path\":\"/nfc/528911aa-344b-88ef-45d7-5096e6125187/disk-2.nvram\",\"RawPath\":\"\",\"OmitHost\":false,\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"}}]" time="2025-12-02T08:18:39Z" level=info msg="Downloading an image" busType=sata deviceId="/vm-35/ParaVirtualSCSIController0:0" name=ubuntu-test-import namespace=default path=ubuntu-test-import-default-disk-0.vmdk size=64424509440 spec.sourceCluster.kind=VmwareSource spec.sourceCluster.name=vcsim spec.virtualMachineName=ubuntu-test ``` * 遷移完成後會自動將 vm 開機 ``` $ kubectl get virtualmachineimport.migration NAME STATUS ubuntu-test-import virtualMachineRunning ``` ![image](https://hackmd.io/_uploads/B1ZdBm2WZe.png) * 並且產生了兩顆對應的硬碟 ![image](https://hackmd.io/_uploads/r1xBrX3ZWx.png) * 如果沒有固定網卡名稱,遷移後 guset os 網卡名稱有變動需要再手動修改 ![image](https://hackmd.io/_uploads/SJwiNQ3bbe.png) ### 遷移 windows server vm * windows server 規格: - 8 core cpu - 16g RAM - 使用一顆 50g 硬碟 - 網路介面名稱:Internal VM Network ![image](https://hackmd.io/_uploads/SkEru7n-We.png) * windows 遷移前可以先安裝 virtio,這樣在遷移後才看得到網卡名稱,可以[參考](https://hackmd.io/@wu-andy/BJQOqMpZWl) * 定義要 import windows server 的 yaml 資訊 ``` $ vim vmimport-win.yaml apiVersion: migration.harvesterhci.io/v1beta1 kind: VirtualMachineImport metadata: name: windows-server-test-import namespace: default spec: # vmware 上的 vm 名稱 virtualMachineName: "windows-server-2025-test" networkMapping: # vmware 上的 vm 所使用的網路介面 - sourceNetwork: "Internal VM Network" # 這邊要改成在 Harvester 上實際建立的網路名稱 destinationNetwork: "default/bridge" sourceCluster: name: vcsim namespace: default kind: VmwareSource apiVersion: migration.harvesterhci.io/v1beta1 ``` > 注意:遷移的 vm 名稱中不能有 `.` 和空格 ``` $ kubectl apply -f vmimport-win.yaml ``` * 檢視遷移狀態 ``` $ kubectl get virtualmachineimport.migration NAME STATUS ubuntu-test-import virtualMachineRunning windows-server-test-import sourceRead ``` * 遷移完畢 ``` $ kubectl get virtualmachineimport.migration NAME STATUS ubuntu-test-import virtualMachineRunning windows-server-test-import virtualMachineRunning ``` ![image](https://hackmd.io/_uploads/r1K_JVhbZx.png) * 並且產生了對應的硬碟 ![image](https://hackmd.io/_uploads/ryhF1N3bbe.png) * 登入 windows server ![image](https://hackmd.io/_uploads/S1c_LVhZ-l.png) ### 遷移 K8s 叢集 * 定義要 import vm 的 yaml 資訊 ``` $ vim vmimport-k8s-m1.yaml apiVersion: migration.harvesterhci.io/v1beta1 kind: VirtualMachineImport metadata: name: k8s-m1-import namespace: default spec: # vmware 上的 vm 名稱 virtualMachineName: "k8s-m1" networkMapping: # vmware 上的 vm 所使用的網路介面 - sourceNetwork: "Internal VM Network" # 這邊要改成在 Harvester 上實際建立的網路名稱 destinationNetwork: "default/bridge" sourceCluster: name: vcsim namespace: default kind: VmwareSource apiVersion: migration.harvesterhci.io/v1beta1 ``` ``` $ vim vmimport-k8s-w1.yaml apiVersion: migration.harvesterhci.io/v1beta1 kind: VirtualMachineImport metadata: name: k8s-w1-import namespace: default spec: # vmware 上的 vm 名稱 virtualMachineName: "k8s-w1" networkMapping: # vmware 上的 vm 所使用的網路介面 - sourceNetwork: "Internal VM Network" # 這邊要改成在 Harvester 上實際建立的網路名稱 destinationNetwork: "default/bridge" sourceCluster: name: vcsim namespace: default kind: VmwareSource apiVersion: migration.harvesterhci.io/v1beta1 ``` > 注意:遷移的 vm 名稱中不能有 `.` 和空格 ``` $ kubectl apply -f vmimport-k8s-m1.yaml $ kubectl apply -f vmimport-k8s-w1.yaml ``` * 如果同時遷移,harvester 會批次作業 ``` $ kubectl get virtualmachineimport.migration NAME STATUS k8s-m1-import sourceReady k8s-w1-import ubuntu-test-import virtualMachineRunning windows-server-test-import virtualMachineRunning ``` * 遷移完成 ``` $ kubectl get virtualmachineimport.migration NAME STATUS k8s-m1-import virtualMachineRunning k8s-w1-import virtualMachineRunning ubuntu-test-import virtualMachineRunning windows-server-test-import virtualMachineRunning ``` ![image](https://hackmd.io/_uploads/SJCJ_d6W-l.png) * 確認遷移後 K8s 狀態是正常的 ``` bigred@m1:~$ kubectl get no NAME STATUS ROLES AGE VERSION m1 Ready control-plane 5h15m v1.34.1 w1 Ready <none> 5h15m v1.34.1 bigred@m1:~$ kubectl get po -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-548476666b-mtmp9 1/1 Running 1 3h38m kube-system calico-node-7kkwf 1/1 Running 1 5h14m kube-system calico-node-tmvrv 1/1 Running 0 3h38m kube-system coredns-66bc5c9577-6gmc5 1/1 Running 1 3h38m kube-system coredns-66bc5c9577-kmjz4 1/1 Running 1 3h38m kube-system etcd-m1 1/1 Running 1 5h15m kube-system kube-apiserver-m1 1/1 Running 1 5h15m kube-system kube-controller-manager-m1 1/1 Running 1 5h15m kube-system kube-proxy-csrk9 1/1 Running 1 5h15m kube-system kube-proxy-thgjm 1/1 Running 0 3h38m kube-system kube-scheduler-m1 1/1 Running 1 5h15m ```