2012年7月26日 星期四

再論Linux開機

從電腦上電到出現命令提示符號間,系統經過了許多血汗的努力,這過程在使用者角度上不太重要,但,如果想要定做一個小型的Linux系統,就需要了解Linux整個啟動的過程。

當電腦上電之後首先是執行BIOS的程式,接著由BIOS交接到磁碟機上的MBR,通常OS Loader會載到MBR,這Loader負責把OS 核心(Kernel)與rootfs檔案initrd.img載入到記憶體中,並把控制權交接給核心運作,之後會解開initrd.img到記憶體上,成為暫時的rootfs但是是在RAM上,被稱為initrd (INITial Ram Disk),解開的rootfs之中有init這檔案,核心會去執行它,init(or linuxrc)必須要可以執行,可以是Script,有人稱它為Application Manager,這程式接手之後就得負責把磁碟機驅動起來,之後要掛載檔案系統,建立一些必要的設備節點,最後是根目錄切換,切換之後再去執行新的目錄中的init,把完整的系統驅動起來。

  1. bootloader載入kernel及initrd
  2. kernel解開initrd,並釋放initrd所佔用的記憶體空間
  3. 將rootfs掛載到ram disk上
  4. 執行 init (initialization)
  5. 掛載真正的rootfs
  6. chroot執行/sbin/init
所以第一次掛載ramfs時候如果需要開機到RAID上,就需要修改initrd.img這檔案,驅動起RAID並且掛載上再切換到RAID上,或是需要掛載iSCSI的磁碟當成系統碟也是需要修改它,如果不夠了解整個開機過程,相信沒辦法做到這一點,如果不需要太多的程序來搶資源,也可以讓自己寫的程式去領PID 1來用,整個系統就幾乎是你的程式獨占資源,所以對這些程序流程理解的愈深,相對的擁有的自由度就愈高。

當我在做小型的Linux系統的時候,我只需要開機到ramfs,所以不再往下交到目標磁碟機手上,而是直接用ramfs就好,一般這種作法搞出來的嵌入式系統是整個運作在記憶體上,好處是掛掉隨便使用者亂關都沒事,反正下一次要用還是得重新載入到記憶體上,只要原始的檔案沒毀損就沒事,缺點就是要等載入跟解壓縮,如此一來開機時間就會拉長,在很多的網通設備、多媒體播放器上都是這樣搞,只是他們也得面臨到開機速度的挑戰,所以就會看到各家奇奇怪怪的加速手段。

 在kernel版本2.6之後,initrd改用cpio製作,可以稱做cpio-initrd,它不需要特殊的block device或loop back device,製作過程比較簡單,而2.6與2.4的差異可以參考這一篇文章寫的。

上頭說的流程是Kernel 2.6以後的版本,而對於開機流程相信查到的文件常常是叫你去改inittab這檔案,如果你跟我一樣是用ubuntu/Debian就會發現事情並不單純(李組長語調),傳統的作法繼承於Unix-Like底下System-V init的作法,但是之後因為一堆隨身碟、硬碟、、、等隨插即用的東西出現,這個系統變得不太能夠適應,新的需求對於軟硬體的啟動、停止、掛載、移除,需要服務可以動態的啟動,傳統的sysVinit是基於runlevel的系統,使用runlevel(單、多使用者以及其它level)和鏈接(於/dec/rc?.d目錄,分別鏈接到/etc/init.d的init script)來啟動和關閉服務,而Ubuntu使用的是UPStart-Init則是基於事件的系統,它使用事件來啟動和關閉系統服務,傳統的SysVinit還有一個缺點,就是啟動需要跑一堆shell script,好處是很容易改,但是缺點是「慢」,這個缺點是從MacOS學到的教訓,在相同的位置上Solaris使用SMF(Service Management Facility),而Mac OS則使用Launchd,而Ubuntu則是傾向集這些軟體的優點於一身。

使用上也真的比較快,開機真的快多了,而且對於裝置服務的反應以比較靈敏,新的CPIO省去一次載入核心的時間,而init省去shell script運作產生的浪費,目前最耗時間的還是載入rootfs的時間(壓縮比加到頂也沒小多少,但是就明顯感覺核心解壓縮有點燒到點時間)。

sysVinit
  • initScript /rc script
  • rc => run commands
  • /etc/rc.d/init.d
  • /etc/inittab
    • id:5:initdefault:
  • /etc/rc.d/rc5.d
    • exp:
    • /etc/rc.d/rc5.d/K36mysqld
    • link to ../init.d/mysqld
    • K36mysqld
      • K : Kill/Start
      • 36: boot sequence
      • mysqld: service name
  • runlevel設定相互獨立
UPStart
  • event-driven/-based
  • 理順服務依賴關係以便實現平行啟動
  • 按需求啟動
  • Upstart job script
  • 有關UPStart相關的說明可以參考這一篇文章
也就是init最後不要交到真的磁碟機的/sbin/init而是交到ramfs裏面的/sbin/init,如果是用UPStart的服務,則是要搬相對的資料給他用,/etc/init目錄下的東西,底下的東西是.conf只是設定檔而已,不是shell script,而也要順便拷貝/etc/init.d目錄下的東西,除此之外還有相對應的設定檔也要拷貝,比如說ssh,除了init或init.d之外,還放了一個/etc/ssh/的目錄,也要順便拷貝走,與DNS相關的是/etc/hosts、/etc/resolv.conf、/etc/nsswitch.conf這3個設定檔,與帳號、密碼相關的設定檔是/etc/passwd、/etc/shadow、/etc/group這3個,如果說認証上有問題要注意/etc/pam.d/,PAM(Pluggable Authentication Modules),要順便注意/etc/nologin、/etc/securetty、/etc/security/*這堆。



沒有留言:

張貼留言