1. 程式人生 > >經典KVM詳解,太詳細太深入了

經典KVM詳解,太詳細太深入了

 學習 KVM 的系列文章:

1. QEMU/KVM 遷移的概念

     遷移(migration)包括系統整體的遷移和某個工作負載的遷移。系統整理遷移,是將系統上所有軟體包括作業系統完全複製到另一個物理機硬體機器上。虛擬化環境中的遷移,可分為靜態遷移(static migration,或者 冷遷移 cold migration,或者離線遷移 offline migration) 和 動態遷移 (live migration,或者 熱遷移 hot migration 或者 線上遷移 online migration)。靜態遷移和動態遷移的最大區別是,靜態遷移有明顯一段時間客戶機中的服務不可用,而動態遷移則沒有明顯的服務暫停時間。

    虛擬化環境中的靜態遷移也可以分為兩種,一種是關閉客戶機後,將其硬碟映象複製到另一臺宿主機上然後恢復啟動起來,這種遷移不能保留客戶機中執行的工作負載;另一種是兩臺宿主機共享儲存系統,這時候的遷移可以保持客戶機遷移前的記憶體狀態和系統執行的工作負載。

    動態遷移,是指在保證客戶機上應用服務正常執行的同時,讓客戶機在不同的宿主機之間進行遷移,其邏輯步驟和前面的靜態遷移幾乎一直,有硬碟儲存和記憶體都複製的動態遷移,也有僅複製記憶體映象的動態遷移。不同的是,為了保證遷移過程中客戶機服務的可用性,遷移過程只能有非常短暫的停機時間。動態遷移允許系統管理員將客戶機在不同物理機上遷移,同時不會斷開訪問客戶機中服務的客戶端或者應用程式的連線。一個成功的遷移,需要保證客戶機的記憶體、硬碟儲存和網路連線在遷移到目的主機後任然保持不變,而且遷移的過程的服務暫停時間較短。

1.1 遷移效率的衡量

(1)整體遷移時間

(2)伺服器停機時間:這時間是指源主機上的客戶機已經暫停服務,而目的主機上客戶機尚未恢復服務的時間。

(3)對服務效能的影響:客戶機遷移前後效能的影響,以及目的主機上其它服務的效能影響。

  其中,整體遷移時間受很多因素的影響,比如 Hypervisor 和遷移工具的種類、磁碟儲存的大小(是否需要複製磁碟映象)、記憶體大小及使用率、CPU 的效能和利用率、網路頻寬大小及是否擁塞等,整體遷移時間一般分為幾秒鐘到幾十分鐘不等。動態遷移的服務停機時間,也有這些因素的影響,往往在幾毫秒到幾百毫秒。而靜態遷移,其暫停時間較長。因此,靜態遷移一般適合於對服務可用性要求不高的場景,而動態遷移適合於對可用性要求高的場景。

動態遷移的應用場景包括:負載均衡、解除硬體依賴、節約能源 和異地遷移。

1.2 KVM 遷移的原理

1.2.1 靜態遷移

    對於靜態遷移,你可以在宿主機上某客戶機的 QEMU monitor 中,用 savevm my_tag 命令儲存一個完整的客戶機映象快照,然後在宿主機中關閉或者暫停該客戶機,然後將該客戶機的映象檔案複製到另一臺宿主機中,使用在源主機中啟動該客戶機時的命令來啟動複製過來的映象,在其 QEMU monitor 中 loadvm my_tag 命令恢復剛才儲存的快照即可完全載入儲存快照時的客戶機狀態。savevm 命令可以保證完整的客戶機狀態,包括 CPU 狀態、記憶體、裝置狀態、科協磁碟中的記憶體等。注意,這種方式需要 qcow2、qed 等格式的磁碟映象檔案的支援。

