返回上一頁

將 Linux 系統備份為可開機的虛擬硬碟

以下介紹 Linux 備份方法
本指南目的為建立一個可以直接透過虛擬機開機的虛擬硬碟
請注意,僅能透過虛擬機直接開機,若要直接使用實體機開機可能無法或是要另外設定

事前準備與注意事項

首先你需要一顆額外的硬碟,使用此方法的一個前提是,你不能掛載來源硬碟
也就是說,你最少需要

  • 來源硬碟
  • LiveUSB 當作系統
  • 另一顆硬碟,外接或放在電腦裡面沒差

接著,你基本上需要使用 LiveUSB 開機
開機後,來源硬碟那顆不能掛載上來
而額外的那顆硬碟,本身請先格式化,例如 Brtfs 之類的
這些步驟完成後在往下

依賴套件安裝

首先,確認有安裝 qemu,沒有的話,使用以下指令安裝

sudo dnf install qemu

虛擬硬碟掛載相關

建立 QCOW2 映像檔(大小最小需大於等於來源磁碟)

使用以下命令建立虛擬硬碟

qemu-img create -f qcow2 test.qcow2 120G

image

參數:-f qcow2 指定格式為 QCOW2(支援快照且動態增長空間)

test.qcow2 是你要建立虛擬硬碟的路徑及檔名

1G 是硬碟的虛擬大小。

請自行更改

並請注意大小最小需大於等於來源磁碟

載入 NBD 模組

nbd 模組有點像是給虛擬硬碟一個掛載點,這裡要先載入這個模組

使用以下命令載入 Linux 核心的 nbd 模組

sudo modprobe nbd max_part=8

請注意如果要設定 max_part 的話,不要小於 4,會出事

掛載虛擬硬碟

使用以下命令將虛擬硬碟掛載到 nbd

sudo qemu-nbd -c /dev/nbd0 test.qcow2

/dev/nbd0 請設定為你要實際掛載的位置
例如 /dev/nbd1 之類的都可以
這裡使用 /dev/nbd0

test.qcow2 是剛剛建立虛擬硬碟的位置及檔名

掛載完後,現在 /dev/nbd0 在系統中就像一顆剛插上去的實體硬碟,你可以用 lsblk 看到它。

確認掛載成功

lsblk | grep nbd

image

應該要看到剛掛載為 nbd0 並顯示剛剛分配的空間
以這邊為例是 10G

設定分割表及磁區相關操作

啟動 KDE Partition Manager

首先選擇剛剛的 nbd0

image

接著選擇 New Partition Table

image

選擇 GPT
image

點選 Create New Partition Table

之後你會看到一個顯示 unallocate

image

這代表我們還沒格式化它

但沒關係,現在我們去要備份的那顆硬碟(注意:此時備份的那顆硬碟不能掛載,也就是來源硬碟不能掛載)

而那顆硬碟可能會長成這樣(以系統碟為例)

image

照理說我們應該要先格式化硬碟才能繼續之類的

但這裡我們可以直接複製整個磁區來取代它

你可以直接點磁區的那個區塊(上面那個有顏色的地方)

然後 Crtl+C Crtl+V 到新的那顆 nbd 即可

而因為這邊我僅作示範,所以先隨便分三個磁區

image

都設定完後

記得點左上角的 Apply,否則系統不會做任何操作

image

更改磁碟 ID 相關

查看 nbd 相關資訊

sudo fdisk -x /dev/nbd0

image

可以看到我們有幾個重要資訊

Disk identifier: 25BDF3F9-D9D2-4F8A-9A2C-F282E6BE1BA3

Device       Start      End Sectors Type-UUID                            UUID                                 Name Attrs
/dev/nbd0p1   2048  4196351 4194304 0FC63DAF-8483-4772-8E79-3D69D8477DE4 C02A8C28-DCD6-4E90-8BC7-4443ED813166
/dev/nbd0p2 4196352  8390655 4194304 0FC63DAF-8483-4772-8E79-3D69D8477DE4 E977A3D4-3AF0-4B6E-A074-23B760793746
/dev/nbd0p3 8390656 12584959 4194304 0FC63DAF-8483-4772-8E79-3D69D8477DE4 8BBC01F3-AB90-4153-9227-5C47A57453F0

