2017年9月3日 星期日

Debian Live: 把已灌入硬碟的系統變成 live cd

live-boot 的開機流程 玩出來了! 太感動了! Debian 系列 (含 *ubuntu) 有一個 live-boot 套件, 它可以把你已安裝在硬碟上的 linux 系統打包變成一張開機光碟 (live CD)。 這有什麼好處?

  1. 因為光碟是唯讀的, 所以你可以把系統用 squashfs 的方式壓縮到很小, 很省空間。
  2. 這張光碟可以用 pxe 從網路開機。
  3. 你可以把這張光碟放到隨身碟上, 再加上 persistence 功能, 又讓它變成可寫入的版本。 幫麻瓜製作開機隨身碟變得又快又簡單!。

2022/10/30 若要製作 UEFI 版的開機光碟, 請參考 支援 UEFI 光碟的開機載入程式 rEFInd

一、 開機流程

製作好的光碟的開機流程如上圖:

  1. isolinux 取得控制權, 讀取 isolinux/isolinux.cfg
  2. 載入指定的 vmlinuz 跟特製的 initrd
  3. 特製的 initrd 在 live/ 目錄下找到一個 squashfs, 檔名任意, 把它變成 root file system。 但是會先用 overlayfs 在上面覆蓋一個 (位於記憶體內的) 可讀寫的檔案系統, 所以用起來感覺跟可寫入的正常系統一樣 -- 變成了一張像是 ubuntu 安裝光碟, 可試用的 live CD。

其中聽起來最可怕的 「特製的 initrd」, 其實超簡單, 甚至連下指令都不需要! 只要安裝 live-boot live-boot-initramfs-tools 這兩個套件, 系統就會自動根據目前的 kernel 立即幫你產生一個 「特製的 initrd」, 它認得 man live-boot 手冊裡面所講的這些特殊參數, 所以你可以在 isolinux/isolinux.cfg 設定檔裡面使用這些參數。 對於熟悉 extlinux 開機設定 的讀者來說, 剩下的事情就都很簡單了。

二、 製作 iso 檔

以下把 「想要變成 live CD 的那個系統」 稱為廚窗展示系統。 嚴正提醒: 不要放入個人隱私資料 然後又把做好的 iso 放到 ftp 上讓網友下載你的信用卡號或家裡 wifi 密碼等等 :-) 完整製作步驟如下:

  1. 用廚窗展示系統開機。 (虛擬機可)
  2. apt-get install live-boot live-boot-initramfs-tools 在 /boot 底下產生 「特製的 initrd」。
  3. 用別的輔助 linux (例如含平常的工作系統, 或 live CD 或可開機隨身碟) 開機、 在這個輔助系統上安裝 squashfs-tools isolinux xorriso 三個套件。
  4. 把廚窗展示系統用唯讀的方式掛載起來, 例如 mount -o ro /dev/sdz99 /mnt/showoff
  5. 建一個工作目錄, 假設叫做 /some/large/part/worksp 好了。 把廚窗展示系統的 kernel (vmlinuz) 跟剛產生的特製的 initrd 都拷貝到 /some/large/part/worksp 底下。
  6. 把 /usr/lib/syslinux 整個目錄也拷過去, 改名為 isolinux 。 又把 /usr/lib/ISOLINUX/isolinux.bin /usr/lib/syslinux/modules/bios/ldlinux.c32 兩個檔案都複製到 isolinux/ 底下 (也就是跟 isolinux.cfg 放在同一層子目錄裡)。 還有, 把 我的範例 isolinux.cfg 也放到 isolinux/ 底下。 重點是 boot=live 那一小段叫特製的 initrd 啟用 live-boot 功能。 [2020/3/4 補充: kernel 命令列需要加一些選項: ip=frommedia 避免 ubuntu 清除網路設定 net.ifnames=0 biosdevname=0 堅持採用傳統的網卡簡單命名。]
  7. 把整個廚窗展示系統壓縮成一個 squashfs 檔案系統, 放到 /some/large/part/worksp 底下的 live 子目錄裡面: mkdir /some/large/part/worksp/live ; mksquashfs /mnt/showoff /some/large/part/worksp/live/root.squashfs 它的 /etc/fstab 或是其他任何檔案都不需要修改, 因為掛載 root file system 的動作, 早在它變成 root 就已完成, 所以裡面指定 (或根本沒指定) 誰是 root file system 根本不重要。 所產生的檔案, 副檔名為 .squashfs ; 檔名前半部任意 (例如上面的 root)。
  8. 最後 /some/large/part/worksp 的目錄結構長這樣:
      44444K ./initrd.img-4.8.0-41-generic
      92937  ./isolinux/cyut-bv.jpg
      40960  ./isolinux/isolinux.bin
       1540  ./isolinux/isolinux.cfg
     116492  ./isolinux/ldlinux.c32
        439  ./isolinux/mbr/altmbr.bin
        440  ./isolinux/mbr/gptmbr.bin
        440  ./isolinux/mbr/mbr.bin
      25628  ./isolinux/memdisk
             ...
       1256  ./isolinux/modules/bios/cmd.c32
       3688  ./isolinux/modules/bios/cmenu.c32
       1492  ./isolinux/modules/bios/config.c32
             ...
       3096  ./isolinux/modules/bios/vesa.c32
       2204  ./isolinux/modules/bios/vesainfo.c32
      26724  ./isolinux/modules/bios/vesamenu.c32
             ...
       1913M ./live/root.squashfs
       7140K ./vmlinuz-4.8.0-41-generic
    
  9. 製作 .iso 檔: xorriso -as mkisofs -o /some/large/part/result.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table /some/large/part/worksp
  10. isohybrid 加工 (尚未測試)