1.2.2 動態遷移

    如果源宿主機和目的宿主機共享儲存系統,則只需要通過網路傳送客戶機的 vCPU 執行狀態、記憶體中的內容、虛機裝置的狀態到目的主機上。否則,還需要將客戶機的磁碟儲存發到目的主機上。共享儲存系統指的是源和目的虛機的映象檔案目錄是在一個共享的儲存上的。

    在基於共享儲存系統時,KVM 動態遷移的具體過程為:

  1. 遷移開始時,客戶機依然在宿主機上執行,與此同時,客戶機的記憶體頁被傳輸到目的主機上。
  2. QEMU/KVM 會監控並記錄下遷移過程中所有已被傳輸的記憶體頁的任何修改,並在所有記憶體頁都傳輸完成後即開始傳輸在前面過程中記憶體頁的更改內容。
  3. QEMU/KVM 會估計遷移過程中的傳輸速度,當剩餘的記憶體資料量能夠在一個可以設定的時間週期(預設 30 毫秒)內傳輸完成時,QEMU/KVM 會關閉源宿主機上的客戶機,再將剩餘的資料量傳輸到目的主機上,最後傳輸過來的記憶體內容在目的宿主機上恢復客戶機的執行狀態。
  4. 至此,KVM 的動態遷移操作就完成了。遷移後的客戶機儘可能與遷移前一直,除非目的主機上缺少一些配置,比如網橋等。

注意,當客戶機中記憶體使用率非常大而且修改頻繁時,記憶體中資料不斷被修改的速度大於KVM能夠傳輸的記憶體速度時,動態遷移的過程是完成不了的,這時候只能靜態遷移。

1.3 使用命令列的方式做動態遷移

1.3.1 使用 NFS 共享儲存

(1)在源宿主機上掛載 NFS 上的客戶機映象,並啟動客戶機

mount my-nfs:/raw-images/ /mnt/ kvm /mnt/rh1.img -smp 2 -m 2048 -net nic -net tap

(2)在目的宿主機上也掛載映象目錄,並啟動一個客戶機用於接收動態遷移過來的記憶體內容

mount my-nfs:/raw-images/ /mnt/ kvm /mnt/rh1.img -smp 2 -m 2048 -net nic -net tap -incoming tcp:0:6666

注意:(1)NFS 掛載目錄必須一致 (2)“-incoming tcp:0:6666” 引數表示在 6666 埠建立一個 TCP socket 連線用於接收來自源主機的動態遷移的內容,其中 0 表示執行來自任何主機的連線。“-incoming“ 使 qemu-kvm 程序進入到監聽模式,而不是真正以命令列中的檔案執行客戶機。

(3)在源宿主機的客戶機的 QEMU monitor 中,使用命令 ” migrate tcp:host2:6666" 即可進入動態遷移的流程。

1.3.2 不使用共享儲存的動態遷移

過程類似,包括使用相同backing file 的映象的客戶機遷移,以及完全不同映象檔案的客戶機的遷移。唯一的區別是,migrate 命令中新增 “-b” 引數,它意味著傳輸塊裝置。

1.3.3 其它 QEMU monitor migrate 命令

  • migrate_cancel:取消遷移
  • migrate_set_speed:設定最大遷移速度,單位是 bytes
  • migrate_set_downtime:設定最大允許的服務暫停時間,單位是 秒
  • info migrate:顯示遷移進度

2. OpenStack Nova QEMU/KVM 例項動態遷移的環境配置

除了直接拷貝磁碟映象檔案的冷遷移,OpenStack 還支援下面幾種虛機熱遷移模式:

  • 不使用共享儲存時的塊實時遷移(Block live migration without shared storage)。這種模式不支援使用只讀裝置比如 CD-ROM 和 Config Drive。塊實時遷移不需要 nova compute 節點都使用共享儲存。它使用 TCP 來將虛機的映象檔案通過網路拷貝到目的主機上,因此和共享儲存式的實時遷移相比,這種方式需要更長的時間。而且在遷移過程中,主機的效能包括網路和 CPU 會下降。
  • 基於共享儲存的實時遷移 (Shared storage based live migration):兩個主機可以訪問共享的儲存。
  • 從卷啟動的虛機的實時遷移(Volume backed VM live migration)。這種遷移也是一種塊拷貝遷移。

實時遷移的過程並不複雜,複雜在於環境配置。

2.1 基礎環境配置

2.1.1 SSH 許可權配置

這種方式需要配置源(compute1)和目的主機(compute2)之間能夠通過 SSH 相互訪問,以確保能通過 TCP 拷貝檔案,已經可以通過 SSH 在目的主機建立目錄。

使用 nova 使用者在compute1 上執行操作:

複製程式碼
usermod -s /bin/bash nova
su nova
mkdir -p -m 700 .ssh