這裡需要注意的是 Disk identifier 以及每個分區的 Type-UUIDUUID
等等會用到

查看要備份的目標硬碟相關資訊

fdisk -x /dev/nvme0n1

image

一樣可以看到我們有幾個重要資訊

Disk identifier: D356EF25-CA85-4E80-88CC-19046A20857C

Device           Start       End   Sectors Type-UUID                            UUID                                 Name Attrs
/dev/nvme0n1p1    2048      4095      2048 21686148-6449-6E6F-744E-656564454649 4DD9ED3C-EB33-4233-B03E-BD6B5E3E6DF7
/dev/nvme0n1p2    4096   2101247   2097152 BC13C2FF-59E6-4262-A352-B275FD6F7172 5104E937-01D8-4357-97AB-660AA3E4F456
/dev/nvme0n1p3 2101248 209713151 207611904 0FC63DAF-8483-4772-8E79-3D69D8477DE4 D3336CA9-5AB2-4638-B3A9-1CA94E708A9C

同樣需要注意的是 Disk identifier 以及每個分區的 Type-UUIDUUID
等等會用到

修改 Disk identifier

使用以下指令進入 fdisk 工具

sudo fdisk /dev/nbd0 

會出現以下資訊

~/test_virtual_disk

sudo fdisk /dev/nbd0

Welcome to fdisk (util-linux 2.40.4).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help):

這裡輸入 x 進入 Expert 模式以修改進階設定

Command (m for help): x

Expert command (m for help):

輸入 i 進入輸入模式

Expert command (m for help): i

Enter new disk UUID (in 8-4-4-4-12 format):

輸入 i 之後,輸入硬碟 UUID

請注意,這裡 UUID 請使用剛剛 /dev/nvme0n1 得知的 Disk identifier,簡單說,我們的目標就是將虛擬硬碟的 Disk identifier 更改為與實際我們備份硬碟的 Disk identifier 相同

直接輸入要備份的那顆硬碟的 Disk identifier,在這裡就是 /dev/nvme0n1

Enter new disk UUID (in 8-4-4-4-12 format): D356EF25-CA85-4E80-88CC-19046A20857C

Disk identifier changed from 25BDF3F9-D9D2-4F8A-9A2C-F282E6BE1BA3 to D356EF25-CA85-4E80-88CC-19046A20857C.

Expert command (m for help):

輸入 r 後輸入 w
完成寫入,在寫入之前,所有操作都是暫存而已

修改該磁碟各分區的 UUID

使用以下指令進入 fdisk 工具

sudo fdisk /dev/nbd0 
~/test_virtual_disk

sudo fdisk /dev/nbd0

Welcome to fdisk (util-linux 2.40.4).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help):

輸入 x
輸入 u
選擇分區

Command (m for help): x

Expert command (m for help): u
Partition number (1-3, default 3): 1

輸入新的uuid

Partition number (1-3, default 3): 1

New UUID (in 8-4-4-4-12 format): 21686148-6449-6E6F-744E-656564454649

Partition UUID changed from C02A8C28-DCD6-4E90-8BC7-4443ED813166 to 21686148-6449-6E6F-744E-656564454649.

Expert command (m for help):

輸入 r 後輸入 w
完成寫入,在寫入之前,所有操作都是暫存而已

修改該磁碟各分區的 TYPE-UUID

使用以下指令進入 fdisk 工具

sudo fdisk /dev/nbd0 
~/test_virtual_disk

sudo fdisk /dev/nbd0

Welcome to fdisk (util-linux 2.40.4).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help):

輸入 m
輸入 t

GPT
   M   enter protective/hybrid MBR

Generic
   d   delete a partition
   F   list free unpartitioned space
   l   list known partition types
   n   add a new partition
   p   print the partition table
   t   change a partition type
   v   verify the partition table
   i   print information about a partition
   e   resize a partition

