把Debian放進RAM裡面開機

這是真的。Minecraft是我從高職時期來一直有在接觸的遊戲,還和好友一起架設伺服器,與其他朋友們一起遊玩同一個世界,隨著電腦網路知識的增長,伺服器的作業系統也從一開始的Windows,轉換到Ubuntu,最後選擇了更輕量、簡潔的Debian,說真的Minecraft server只不過需要個簡單的OS管理硬體資源和網路,然後提供Java的執行環境而已。

幾年前,筆者正在服兵役時,接到朋友通知「伺服器連不上了!」,起初我還以為是個玩笑,我們常常用這個梗嚇嚇對方。但看他一臉認真的樣子,看起來是真的不妙,趁著休假時實際將螢幕插上server,結果發現卡在initramfs,寫著kernel panic .... 原來是停電造成OS檔案系統損毀開不了機。

除了加裝UPS,讓sever能在停電時妥善關機之外,也讓我有個發想:如果server能像Wi-Fi AP一樣,隨時拔插頭都不會壞,那該有多好? 如果storage放的檔案是唯讀的,那麼是不是就不會有寫到一半突然斷電,資料損毀的問題了? 如果OS檔案放在隨身碟,開機時通通倒進RAM裡面執行,是不是就能達到我要的目的了? 

是的,於是第一版放進RAM執行的Debian就這麼誕生了 ... 花了幾天把一般x86-64的Linux開機流程弄清楚,在VirtualBox裡面安裝一個完整的Debian,然後把rootfs包成壓縮檔,開機時透過魔改過的initramfs解壓縮到RAM裏頭,並將RAM(tmpfs)掛在/,這麼一來所有的寫入、變更都是在RAM裏頭進行,隨身碟的檔案完全就是唯讀的。rootfs包成壓縮檔最大的好處就是,利用隨身碟連續讀取很快的特性,來加快開機速度。

https://github.com/danchouzhou/ramfs

由於東西都是寫進RAM而已,所有變更都會在重新開機以後全部重來,因此我透過startup script的方式,讓開機自動執行我們所需的變更。簡單說就是,OS的壓縮檔可以不用重新打包,user要做的變更放在startup script裡面,每次開機就自動重作一遍,自動執行也在RAM裡面執行,所以也沒有要等很久的情況,而且server也不會常常重開機;由於user能很輕易地透過一支start.sh自訂功能,很容易備份、復原功能,不小心改壞了,也就是把原來的script貼回去而已,重新開機以後又恢復原先的樣子。

講到這裡,讀者看得可能有點霧,這邊簡單說明x86-64的Linux正常開機的流程:

  1. 主機板BIOS會去開GRUB
  2. GRUB會把Linux Kernel載到RAM裡面,然後執行initramfs
  3. initramfs負責掛載硬碟到/
  4. 在磁碟機裡面就是真正的Debian,會開始用systemd把一些服務開起來

要把RAM當硬碟用,其實就是在第3步動手腳,initramfs不再把硬碟掛載到/,取而代之的是把RAM (tmpfs)掛在/,並把隨身碟的壓縮檔,接壓縮進去。可參考檔案local.ramfs中的local_mount_root()。

mount -t tmpfs -o size=95% none ${rootmnt}

關於「1. 主機板BIOS會去開GRUB」,這邊再補充一下:如果是Legacy BIOS,會去找MBR裡面的一段boot code,boot code會再去找GRUB執行檔,這是因為MBR只有小小的512-byte,再扣掉分割表,boot code最多只有440-byte,不足以存放GRUB,這才需要分成兩段開進GRUB。如果是UEFI BIOS,會從檔案系統為FAT32的磁區 -- ESP (EFI System Partition),執行這個路徑EFI/BOOTX64.efi的檔案,透過grub-install --target=x86_64-efi,就是把GRUB放在這個路徑。

那麼自訂功能而不用重包壓縮檔怎麼辦到的? 其實魔改過initramfs是去執行隨身碟裡面的init.sh,init.sh的內容如下,實際上解壓縮是在init.sh裡面做的,同時也會把start.sh複製到/裡面,並且在第4步讓systemd自動執行。如此,使用者大可以從server上拔下隨身碟,在一台再普通不過的Windows電腦上就能修改initramfs以及開進Debian以後要做的事情了。

#!/bin/sh

echo "Copying rootfs.tar.gz ..."
cp /mnt/EFI/rootfs.tar.gz .
echo "Copying start.sh ..."
cp /mnt/EFI/start.sh .
chmod +x start.sh
echo "Unmount boot device ..."
umount /mnt
echo -n "Extracting from rootfs.tar.gz ..."
tar zxf rootfs.tar.gz --checkpoint=.5000
echo
rm rootfs.tar.gz

好吧,篇幅有限,可能沒辦法說明得太完整,有興趣的朋友可以研究一下我的GitHub Repo,應該就知道在幹嘛了。也可以在下方留言,我很樂意與您討論。

透過這樣的方法開機,雖然遊戲檔案還是儲存在硬碟中,但至少連不上時我還能遠端連進OS看看到底發生了什麼事(我們只是用一台十多年前的FX-4100消費型PC當成server在用,可不像正規的server有BMC可以遠端管理)。

這個方法已經在我的server上開機超過一年沒關了,應該足以驗證它的可靠度。唯一令我不滿意的是,由於壓縮檔是打包一個完整在硬碟中安裝的Debian,在RAM裡面解壓縮後大概占用1.3 GB,而且這是指有CLI沒有GUI的情況,也因此近期也正在研究如何進行「瘦身」,盡可能把寶貴的RAM留給Minecraft server用。有進展的話會在發一篇,我們下集見。

 

留言

這個網誌中的熱門文章

無法被取代的指針型三用電表(一):前言

關於新唐科技NuMicro ISP的介紹和使用方式

科風 BNT-1000AP 黑武士系列不斷電系統開箱拆解、簡易評測及經驗分享