#建立 config 檔案如下
[email protected]:~/.ssh$ cat config
Host * StrictHostKeyChecking no
UserKnownHostsFile=/dev/null #產生 key
ssh-keygen -f id_rsa -b 1024 -P "" cat id_rsa.pub >> authorized_keys

#將 id_rsa id_rsa.pub 拷貝到 compute2 上面
cat id_rsa.pub >> authorized_keys
複製程式碼

使用 root 使用者在每個主機上進行操作:

[email protected]:/var/lib/nova/.ssh# chown -R nova:nova /var/lib/nova
[email protected]:/var/lib/nova/.ssh# chmod 700 /var/lib/nova/.ssh
[email protected]:/var/lib/nova/.ssh# chmod 600 /var/lib/nova/.ssh/authorized_keys

測試 SSH 無密碼訪問:

複製程式碼
[email protected]:~/.ssh$ ssh [email protected] ls
Warning: Permanently added 'compute2,192.168.1.29' (ECDSA) to the list of known hosts.
...

[email protected]:~/.ssh$ ssh [email protected] ls
Warning: Permanently added 'compute1,192.168.1.15' (ECDSA) to the list of known hosts.
...
複製程式碼

2.1.2 其它配置

 每個node 上的 DNS 或者 /etc/hosts,確保互聯互通。

2.2 Live migration 環境配置

2.2.1 libvirtd 配置

在 compute1 和 compute2 上做如下配置:

複製程式碼
->Edit /etc/libvirt/libvirtd.conf
listen_tls = 0 listen_tcp = 1 auth_tcp = “none” ->Edit /etc/init/libvirt-bin.conf env libvirtd_opts="-d -l" 
->Edit /etc/default/libvirt-bin

  # options passed to libvirtd, add "-l" to listen on tcp
  libvirtd_opts="-d -l"

->Restart libvirtd
service libvirt-bin restart

root     12088     1  2 07:48 ?        00:00:00 /usr/sbin/libvirtd -d -l
複製程式碼

做完上述操作後,可以使用如下命令來檢查是否設定正確:

複製程式碼
[email protected]:~# virsh -c qemu+tcp://compute1/system list  --all  Id    Name                           State ---------------------------------------------------- 4 instance-0000000d              running 5 instance-00000006 running -     instance-00000005 shut off

[email protected]:~# virsh -c qemu+tcp://compute2/system list  --all  Id    Name                           State ----------------------------------------------------
複製程式碼

Nova 設定:

->Edit /etc/nova/nova.conf, add following line:  
  [libvirt]
  block_migration_flag = VIR_MIGRATE_UNDEFINE_SOURCE,VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE,VIR_MIGRATE_TUNNELLED,VIR_MIGRATE_NON_SHARED_INC
  live_migration_flag = VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE,VIR_MIGRATE_TUNNELLED
  live_migration_uri = qemu+tcp://%s/system

2.2.2 共享儲存 Live migration 環境配置

其實共享儲存的實時遷移配置的要求和塊拷貝的實時遷移的配置差不多,除了下面幾點:

  1. Hypervisor 要求:目前只有部分 Hypervisor 支援 live migraiton,可查詢該表
  2. 共享儲存:存放虛機檔案的資料夾 NOVA-INST-DIR/instances/ (比如 /var/lib/nova/instances,該路徑可以由 state_path 配置變數來配置) 必須是掛載到共享儲存上的。當Nova 使用 RBD 作為映象的backend時,這個要求不是必須的,具體見下面的說明。
  3. 必須在 nova.conf 中配置 vncserver_listen=0.0.0.0 (關於這個,社群認為這個配置具有安全風險,會通過這個 ticket 來解決)
  4. 不使用預設配置的話,必須在每個 nova compute 上的 nova.conf 中配置相同的 instances_path 和 state_path 。
  5. 在 Kilo 版本之前,Nova 是預設不支援 live migriation 的。在做實時遷移之前,需要在 nova.conf 中做如下配置
live_migration_flag=VIR_MIGRATE_UNDEFINE_SOURCE,VIR_MIGRATE_PEER2PEER,VIR_MIGRATE_LIVE,VIR_MIGRATE_TUNNELLED