Misc
   m   print this menu
   x   extra functionality (experts only)

Script
   I   load disk layout from sfdisk script file
   O   dump disk layout to sfdisk script file

Save & Exit
   w   write table to disk and exit
   q   quit without saving changes

Create a new label
   g   create a new empty GPT partition table
   G   create a new empty SGI (IRIX) partition table
   o   create a new empty MBR (DOS) partition table
   s   create a new empty Sun partition table

Command (m for help): t
Partition number (1-3, default 3):

選擇分區

Command (m for help): t
Partition number (1-3, default 3): 1
Partition type or alias (type L to list all):

輸入新的type uuid

Command (m for help): t
Partition number (1-3, default 3): 1
Partition type or alias (type L to list all): 21686148-6449-6E6F-744E-656564454649

Changed type of partition 'Linux filesystem' to 'BIOS boot'.

Command (m for help):

輸入 r 後輸入 w
完成寫入,在寫入之前,所有操作都是暫存而已

卸載硬碟

qemu-nbd -d /dev/nbd0

備份完成

確認備份是否正確

一般啟用情境

接著我們要確認這份備份是否正確

我們使用虛擬機進行確認

  1. 首先進入 Virt Manager 或是 Virtual Machine Manager 總之一樣的意思

    我們可以看到他長這樣

    image

  2. 點選左上角,建立新虛擬統
    並選擇 匯入現有磁碟映像,點 下一步

    image

  3. 選擇 本機瀏覽,並找到你當初存放 qcow2 的位置

    image

  4. 接著選擇你的系統及版本,以我為例,我使用的是 Ubuntu 22.04
    所以選這個選項

    image

  5. 設定 CPU 及 RAM 的使用量,隨便,高興就好

    image

  6. 接著,記得要勾選 在安裝前自訂組態,如果忘記勾選,前面全部重來,這很重要

    image

  7. 下一步後,在韌體選擇 UEFI X86_64:/usr/share/edk2/ovmf/OVMF_CODE_4M.qcow2
    實際選項可能不一樣,但總之就找關鍵字 UEFIOVMF_CODE_4M 這兩個就對了,不要選到 secure boot 相關的,可能會出事

    image

  8. 這裡有點重要,預設應該是 QXL ,先不用動他,有問題再改 VGA
    image

  9. 都確認好後,點選右下角 套用 並點左上角 開始安裝,如果正常應該可以直接開機
    image

故障排除

在過程中,你可能會遇到
這個
image

這個
image

這個
image

或是這個
image

然後還有他 X 的這種直接卡住
image

還有這個,只有游標
image

最後甚至好了,直接一片黑,連游標都沒有了
image

以上族繁不及備載
有以上情況,你有兩種辦法

  1. 擺爛,反正我磁區已經複製到虛擬硬碟了,也顯示有占用了,所以應該備份好了,就當他有了,然後可能你的資料有問題
  2. 還是檢查一下好了

假設你想選 2 的話呢?
我剛好有一些解法,雖然可能不能解決你的問題
但解決我的了

首先,在虛擬機開機的時候一直按 esc,應該會進入 grub,像以下這樣
image

接著,請下以下命令

ls

我們要先知道裡面長什麼樣子
你可能得到結果是

grub> ls
(proc) (memdisk) (hd0) (hd0,gpt2) (hd0,gpt1)

接著,你必須要確認你的系統在哪一個分區,所以對每一個分區 ls,你有幾個分區就做幾次,因為我只有兩個,所以做兩次
以下是輸出

grub> ls (hd0,gpt2)/
error: unknown filesystem.

grub> ls (hd0,gpt2)
Partition hd0,gpt2: No known filesystem detected - Partition start at 525312KiB - Total size 976236544KiB

grub> _

可以看到 gpt2 明顯比較大,所以開機磁區應該在這,所以我們下

ls (hd0,gpt2)/boot/

確認這個磁區裡面有沒有 boot 資料夾,以及看裡面有什麼東西
結果如下

