---
# System prepended metadata

title: VMware migrate to Harvester
tags: [工具]

---

# 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
```