注意:對於上面第二點,在 Kilo 版本中(前面版本的情況未知),當 Nova 使用 RBD 作為 image backend 時,Nova 會認為是在共享儲存上:

def check_instance_shared_storage_local(self, context, instance): """Check if instance files located on shared storage."""  if self.image_backend.backend().is_shared_block_storage(): return None

在 class Rbd(Image): 類中:

 @staticmethod
    def is_shared_block_storage():
        """True if the backend puts images on a shared block storage.""" return True

目前,只有 RBD 作為 image backend 時,該函式才返回 true。對於其它型別的 backend,Nova 會在目的 host 上的 instance folder 建立一個臨時檔案,再在源 host 上檢視該檔案,通過判斷是否該檔案在共享儲存上來判斷是否在使用共享儲存。

常見問題:

(1)在源 host 上,出現  ”live Migration failure: operation failed: Failed to connect to remote libvirt URI qemu+tcp://compute2/system: unable to connect to server at 'compute2:16509': Connection refused“

其原因是 2.1.1 部分的 libvirt 設定不正確。

(2)在目的 host 上,出現 ”libvirtError: internal error: process exited while connecting to monitor: 2015-09-21T14:17:31.840109Z qemu-system-x86_64: -drive file=rbd:vms/6bef8898-85f9-429d-9250-9291a2e4e5ac_disk:id=cinder:key=AQDaoPpVEDJZHhAAu8fuMR/OxHUV90Fm1MhONQ==:auth_supported=cephx\;none:mon_host=9.115.251.194\:6789\;9.115.251.195\:6789\;9.115.251.218\:6789,if=none,id=drive-virtio-disk0,format=raw,cache=writeback,discard=unmap: could not open disk image rbd:vms/6bef8898-85f9-429d-9250-9291a2e4e5ac_disk:id=cinder:key=AQDaoPpVEDJZHhAAu8fuMR/OxHUV90Fm1MhONQ==:auth_supported=cephx\;none:mon_host=9.115.251.194\:6789\;9.115.251.195\:6789\;9.115.251.218\:6789: Could not open 'rbd:vms/6bef8898-85f9-429d-9250-9291a2e4e5ac_disk:id=cinder:key=AQDaoPpVEDJZHhAAu8fuMR/OxHUV90Fm1MhONQ==:auth_supported=cephx\;none:mon_host=9.115.251.194\:6789\;9.115.251.195\:6789\;9.115.251.218\:6789': Operation not permitted“

原因:目的 host 上的使用者操作 RBD 的許可權設定不正確,檢查 secret 設定。

3. 遷移過程

3.0 Nova 有關遷移的命令

Nova 有三個與遷移有關的命令:migrate,live-migrate 和 resize。

Nova CLI REST API Action 行為
nova live-migration  --block-migrate  --disk_over_commit 8352e969-0a25-4abf-978f-d9d0ec4de0cd compute2 os-migrateLive 塊拷貝動態遷移
nova live-migration  8352e969-0a25-4abf-978f-d9d0ec4de0cd compute2 os-migrateLive 共享儲存動態遷移
nova migrate  8352e969-0a25-4abf-978f-d9d0ec4de0cd migrate 靜態遷移
nova resize --poll 8352e969-0a25-4abf-978f-d9d0ec4de0cd 1 resize 靜態遷移並且改變 flavor
nova resize --poll 8352e969-0a25-4abf-978f-d9d0ec4de0cd resize 靜態遷移
nova resize-confirm 9eee079e-0353-44cb-b76c-ecf9be61890d confirmResize 確認 resize 使得完整操作得以完成 
nova resize-revert 9eee079e-0353-44cb-b76c-ecf9be61890d revertResize 取消 resize 使得操作被取消虛機回到原始狀態 

3.1 靜態遷移(migrate 或者 resize 不使用新的 flavor)

複製程式碼
[email protected]:~$ nova migrate --poll 9eee079e-0353-44cb-b76c-ecf9be61890d