grub> ls (hd0,gpt2)/boot/
efi/ grub/ config-6.8.0-60-generic vmlinuz-6.8.0-60-generic initrd.img initrd.img.old memtest86+.bin memtest86+.elf memtest86+_multiboot.bin vmlinuz
vmlinuz.old config-6.8.0-87-generic config-6.8.0-90-generic vmlinuz-6.8.0-87-generic System.map-6.8.0-87-generic System.map-6.8.0-90-generic
System.map-6.8.0-60-generic initrd.img-6.8.0-87-generic vmlinuz-6.8.0-90-generic initrd.img-6.8.0-60-generic initrd.img-6.8.0-90-generic

這裡我們可以看到很多 kernel 的版本,這裡我們選最新的
vmlinuz-6.8.0-90-generic,並且對應的映像是 initrd.img-6.8.0-90-generic

這樣我們確認到,kernel 確實存在

接著我們下以下這些命令

set root=(hd0,gpt2)
linux /boot/vmlinuz-6.8.0-90-generic root=/dev/vda2 ro quiet splash nomodeset
initrd /boot/initrd.img-6.8.0-90-generic
boot

需要注意的點是

/boot/vmlinuz-6.8.0-90-generic,請換成你自己看到的最新的 kernel
/dev/vda2,請換成你自己的磁區
/boot/initrd.img-6.8.0-90-generic,也是換成你自己的映像

簡單說我這邊的命令都是參考,需要自行替換

詳細一點的解釋如下

set root=(hd0,gpt2)
# 告訴 GRUB「檔案系統的根目錄在哪」
# hd0 = 第一顆硬碟
# gpt2 = GPT 分區表的第二個分區(ext4 系統分區)
# 系統才知道後面的路徑去哪裡找
linux /boot/vmlinuz-6.8.0-90-generic root=/dev/vda2 ro quiet splash nomodeset

# linux = GRUB 指令,載入 Linux kernel
# /boot/vmlinuz-6.8.0-90-generic = kernel 映像檔路徑
# root=/dev/vda2 = 告訴 kernel 開機後根目錄在哪(virtio 磁碟所以是 vda)
# ro = 一開始用唯讀方式掛載根目錄(正常開機流程)
# quiet splash = 安靜模式 + 顯示開機畫面
# nomodeset = 禁用顯卡 KMS,用基本顯示驅動
initrd /boot/initrd.img-6.8.0-90-generic
# 載入 initial ramdisk
# 這是開機早期需要的驅動和工具的暫存檔案系統
# 必須跟 kernel 版本配對
boot
# 執行開機,把控制權交給 kernel

理論上全部都下完之後,應該就可以開機了

開機進入系統後,應該就會像這樣

image

進去後,記得要做一些事

首先,我們進 CMD
輸入

sudo nano /etc/default/grub

我們需要改些開機相關的

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

改成

GRUB_CMDLINE_LINUX_DEFAULT=""

Crtl+O 儲存後,Crtl+X 離開

之後輸入

sudo update-grub

確定更新完 grub 後,關機
並回到上面 一般啟用情境 中的 8.

把顯示改成 VGA

之後應該就能正常開機了

故障原因推測

其實我不是很確定究竟問題在哪
但大概是跟顯示有關的,主要是開機時的那三個參數

quiet splash nomodeset

這些參數有以下意思

quiet

  • 減少開機時顯示的 kernel 訊息
  • 只顯示錯誤和重要訊息

splash

  • 啟動時開機動畫
  • 顯示圖形化的開機畫面(例如 Ubuntu logo)
  • 拿掉的話會看到文字訊息而不是 logo

nomodeset

  • 禁用 Kernel Mode Setting(KMS)
  • 阻止 kernel 載入顯卡的原生驅動
  • 強制用基本的 VESA/VGA framebuffer 顯示
  • 解析度會較低,但相容性最高

在我自己測試後,發現只要沒有 quietsplash 的話,並且顯示改成 VGA 就可以正常開機
如果拿掉 quietsplash 後,還是使用 QXL 的話,一樣會黑畫面

因此我推測是顯示協定的相關問題
但查這個搞了我很久

所以就先停在這了
以上是目前的解法