然後就可以用 kvm 去測試你的 /some/large/part/result.iso 了! 很訝異這麼讚的東西, 竟然搜尋不太到教學文, 甚至連僅有的少數英文教學文都寫得不清不楚。 Ubuntu 的 casper 也是用 live-boot 做出來的; 但多數文章都沒解釋細節, 我也一直無法理解為什麼設定檔裡看不見 *.squashfs 的檔名。 最後是靠 這個簡短的問答 才學會的。

kernel panic 如果失敗, 就用螢幕錄影軟體 (例如 gtk-recordmydesktop) 把開機過程錄下來, 看看掛載 *.squashfs 成功之後, 發生了什麼事。 有時虛擬機開機速度太快, 可能需要把 gtk-recordmydesktop 的 「效能=>每秒畫格」 從 15 調到 30 之類的, 才拍得到。 有一個可能的原因: 記憶體不足。 造成 kernel panic 的另一個原因可能是: 你用的 initrd 是舊的、 錯誤的、 沒有經過 live-boot-initramfs-tools 加持的版本, 例如右圖。 這時可以移除 live-boot live-boot-initramfs-tools 這兩個套件、 再重裝一次, 系統就會自動更新 /boot 底下的所有 initrd*。

busybox 如果是像右邊這個 busybox, 那就是 initrd 已經執行到底, 可是卻找不到 live/*.squashfs 。 這時可能需要檢查 *.squashfs 放置的位置, 或是在 isolinux.cfg 裡的 append 那句後面加上 live-media-path=... (預設值是 live-media-path=/live )。

三、 把 squashfs 放在 lvm 裡面

Debian live 所製作的 initrd 會自動到各個 mbr 分割區或各個 gpt 分割的 /live 目錄下尋找任何名為 *.squashfs 的檔案來掛載。 所以熟悉 extlinux 開機設定 的讀者也不需要製作光碟, 可以直接把 vmlinuz、 initrd、 *.squashfs 等三個檔案搬到一般的分割上, 而且 *.squashfs 甚至不需要跟 extlinux 放在同一個分割區。

但若想搬到 lvm 的 logical volume 呢? 此時, 光指定 live-media-path 是不夠的。 還必須用 live-media 直接指定那個 logical volume 的 device name, 類似這樣:

label grml-lvm
        menu label grml from lvm /dev/mapper/eeepc-iso
        kernel /grml/vmlinuz
        append initrd=/grml/initrd.img boot=live live-media=/dev/mapper/eeepc-iso live-media-path=/grml

當然, 前提是 這個版本的 initrd 必須認得 lvm2 (grml 有)。 如果預設的 initrd 不認得, 就必須先把它安裝到硬碟上 (或用下節的 persistence 機制)、 安裝 lvm2 套件, 然後系統會自動建立新的 initrd。 你必須改用這個新的 initrd 來開機。

以後可以在硬碟上切一個 lvm 的 logical volume, 裡面專門放一堆各種版本的 debian-live 的 squashfs, 那麼單單是這一個 logical volume 就可以讓開機選單變得很熱鬧了啊~~

四、 persistence

如果 live CD 開機之後, 某顆硬碟或某顆隨身碟上面有正確的映像檔, 那麼系統會用 overlayfs 把這個映像檔覆蓋到唯讀的 squashfs 之上, 於是所有的變動就又可以存入映像檔。 這個機製稱為 persistence。 在 isolinux.cfg 的 kernel 命令列上要包含這幾段: persistence persistence-path=/live-save persistence-label=stux.img 之類的設定, 這樣光碟開機時, 會到每顆硬碟、 每顆隨身碟的每個分割裡的 /live-save 目錄下尋找 stux.img 檔案。 stux.img 必須是一個 loopback file system, 而且它的根目錄下必須有一個 persistence.conf 設定檔。 以下是製作 stux.img 的範例指令:

dd count=524288 bs=1024 < /dev/zero > stux.img
mkfs -t ext4 stux.img
mount stux.img /mnt/t1
echo '/ union' > /mnt/t1/persistence.conf
umount /mnt/t1

persistence-label 所指定的, 未必要是一個映像檔, 也可以是一個分割。 以 lubuntu 17.04 所製作的 live boot 光碟, 它會去每個 MBR 或 GPT 分割還有每個 LVM 的 volume 檢查, 如果有哪一個分割或 volume 的 label (以 e2label 檢查出來的為準; 跟 lvs 列出來的名稱無關) 正好符合 persistence-label 後面的參數 (以上例而言, 如果這個分割的 e2label 正好也叫做 stux.img), 那麼 live boot 光碟的 initrd 就會在這個分割或 volume 的根目錄底下尋找 persistence.conf 設定檔。 在這種情況下, persistence-path 這個參數設定任何值都無所謂 -- 它會被忽略。

更詳盡的設定語法請見 persistence.conf ; 這一頁 有更多範例。 這個映像檔最最起碼要有 300MB 的容量, 因為 /var/cache/apt 會吃掉很多空間; 但一開始也並不需要設很大, 因為日後空間不夠用時還可以擴增, 例如這樣做可以幫它增加 1.5G 的容量:

dd count=1572864 bs=1024 < /dev/zero >> stux.img
e2fsck -f stux.img
resize2fs stux.img

persistence 失敗 右圖的錯誤訊息顯示它有找到 persistence 的分割區, 可是無法掛載 (也許是那個分割區並未格格式化之類的)。 最後如果用 live CD 開機有看到類似下面的 /lib/live/mount/persistence/loop1 那麼 persistence 的設定應該就成功了:

檔案系統        1K-區段    已用     可用 已用% 掛載點
udev            1000092       0  1000092    0% /dev
tmpfs            204784    3728   201056    2% /run
/dev/sda1      18308352 2540816 15767536   14% /lib/live/mount/persistence/sda1
/dev/loop0      1959040 1959040        0  100% /lib/live/mount/rootfs/root.squashfs
tmpfs           1023916       0  1023916    0% /lib/live/mount/overlay
/dev/loop1       499656  256960   206000   56% /lib/live/mount/persistence/loop1
overlay          499656  256960   206000   56% /
tmpfs           1023916      72  1023844    1% /dev/shm
tmpfs              5120       0     5120    0% /run/lock
tmpfs           1023916       0  1023916    0% /sys/fs/cgroup
tmpfs           1023916       4  1023912    1% /tmp
tmpfs            204784  131796    72988   65% /run/user/1000

我所安裝的系統約使用 6G 的空間, 用 mksquashfs 壓縮之後只剩 2.3G。 再搭配一個 2G 的 persistence 映像檔, 只需要 4.3G 的空間就可以享受將近 6G 的自由。 而且這全部可以安裝在 vfat 分割上。 也就是說, 麻瓜拿隨身碟給我, 不需要燒毀, 只要還有足夠的空間, 就可以幫他製作開機隨身碟!

五、 全部載入記憶體, 豪邁帥氣裸奔!

如果你的記憶體夠大, 可以把整張光碟或隨身碟的整個分割載入記憶體。 一旦載入成功, 開機完成之後, 就可以拔掉隨身碟或光碟, 而且執行速度變得飛快!

載入記憶體的最佳方式, 就是在 kernel 命令列 (亦即 isolinux/isolinux.cfg 的 append 那句) 加上 toram=root.squashfs 之類的 boot option -- 請根據你的光碟或隨身碟上的 *.squashfs 檔名 及放置位置 來修改, 檔名就好, 不要加路徑!) 於是整個 *.squashfs 會被載入記憶體。 這個寫法在手冊上找不到, 是從 這一頁 學來的。 手冊上的 toram 後面沒有參數, 結果會把 (*.squashfs 所在的) 整個分割或整張光碟上所有檔案拷貝進記憶體, 有可能會因此而太撐、 失敗。

另一個方式是在 kernel 命令列上採用 findiso=/gregslab17E.iso 之類的寫法, 載入整張光碟的映像檔。 這雖然比載入 *.squashfs 要浪費一些, 至少不會把隨身碟同一分割上所有不相關的所有檔案一起抓進來。

不論用哪一種方式載入記憶體, 開機完成後記得要先下 df 確認已掛載的裝置裡面沒有你的開機光碟或隨身碟, 才能拔掉。 還有, 當然, 載入記憶體跟隨身碟的 persistence 是無法並存的。

六、 網路開機

假設你已成功設定 透過 pxe 從網路啟動簡單的 live CD。 想要把 live-boot 所製作的 live CD 放到網路上, 除了 dnsmasq 基本的設定之外, 還需要在 pxe 伺服器上架設一個 http 服務 (例如 apache2), 由它來提供 *.squashfs 。 假設 pxe 伺服器的 apache2 的 DocumentRoot 是 /var/www/html, 又假設 iso 檔已放在伺服器的 /large/partition/result.iso 。 可以這樣掛載並建立連結:

mkdir /var/lib/tftpboot/os/myliveCD
mount /large/partition/result.iso /var/lib/tftpboot/os/myliveCD
ln -s /var/lib/tftpboot/os/myliveCD /var/www/html

那麼你的 /var/lib/tftpboot/pxelinux.cfg/default 裡面跟這張 iso 相關的部分應該長得類似這樣:

label myliveCD
        kernel /os/myliveCD/vmlinuz-4.8.0-41-generic
        append initrd=/os/myliveCD/initrd.img-4.8.0-41-generic boot=live fetch=http://192.168.xx.yy/myliveCD/live/root.squashfs

其中 192.168.xx.yy 當然是 pxe 伺服器的 IP。 (必須用數字 IP!) 也就是說, 客戶端透過 tftp 取得 vmlinuz 跟 initrd; 但是下一階段的 root file system 必須用 fetch=... 透過 http 的方式取得, 而且這種做法自動會把整個 root.squashfs 載入客戶端的記憶體。 如果客戶端記憶體容量不夠大, 但有硬碟可用, 可以試試 live-boot 手冊裡的 todisk 參數。 我沒試過; 但猜想可用這個功能來取代電腦教室裡的還原卡。

live-boot 真是太讚了! 好想把這招分享給電腦老師們啊! 有沒有學校想辦電腦教室網管研習呢?

8 則留言:

  1. 太感謝了~~一直很愛live cd裡面toram的功能,沒想到我也可以把自己的系統製作成live cd,好好的拜讀老師的文章!!

    回覆刪除
  2. 使用persistence 功能 ,更改使用者密碼下一次開機的確是有所變動。 可是更改網路參數到此設定檔 /etc/network/interfaces,下一次開機並沒有變動,還是原設定檔。

    回覆刪除
  3. 老師~不好意思打擾~~請教一下:
    文章上說到: 把 /usr/lib/syslinux 整個目錄也拷過去, 改名為 isolinux 。 又把 /usr/lib/ISOLINUX/isolinux.bin /usr/lib/syslinux/modules/bios/ldlinux.c32 兩個檔案都複製到 isolinux/ 底下

    請問"isolinux.bin"這個檔案是在那邊?還是怎麼產生的呢?!

    回覆刪除
  4. 老師~不好意思打擾~~請教一下:
    您這篇大作,好像只能Legacy 模式,如果要支援UEFI的話,該做那些的修正才能達到同樣的效果呢?

    回覆刪除
    回覆
    1. 可以看這篇喔: https://newtoypia.blogspot.com/2022/10/refind.html 我把連結加上去好了。

      刪除
  5. 教授真的非常有求知精神,我太懶只會用人家做好的工具。最近有發現一個 Penguins' Eggs 工具可以完成上述功能的大部分,而且功能強大還沒了解到很透徹,開發者是義大利人,我試著用此工具將 Debian-based 發行版,如 Debian, Sparky, MX, LMDE 加入此工具做成 ISO 檔,有興趣可以下載玩看看。 https://sourceforge.net/projects/antix-mate-respin/

    回覆刪除

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。