Server migrating... 100% complete
Finished
[email protected]:~$ nova list
+--------------------------------------+-------+---------------+------------+-------------+------------------------------------------+
| ID                                   | Name  | Status        | Task State | Power State | Networks                                 |
+--------------------------------------+-------+---------------+------------+-------------+------------------------------------------+
| 02699155-940f-4401-bc01-36220db80639 | vm10  | ACTIVE        | -          | Running     | demo-net2=10.0.10.17; demo-net=10.0.0.39 |
| 9eee079e-0353-44cb-b76c-ecf9be61890d | vm100 | VERIFY_RESIZE | -          | Running     | demo-net2=10.0.10.20                     |
+--------------------------------------+-------+---------------+------------+-------------+------------------------------------------+ [email protected]:~$ nova resize-confirm 9eee079e-0353-44cb-b76c-ecf9be61890d
[email protected]:~$ nova list
+--------------------------------------+-------+--------+------------+-------------+------------------------------------------+
| ID                                   | Name  | Status | Task State | Power State | Networks                                 |
+--------------------------------------+-------+--------+------------+-------------+------------------------------------------+
| 02699155-940f-4401-bc01-36220db80639 | vm10  | ACTIVE | -          | Running     | demo-net2=10.0.10.17; demo-net=10.0.0.39 |
| 9eee079e-0353-44cb-b76c-ecf9be61890d | vm100 | ACTIVE | -          | Running     | demo-net2=10.0.10.20                     |
+--------------------------------------+-------+--------+------------+-------------+------------------------------------------+
複製程式碼

3.1.1 遷移過程

 直接使用流程圖來說明:

1. migrate 和 resize 都是執行靜態遷移。

2. 靜態遷移分為三個階段:

(1)呼叫 Scheduler 演算法選擇目的 node(步驟5),並通過 RPC 遠端呼叫 prep_resize 做些遷移前的準備工作

(2)在源主機上,呼叫 libvirt driver 做一系列操作:

  1. 使用 ssh 在目的 node 上建立虛機的映象檔案的目錄
  2. 將虛機關機
  3. 斷開所有 volume connections
  4. 針對每一個非 swap 分割槽的磁碟,如果是 qcow2 格式,則執行 qemu-img merge 操作將稀疏檔案和backing 檔案合併成單個檔案,並通過 “rysnc” 或者 “scp”命令將檔案拷貝到目的 node 上
  5. 開始遷移需要的網路工作

(3)通過 RPC,呼叫目的 node 上的 Nova 的 finish_resize 方法。該方法會在自己本機上設定網路、結束網路設定工作,並呼叫 libvirt driver 來:

  1. 建立 image
  2. 獲取 guest xml
  3. 建立 domain 和 network
  4. 需要的話啟動虛機

至此,虛機已經被拷貝到目的主機上了。接下來,使用者有兩個選擇:resize_confirm 和 resize_revert。

3.1.2 確認遷移 (resize_confirm)

遷移確認後,在源主機上,虛機的檔案會被刪除,虛機被 undefine,虛機的 VIF 被從 OVS 上拔出,network filters 也會被刪除。

3.1.3 取消遷移 (resize_revert)

取消遷移的命令首先發到目的 node 上,依次 tear down network,刪除 domain,斷掉 volume connections,然後呼叫源主機上的方法來重建 network,刪除臨時檔案,啟動 domain。這樣,虛機就會需要到 resize 之前的狀態。

 3.2 實時遷移 (Live migration)

可以 Nova client 的 live-migration 命令來做實時遷移,除了要被遷移的 虛機 和 目的 node 外,它可以帶兩個額外的引數:

  • “block-migrate“:使用的話,做 block copy live migration;不使用的話,做共享儲存的 live migration;
  • ”disk_over_commit“:使用的話,計算所有磁碟的 disk_size 來計算目的 node 上所需空間的大小;不使用的話,則計算磁碟的 virtual size。在下面的例子中,如果使用 disk_over_commit,那麼計算在目的主機上需要的空間的時候,該 disk 的 size 為 324k,否則為 1G:
複製程式碼
[email protected]:/home/s1# qemu-img info /var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk.local
image: /var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk.local
file format: qcow2 virtual size: 1.0G (1073741824 bytes)
disk size: 324K
cluster_size: 65536 backing file: /var/lib/nova/instances/_base/ephemeral_1_default
Format specific information:
    compat: 1.1 lazy refcounts: false
複製程式碼

REST API request body 例項: {"os-migrateLive": {"disk_over_commit": false, "block_migration": true, "host": "compute2"}}

實時遷移的主要步驟如下:

其過程也可以分為三個階段:

