復原 OpenStack 中被刪除的 instance

上週五在測試 puppet 全自動安裝 Openstack compute,大概是 class dependency 沒有設好的原因,總之 puppet 在安裝 compute 時總是會漏掉許多設定值。因此,我不斷地做 install/uninstall 來做測試。

Unstall 時已經很習慣用 apt-get –purge install nova-* quantum-* 。原本這行指令並沒有甚麼問題,但在於實驗的cloud環境,將 /var/lib/nova/instance 用 ceph 分享給所有 compute。

所以…悲劇發生了,所有 running 中 VM 的 instance 都被我刪除了。這個問題整個周末都沒有發現,是昨天上班時,我問效維新安裝的伺服器是否有發生狀況,這時我們才發現了這個大問題。

所幸,Linux 有個保護機制,當一個 file 被某些 process 佔用時,如果將該檔案刪除,此時系統只會將檔案 mark 為 (deleted)。 這樣一來其他 process、user 是讀取不到該檔案,但是該檔案還是繼續存在於 file system 中,直到那些所佔用 process 都結束了,這些 file 才會消失。

回到正題,cloud 上的 VM instance 被刪除會發生甚麼狀況呢?

萬一整個 cloud 上所有 user 的資料都消失了,那我想我應該會被罵到死吧= =

萬幸的是我終於找到方法了

Solution

第一步

先登入到 physical machine 中,使用 virsh 指令查看還有哪些 VM 是 running :

root@local# virsh list --all
 Id    Name                           State
----------------------------------------------------
 16    instance-000002d3              running
 38    instance-0000006c              running
 39    instance-00000008              running
 -     instance-0000029d              shut off
 -     instance-000002a6              shut off
 -     instance-000002c6              shut off

以上述為例,目前還有3個 VM 是 running 中,此時我們必須要先將 VM 暫停:

root@local# virsh suspend 16
root@local# virsh suspend 38
root@local# virsh suspend 39

之後 VM 的狀態就會從 running 變成 paused :

root@local# virsh list --all
 Id    Name                           State
----------------------------------------------------
 16    instance-000002d3              paused
 38    instance-0000006c              paused
 39    instance-00000008              paused
 -     instance-0000029d              shut off
 -     instance-000002a6              shut off
 -     instance-000002c6              shut off

第二步

找到 VM 的 process id:

root@local# ps aux |grep 'instance-000002d3'
root     22430  0.0  0.0   9388   940 pts/1    S+   09:12   0:00 grep --color=auto 2d3
107      25534 12.9  5.9 13075024 1474148 ?    Sl   Sep17 6469:57 /usr/bin/kvm -name instance-000002d3 -S ...(以下省略)...

從上述中的例子我們可以看到,instance-000002d3 的 process id 為 25534。根據 process id,切換當前目錄到 /proc/$processid/fd,此時就可以看到此 process 佔用了那些檔案:

root@local# cd /proc/25534/fd
root@local# ls -l
total 0
dr-x------ 2 libvirt-qemu kvm  0 Oct 21 21:08 .
dr-xr-xr-x 9 libvirt-qemu kvm  0 Sep 17 16:30 ..
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 0 -> /dev/null
l-wx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 1 -> /var/log/libvirt/qemu/instance-000002d3.log
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 10 -> anon_inode:[eventfd]
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 11 -> /var/lib/nova/instances/19664c67-5831-4ebe-a1e5-1cb808ec2d81/disk (deleted)
lr-x------ 1 libvirt-qemu kvm 64 Oct 21 21:08 12 -> pipe:[73026899]
l-wx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 13 -> pipe:[73026899]
lr-x------ 1 libvirt-qemu kvm 64 Oct 21 21:08 14 -> /var/lib/nova/instances/_base/05a559eb870ea8c8e3142a7269f2c1dd8bd69321 (deleted)
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 15 -> anon_inode:kvm-vcpu
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 16 -> anon_inode:kvm-vcpu
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 17 -> anon_inode:kvm-vcpu
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 18 -> anon_inode:kvm-vcpu
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 19 -> socket:[73019779]
l-wx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 2 -> /var/log/libvirt/qemu/instance-000002d3.log
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 20 -> anon_inode:[eventfd]
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 21 -> socket:[73019780]
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 24 -> /dev/net/tun
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 29 -> /dev/vhost-net
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 3 -> socket:[72970876]
l-wx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 4 -> /var/lib/nova/instances/19664c67-5831-4ebe-a1e5-1cb808ec2d81/console.log (deleted)
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 5 -> /dev/ptmx
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 6 -> /dev/kvm
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 7 -> anon_inode:kvm-vm
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 8 -> anon_inode:[signalfd]
lrwx------ 1 libvirt-qemu kvm 64 Oct 21 21:08 9 -> anon_inode:[eventfd]

第三步

在以上的範例中,<font color="red">11</font>這個檔案是 link 到 VM 的 instance (/var/lib/nova/instances/19664c67-5831-4ebe-a1e5-1cb808ec2d81/disk),而 <font color="red">14</font> 則是 link 到此 instance 的 backing_file (在 Openstack 上稱為 VM image)。此時,將 11、14、4 三個檔案複製到其他位置保存:

root@local# mkdir ~/backup/19664c67-5831-4ebe-a1e5-1cb808ec2d81 ~/backup/_base
root@local# cp 11 ~/backup/19664c67-5831-4ebe-a1e5-1cb808ec2d81/disk
root@local# cp 4 ~/backup/19664c67-5831-4ebe-a1e5-1cb808ec2d81/console.log
root@local# cp 14 ~/backup/_base/05a559eb870ea8c8e3142a7269f2c1dd8bd69321

重複以上的步驟直到所有 VM 的 instances、base image 都備份完成

一般來說,一個 base image 會開出很多的 VM instance。因此相同的 base image 只要 copy 一份即可

第四步

完成備份之後,將所有的 VM 關機 (這個步驟一定要用 virsh 指令,不可以使用 openstack dashboard):

root@local# virsh list --all
 Id    Name                           State
----------------------------------------------------
 16    instance-000002d3              paused
 38    instance-0000006c              paused
 39    instance-00000008              paused
 -     instance-0000029d              shut off
 -     instance-000002a6              shut off
 -     instance-000002c6              shut off

root@local# virsh destroy 16
Domain 16 destroyed

root@local# virsh destroy 38
Domain 38 destroyed

root@local# virsh destroy 39
Domain 39 destroyed

root@local# virsh list --all
 Id    Name                           State
----------------------------------------------------
 -     instance-0000029d              shut off
 -     instance-000002a6              shut off
 -     instance-000002c6              shut off
 -     instance-000002d3              shut off
 -     instance-0000006c              shut off
 -     instance-00000008              shut off

第五步

將每一台 VM 關機之後,再將備份好的檔案全部寫回去:

root@local# cp -R ~/backup/* /var/lib/nova/instances/

確認一下 base image 與 VM instance 都否都存在:

  1. /var/lib/nova/instances/_base/$(Base image)
  2. /var/lib/nova/instances/$(VM UUID)/disk
  3. /var/lib/nova/instances/$(VM UUID)/console.log

修改檔案的擁有者、群組以及存取權限:

完成之後,就可以在 Openstack Dashboard 上 hardware reboot VM 。