3.2.1 實時遷移前的準備工作 (步驟 2 - 7)

Nova 通過 RPC 呼叫目的主機上 nova comute manager 的 pre_live_migration 方法,它依次:

(1)準備 instance 目錄:

      (1)建立 instance dir

(2)如果源和目的虛機不共享 instance path:獲取映象型別,為每一個disk,如果不使用 backing file 的話則呼叫 “qemu-img create” 方法來建立空的磁碟映象;否則,依次建立空的 Ephemeral disk 和 Swap disk,以及從  Glance 中獲取 image 來建立 Root disk

(3)如果不是 block migration 而且 不 is_shared_instance_path,則 _fetch_instance_kernel_ramdisk

(2)呼叫 volumer driver api 為每一個volume 建立目的主機和 volume 的連線

(3)呼叫 plug_vifs(instance, network_info) 將每一個 vif plug 到 OVS 上

(4)呼叫 network_api.setup_networks_on_host 方法,該方法會為遷移過來的虛機準備 dhcp 和 gateway;

(5)呼叫 libvirt driver 的 ensure_filtering_rules_for_instance 方法去準備 network filters。

3.2.2 呼叫 libvirt API 開始遷移虛機 (步驟 8 - 9)

  這部分的實現在 libvirt driver 程式碼中。因為 libvirt 的一個 bug (說明在這裡),當 libvirt 帶有 VIR_DOMAIN_XML_MIGRATABLE flag 時,Nova 會呼叫 libvirt 的 virDomainMigrateToURI2 API,否則呼叫 virDomainMigrateToURI API。

首先比較一下 block live migration 和 live migration 的 flags 的區別:

#nova block live migration flags:VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED, VIR_MIGRATE_NON_SHARED_INC #nova live migration flags:      VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED 

各自的含義如下:

  • VIR_MIGRATE_UNDEFINE_SOURCE: 遷移完成後,將源虛機刪除掉。(If the migration is successful, undefine the domain on the source host.)
  • VIR_MIGRATE_PEER2PEER 和 VIR_MIGRATE_TUNNELLED 一起使用:點對點遷移,必須指定目的 URI,QEMU在兩者之間建立 TCP Tunnel 用於資料傳輸
  • VIR_MIGRATE_LIVE: 執行 live migration,不要停機 (Do not pause the VM during migration)
  • VIR_MIGRATE_NON_SHARED_INC: 使用非共享儲存式遷移即 block migration (Migration with non-shared storage with incremental disk copy)

再看看兩個 API 的引數:

複製程式碼
int virDomainMigrateToURI2        (virDomainPtr domain, const char * dconnuri, # 格式為 qemu+tcp:///system const char * miguri, #為 none const char * dxml, #指定遷移後的虛機的 XML。Nova 對 “/devices/graphics” 部分做了一點點更改。 unsigned long flags, # nova.conf 中的配置 const char * dname, #none unsigned long bandwidth) # 由 CONF.libvirt.live_migration_bandwidth 指定,預設為 0 表示由 libvirt 自己選擇合適的值
複製程式碼

如果 libvirt 不帶 VIR_DOMAIN_XML_MIGRATABLE flag,則呼叫的 API 是:

int virDomainMigrateToURI        (virDomainPtr domain, const char * duri,
                     unsigned long flags, const char * dname,
                     unsigned long bandwidth)

可見,兩個 API 唯一的區別是不能指定新的虛機使用的 XML 配置。這時候你必須手動配置 VNC 或者 SPICE 地址為 0.0.0.0 or :: (接收全部)或者 127.0.0.1 or ::1 (只限本機)。

呼叫 API 後,接下來就是等待其完成。這其中的過程應該主要包括:

(1)根據傳入的 domain xml,啟動一個虛機,它處於等待 TCP incoming 狀態

(2)從源 node 上將 domain 的資料傳過來

(3)快完成時,關閉源 node 上的虛機,傳輸最後一次資料,開啟目的 node 上的虛機

(4)將源 node 上的虛機刪除

Nova 每個0.5 秒檢查源虛機的狀態,直到它被刪除。

遷移完成後,需要執行後續的操作(_post_live_migration)。

3.2.3 遷移完成後在源和目的主機上的後續操作(步驟 10 -29)

在源主機上,依次執行下面的操作:

  1. 呼叫 volume driver 的 disconnect_volume 方法和terminate_connection 方法,斷開主機和所有 volume 的連線
  2. 呼叫 firewall driver 的 unfilter_instance 方法,刪除 domain 的 iptables 中的所有 security group ingress 規則 (self.iptables.ipv4['filter'].remove_chain(chain_name))
  3. 呼叫 network api 的 migrate_instance_start 方法,開始將網路從源主機上遷移到目的主機上(實際上沒做什麼事情,只是 pass)
  4. 呼叫 vif driver 的 unplug 方法,將每個 vif 從 OVS 上刪除                                                                                                                                      
    brctl delif qbr59cfa0b8-2f qvb59cfa0b8-2f 
    ip link set qbr59cfa0b8-2f down 
    brctl delbr qbr59cfa0b8-2f 
    ovs-vsctl --timeout=120 -- --if-exists del-port br-int qvo59cfa0b8-2f 
    ip link delete qvo59cfa0b8-2f
  5. 通過 RPC 呼叫目的主機上的 nova manager 的 post_live_migration_at_destination 方法,該方法會:
    1. 呼叫 network api 的 setup_networks_on_host 方法來設定網路(處理 vpn,dhcp,gateway)
    2. 呼叫 network api 的 migrate_instance_finish 方法
    3. 呼叫 libvirt driver 的 post_live_migration_at_destination方法,它會呼叫 libvirt _conn.listDefinedDomains 方法檢視遷移過來的主機的 domain是否存在;不存在的話,生成其 xml,然後呼叫 libvirt API  _conn.defineXML(xml) 去定義該 domain。
    4. 將新的 domain 資料更新到資料庫(包括新的 host,power_state,vm_state,node)
    5. 呼叫 network api 的 setup_networks_on_host 方法 (不理解為什麼重複上面第1步)
  6. 呼叫 libvirt driver 的 driver.cleanup 方法去 _unplug_vifs (如果上面第四步失敗,則再次嘗試刪除所有 vif 相關的 bridge 和 OVS 連線),firewall_driver.unfilter_instance (和上面第2步重複了),_disconnect_volume(斷開 domain 和 所有 volume 的連線),_delete_instance_files (刪除 domain 相關的檔案),_undefine_domain (刪除 domain)
  7. 呼叫 network_api.setup_networks_on_host 去 tear down networks on source host
  8. 至此,live migration 完全結束。

3.2.4 遷移過程中失敗時的回滾

 遷移的三個步驟中,前面第一個和第二個步驟中出現失敗的話,會呼叫 _rollback_live_migration 啟動回滾操作。該方法

(1)將虛機的狀態由 migrating 變為 running。

(2)呼叫 network_api.setup_networks_on_host 方法重做源主機上的網路設定

(3)通過 RPC 呼叫,去目的主機上將準備過程中建立的 volume 連線刪除。

(4)通過 RPC 呼叫,去目的主機上呼叫 compute_rpcapi.rollback_live_migration_at_destination 函式,該方法會

(1)呼叫 network_api.setup_networks_on_host 方法去 tear down networks on destination host

(2)呼叫 libvirt driver 的 driver.rollback_live_migration_at_destination 方法,它會將 domain 刪除,並且清理它所使用的資源,包括  unplug vif,firewall_driver.unfilter_instance,_disconnect_volume, _delete_instance_files, _undefine_domain。

3.2.5 測試

環境:準備兩個虛機 vm1 和 vm2,作業系統為 cirros。打算將 vm1 遷移到另一個node 上。在 vm2 上檢視 vm1 在遷移過程中的狀態。

遷移前:在 vm1 中執行 “ping vm2”,並在 vm2 中 ssh 連線到 vm1。

結果:vm1 遷移過程中,vm2 上 ssh 的連線沒有中斷,vm1 中的 ping 命令繼續執行。在另一次測試結果中,vm2 ping vm1 在整個遷移過程中 time 出現了一次 2ms 的時間增加。

3.3 遇到過的問題

3.3.1 apparmor

將虛機從 compute1 遷移到 compute2 成功,再從 compute2 遷移到 compute1 失敗,報錯如下:

An error occurred trying to live migrate. Falling back to legacy live migrate flow. Error: unsupported configuration: Unable to find security driver for label apparmor