這里介紹一下自己管理自己的Linux桌面的一點經驗吧,我覺得還是有不少可取之處的。先來說一下大多數人管理Linux桌面的方法有哪些不方便的地方吧:買新電腦了,又得在新電腦上安裝Linux,安裝各種軟件,各種庫,各種開發環境,配置各種服務,真麻煩。
最近一直在用電腦A,干了好多事情安裝了好多軟件,也配置了不少開發環境跟各種服務,然而處于某種原因,我又要開始使用好久沒用過的電腦B了,難道我要把在A上的做的各種配置在B上再重新做一遍?
在Windows下做著PPT呢,發現需要調出自己之前的程序,然后根據若干組輸入跑幾個結果畫張圖好插到PPT里,然而這個程序是在Linux下寫的,編譯等的過程也嚴重依賴自己用的Linux環境,重啟進Linux拿到結果再回Windows太不方便,想在Windows下配置好環境把自己的程序跑通更不容易。
要對系統安裝某個軟件,或者進行一些比較危險的更新操作(要知道Archlinux滾動更新滾掛了太正常了),擔心把系統搞掛了,系統備份又實在太麻煩,要真掛了,系統恢復起來更麻煩。
我一直用Archlinux做主力,然而最近做的某件事情要用某個軟件,這個軟件官方只給了Ubuntu上的安裝方式,Archlinux里面沒有相應的包,在Archlinux上手動安裝也太不方便。裝個Ubuntu,然后暫時用幾天Ubuntu吧,也是夠折騰的。更何況有時候只是想用一小下而已,怎樣才能最小化自己在折騰上浪費的時間呢?
有的軟件官方軟件倉庫里面沒有,而make install的話則會在系統中安裝上不被包管理器所管理的文件,將來卸載也不方便,我還是更希望所有的文件都在一個包管理器中管理的。
聽說新版本內核引入了某個牛逼的東西?我就想快速測試一下玩玩,我電腦還有計算在跑著呢,我可不想重啟,那就只能用虛擬機嘗試了。而且,一定要快速,我可不想為此特地裝一個虛擬機。
上述的這些不方便之處是可以通過自己管理系統時的一些技巧來克服的,本文目的就是來介紹一下這些技巧。通過這些技巧,我們實現的功能是:一臺機器上,可以同時安裝Windows跟若干Linux系統,Windows下可以通過虛擬機來運行位于本地磁盤的這些Linux系統,而這些Linux系統下也可以通過容器或者虛擬機的方式互相運行。并且這些系統可以非常方便地備份跟刪除,也可以隨時創建以及運行快照。并且這些Linux系統可以隨時打包帶走,只需要經過很少的修改,就能直接在U盤或者其他機器上運行。如果要換電腦,或者新裝一臺電腦,也不需要重新安裝系統,只需要把已有的系統同步到新電腦就行。這也正是這篇文章標題的意思。
為了行文的方便,我們假定讀者有一臺全新的機器,硬盤還沒分區,也還沒裝任何系統。如果已經什么都裝好了,而只是想遷移到我這種管理方式的話,我相信讀者能夠判斷這個安裝教程中哪些步驟是需要做的哪些步驟是不需要做的。 另外需要注意的是這不是一個手把手的一步一步的教程,中間有一些顯然的步驟我就略去不寫了,所以希望讀者不要照著文章里的的命令不加思考地一條一條粘貼運行,而是要搞明白這些命令的目的是什么,然后根據你自己的情況來做相應的修改。
分區與子卷
具體怎么分區我就不說了,隨便找個livecd啟動進去,然后找到你自己最喜歡的分區程序,按照你的喜好把區分了就好。注意別忘了EFI分區。我這里需要說的是,分區的時候,不論有多少個發行版要安裝,總共只給Linux劃分兩個分區:一個是swap,另一個則是一個大的btrfs分區。那個btrfs分區里面裝著所有的文件,包括用戶的個人數據,以及所有發行版的rootfs。這兩個分區在格式化的時候,一定要給他們取Label,這么做的好處接下來我們很快就會看到。我的習慣是,swap分區的Label我就叫他“swap”,而那個btrfs分區我則叫他“linux”。創建好分區以后,如果格式化工作是在圖形的分區管理程序下完成的,那么指定Label是個非常簡單的工作,右鍵屬性里面就有。如果是使用命令行工具格式化分區的,則可以使用-L label選項來指定label,比如:
mkswap -L swap /dev/sdb4mkfs.btrfs -L linux /dev/nvme0n1p4
那個大的btrfs分區上的不同內容是通過btrfs的子卷來管理的,具體來講就是為自己想安裝的每個不同的Linux系統來創建一個單獨的子卷。 比如說我電腦上同時安裝了Archlinux、Ubuntu、Kali、Debian四個系統,那么的btrfs分區里面就有四個子卷:archlinux、ubuntu、kali、debian。 子卷的創建可以通過btrfs subvolume create
如果你只想裝一個發行版,比如archlinux,那么只需要archlinux子卷就夠了。另外,如果你想把用戶數據單獨放在一個子卷里,也是完全可以的,不過這里不推薦多個Linux系統共享同一個家目錄,因為不同系統上安裝的軟件不同,同樣的軟件版本也不相同,即使版本相同,不同發行版也可能應用了不同的patch,這就導致在一個系統上用戶家目錄里面產生的配置文件,在另一個系統里無法兼容,產生奇怪的行為。
系統安裝
創建好分區與子卷,下一步就是安裝操作系統了。這里分兩種情況來講:第一種情況是你想要全新安裝一個Linux操作系統;第二種情況則是你已經有了某個可用的操作系統了,而只是想把這個操作系統遷移到文章所說的管理方式上。
全新安裝
如果想要全新安裝一個操作系統,安裝方式上,作者只推薦純手工安裝,而不是用官方給的安裝光盤不斷點著“下一步”來進行安裝。這么做是為了防止官方安裝程序做一些我們不想讓他做的事情,比如說自動安裝grub。對于Archlinux跟Gentoo來講,唯一的安裝方法就是純手工安裝,所以只要按照官方的教程來就好了。對于deb系的系統,可以使用debootstrap程序。對于其他的發行版,可能會找不到手工安裝的教程,這時候可以新建一個虛擬機,在虛擬機中使用官方的安裝程序不斷點擊“下一步”來完成安裝,然后按照下一節即將介紹的現有系統遷移教程把系統從虛擬機中遷移到現實機器上;除此之外,讀者還可以找到發行版官方提供的安裝程序的源代碼閱讀一下,看明白這些安裝程序都在干啥,就知道怎么手工安裝了,安裝程序的代碼還是相對簡單的,有時間的讀者不妨嘗試一下。下面來具體說一下安裝過程,這里只介紹Archlinux跟deb系。如果有多個Linux系統需要安裝,建議先安裝并完全配置好其中一個,讓這個系統處于可用并且方便使用的狀態,然后再在這個可用的系統中安裝其他系統。這里我們假設讀者已經完成了分區,創建了對應的子卷,并且把那個btrfs分區掛載在了/mnt上。
Archlinux的手動安裝
Archlinux的手動安裝主要還是看官方教程。分區的時候注意按照上文介紹的方法。非常關鍵的pacstrap那一步注意使用如下命令安裝到子卷里,而不是整個btrfs分區中:
pacstrap -d /mnt/archlinux base
至于fstab,就不要使用教程中的方法來生成了,我們的管理方式比較非常規,還是自己寫fstab比較好。bootloader也要按照本文下文說的方式來安裝跟配置。至于其他的設置鍵盤、設置網絡、設置時區等操作,照著教程來就行。
deb系的手動安裝
deb系的系統網上找到的教程都是使用發行版自帶的安裝程序的教程,并沒有像Archlinux那么詳細的手動安裝教程。因為我們想要手動安裝,所以我們就不參照網上的deb系的安裝教程了。但是我們還是有教程可以參照的,那就是Archlinux的wiki里面關于systemd-nspawn的教程,這個教程里面有一節介紹如何使用debootstrap安裝Debian或者Ubuntu。具體安裝過程請參照上述教程,其中關鍵命令如下:
debootstrap --arch amd64 zesty /mnt/ubuntu http://archive.ubuntu.com/ubuntu/
值得一提的是,我們安裝deb系的發行版并不一定要使用deb系的livecd,任何能夠安裝debootstrap程序的livecd都是可以的。比如說我們完全可以使用Archlinux的livecd來啟動,然后安裝debootstrap并通過debootstrap來安裝Ubuntu。
注意的是,debootstrap并不會像官方安裝程序那樣安裝一個完整齊全開袋即食的操作系統,而只是安裝最基本的軟件包,讀者需要根據自己的情況單獨安裝桌面環境等的軟件包。同時fstab跟bootloader也要根據本文的方法自己配置。
現有系統遷移
Linux系統的遷移其實非常簡單,無非就是把rootfs的文件全都拷貝到目的地即可。不過這個過程雖然看似簡單,但是還是有一些需要注意的東西的。比如說對于符號鏈接,如果處理不當,則會不小心把符號鏈接搞成實體文件,這就不好了。再比如說,文件的權限等元數據的問題,如果處理不當,可能會導致拷貝過程中元數據的丟失。這兩種問題,都有可能會導致系統不能正常運行。還有一個需要注意的地方就是,正常運行的操作系統里,會有/proc、/dev等目錄,這些目錄都是單獨的虛擬文件系統,是不需要拷貝的,也是無法拷貝的。
我們現在假設用戶想要把位于A的Ubuntu系統遷移到目標子卷/mnt/ubuntu去。其中,A可能位于虛擬機中,可能位于另一臺電腦上,也可能位于本地磁盤。對系統進行遷移,大方向上來講,需要做的有兩步:
掛載相應分區,設置ssh,保證我們能夠訪問到A。
使用rsync或者btrfs send命令來把數據從A發送到目標子卷中去。
第一步具體怎么做就不說了,分三種情況簡單幾句話概括一下怎么做:
如果只是一個分區的話,mount就可以了
如果是另一臺機器,把那臺機器配置好ssh,保證root用戶可以用ssh訪問
如果是虛擬機,有兩種選擇,一種是想辦法掛載虛擬機的磁盤鏡像,然后像情況1那樣處理;另一種則是配置好網絡跟ssh,像情況2那樣處理。具體采取哪種措施請讀者根據自己的情況來自行決定。
第二步我們來分別介紹rsync跟btrfs send兩種方法。
我們現在假設A的ip地址為192.168.88.3。則只需執行如下命令即可:
rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} root@192.168.88.3:/ /mnt/ubuntu
這里提醒讀者注意自己系統上是否還有其他不想要同步的文件,記得一并排除掉。
btrfs send只在A的rootfs也是btrfs的情況下才能使用。這個方法的教程參見這里。首先需要做的是在A機器上給rootfs創建一個只讀快照(注意下面命令是在A機器上執行的):
btrfs subvolume snapshot -r / /ubuntu
注意上面命令中快照的名字要和目標子卷的名字相同,這樣可以省去將來改名的麻煩。然后就可以使用btrfs send命令來把快照/ubuntu中的內容發送到目的地了,在這之前我們需要暫時刪除我們分區的時候創建的ubuntu子卷,這個子卷會在接收過程中自動重新創建:
btrfs subvolume delete /mnt/ubuntussh root@192.168.88.3 btrfs send /ubuntu | btrfs receive /mnt
最后在A機器上把剛剛創建的快照刪除就可以了
btrfs subvolume delete /ubuntu
bootloader與fstab
系統裝好了,我們的fstab還沒設置,啟動管理器也還沒安裝配置。下面來講講怎么配置這兩樣東西。我們之前說過一定要給分區取一個Label,玄機在這里。如何在虛擬機中直接運行本地磁盤上安裝的Linux,以及如何能把一個系統直接進行打包帶走而不需要更改太多配置,關鍵也在這里。
fstab
先來說說fstab,fstab總共有五列,分別為fs、mountpoint、type、opts跟dump/pass。這五列分別為什么意思、以及fstab該怎么填,網上一查便知,在此不再贅述。這里只說我們需要做的跟常規不一樣的地方。
第一個要注意的事情是,大家在填寫fstab的時候,通常喜歡在fs那一列填寫類似/dev/sda4或者UUID=d5acc217-d524-4a2d-a937-bad945a047b2,而在這里這樣是不行的,這里我們填寫的是形如/dev/disk/by-label/linux這樣的東西。也就是說,我們的fstab里面是通過分區的Label來找分區的。這么做的原因是,我們希望我們的rootfs不光能在這臺機器上啟動,還希望它能在虛擬機的環境中,或者當我們把rootfs打包帶走同步到別的機器上的時候,也能正常啟動。在這臺機器上rootfs所在的分區叫做/dev/sda4,在別的機器上或者虛擬機里就不一定還叫/dev/sda4了。但是我們只要遵守自己的命名規則,所有機器上的這些分區我們都取相同的Label,那么我們的fstab就是放之四海而皆準的,不需要為不同的環境而更改。
第二個需要注意的問題是,不要填寫rootfs的條目。這種做法跟通常發行版或者其他用戶的默認做法是非常不相同的。為了理解這一點,先來說說Linux系統的啟動過程。通常情況下,Linux啟動的時候,首先由bootloader把內核裝載到內存,并向內核傳遞參數告訴內核rootfs的位置。接下來內核就會根據傳遞的參數,以只讀方式掛載rootfs,并執行rootfs中的init程序。init程序會調用相應的初始化程序執行各種初始化操作。其中一項初始化操作就是根據fstab的配置,來重新以讀寫方式掛載rootfs,并且掛載fstab里面配置的其他各個分區到指定位置。明白了Linux啟動的過程,我們就知道,fstab里面的rootfs那一行其實不是必須的。刪掉了rootfs那一行,我們只需要通過修改bootloader傳遞給內核的參數,就可以告訴內核直接以讀寫而不是只讀的方式掛載rootfs。
那么,我們在寫fstab的時候不寫rootfs那一項有啥好處呢?好處就是,我們不僅希望我們的系統能在裸機上用,還希望我們的系統能在虛擬機上用。在下文設置qemu虛擬機的時候,我們會以virtfs的方式把我們的子卷傳遞給虛擬機,這個時候rootfs就已經不再是/dev/disk/by-label/linux了,如果我們把rootfs的掛載方式硬編碼到fstab里面,那么會導致init程序的失敗,進而無法啟動。
另外有一點值得一提的小技巧是,很多時候我們還有別的一些個分區想要自動掛載。問題在于,這些分區在虛擬機環境中,并不一定是存在的,這就會導致啟動的時候由于無法掛載而啟動失敗。其實系統的設計者早就考慮到這個問題了。如果你不希望fstab中的某些條目自動掛載,在選項里面增加noauto即可。如果你希望一些條目自動掛載,但是這些條目不是那么重要,即使掛載失敗也不希望這些條目導致啟動失敗,可以在選項中增加nofail。這兩個選項真的是給我們的系統管理工作提供了非常大的方便。比如說我們可能會在fstab中增加/dev/disk/by-label/swap的條目,以便開機自動將這個分區設置為交換分區供系統使用。然而后面我們會看到,我們設置虛擬機的時候,這個分區在虛擬機環境下,并不一定是可用的。這種情況下,我們希望系統在找不到這個分區的時候直接忽略錯誤不用swap便是,而不是報錯拒絕啟動。
說了這么多,直接貼一個fstab的例子好了:
tmpfs /tmptmpfsdefaults0 0/dev/disk/by-label/swapnoneswapdefaults,nofail0 0
bootloader
再來說說啟動管理器,這里作者推薦的啟動管理器是refind,安裝教程官網有,在此不贅述。這里只講一下啟動項怎么寫。先貼示例代碼:
其中第三行的volume用來指定內核存放的分區,此分區可以通過多種方式來指定,比如通過分區的GUID,但是對我們來說最重要的是可以通過文件系統的Label來指定。我們的rootfs分區Label是”linux”,所以這一行寫作volume linux。
接下來就是指定內核位置、內核參數跟initramfs的位置了。其中loader用來指定內核位置,options用來指定內核參數,initrd則用來指定initramfs的位置。示例中的是Archlinux系統,內核是archlinux子卷中的boot/vmlinuz-linux文件,所以寫作loader archlinux/boot/vmlinuz-linux。類似,initrd那一行則寫作initrd archlinux/boot/initramfs-linux.img。至于內核參數,root=/dev/disk/by-label/linux告訴內核我們的rootfs所在的分區,rootflags=subvol=archlinux告訴內核掛載名為archlinux的子卷,rw則告訴內核以讀寫方式掛載。對于Ubuntu系統,這三行應該寫作:
loader ubuntu/vmlinuzoptions "root=/dev/disk/by-label/linux rootflags=subvol=ubuntu rw"initrd ubuntu/initrd.img
細心的讀者可能已經發現,我們的refind的配置文件中在指定分區的時候用的全是他們的Label,這就保證了這個配置文件的普適性,換臺電腦,只要你用同樣的管理方式,同樣的命名習慣,配置文件里面的東西動都不用動,直接拷貝過去就行。
系統的備份與恢復以及快照的應用
由于使用了btrfs的動態卷,所以備份恢復工作做起來非常簡單。備份系統只需要創建快照即可:
cd /mntbtrfs subvolume snapshot archlinux backup
至于恢復,其實我們根本不需要恢復,直接把快照作為rootfs用就行。我們只需要去refind的配置文件里面,把相應的啟動項改改即可。比如說對于Archlinux而言,只需要改成:
如果有強迫癥,覺得rootfs名字不叫archlinux很不爽,那其實改名也很簡單:
其實,btrfs的快照功能不僅可以用來備份與恢復系統,還有很多非常靈活的運用的。比如說我想在系統里面安裝一個巨大而又混亂的軟件,這個軟件我只想用幾天干一件事情,干完這件事情我就不想用了。問題是,這個軟件在官方的軟件倉庫并沒有,要安裝,我只能使用軟件提供的安裝程序來安裝,然而軟件并沒有提供卸載程序,或者卸載程序卸載的很不徹底,會在系統殘留垃圾。我想用這軟件,然而又不想臟了我的系統,這該怎么辦?很簡單:創建一個快照,新增加一條以快照為rootfs的啟動項,要用軟件了就啟動到快照中去,用完這個軟件以后把快照刪除即可。再比如說,我想要搞個虛擬機跟實體機一起來測試某個東西(比如說測試某些網絡協議、測試某些集群管理軟件等),這個時候我根本沒必要重新用安裝光盤去裝一個虛擬機,只需要創建一個快照,然后把快照作為虛擬機的rootfs啟動即可,具體方法下文會介紹,在此不多說。當然,快照的應用還遠遠不止我說的這些,更多好玩的應用還待讀者自己探索。
Windows下訪問Linux
從文章的剛開頭我們就說,有時候我們是有在Windows下運行本地安裝的Linux的需求的。這個需求可以通過VirtualBox來滿足,只需要在VirtualBox中使用本地磁盤來作虛擬磁盤即可。說起來簡單,但是實現起來還是需要折騰一下子的。
首先我們需要新建一個虛擬機,具體過程不多說,一路“下一步”就行了,唯一需要注意的是,在創建虛擬磁盤的那一步,選擇“不添加虛擬硬盤”:
這里我的虛擬機取名為“Linux”。創建完虛擬機了以后,就需要把本地磁盤設置為虛擬磁盤了。首先要做的是尋找我們安裝Linux的磁盤的編號,這個可以在系統自帶的磁盤管理程序中找到,在我的機器上這個磁盤編號為2:
知道了磁盤的編號,就可以創建虛擬盤了。這里我們使用的命令如下,注意使用管理員身份運行:
VBoxManage internalcommands createrawvmdk -filename "C:UsersgaoxiangVirtualBox VMsLinuxlocaldisk.vmdk" -rawdisk .PhysicalDrive2
有了虛擬磁盤了,就可以將虛擬磁盤添加到虛擬機中去了:
虛擬磁盤設置好了,最后一步就是設置EFI了。由于我們之前在分區的時候給文件系統都賦予了Label,并且在refind設置的時候也是用的Label來指定分區,所以同一套refind的配置在虛擬機上也能用。因此我們不需要單獨給虛擬機安裝bootloader,而是直接用我們之前安裝在物理磁盤上的EFI分區中的refind就行。VitualBox默認是不開啟EFI的,我們需要在虛擬機的系統設置里面手動勾選EFI:
為了要讓VirtualBox自動啟動refind,還要對EFI的分區做一些簡單的設置,設置的時候一定要注意,這些設置一定要是通用的,即同一份文件既能在物理機上正常工作也能在虛擬機上正常工作,不要改完了設置以后虛擬機上能跑了物理機卻掛了,這就不好玩了。VirtualBox的EFI在啟動的時候會優先選擇/EFI/BOOT/BOOTX64.EFI,如果找不到的話,才會啟動EFI分區根目錄下的startup.nsh中指定的bootloader。知道了這一點,為了實現自動啟動refind,首先需要檢查一下/EFI/BOOT/BOOTX64.EFI這個文件是否存在,若存在,備份并刪除之:
cd EFI/BOOTmv bootx64.efi bootx64-backup.efi
然后就是在EFI分區根目錄下新建一個startup.nsh了,這個文件只需要一行,內容如下:
EFI efind efind_x64.efi
一切設置完畢,運行虛擬機,就能看到我們熟悉的refind界面了:
打開其中的Ubuntu系統,測試一切正常就大功告成了:
當然,要在虛擬機中使用,還有一些細節性的工作要處理,比如安裝VirtualBox的guest需要的相應的內核模塊等等,這些在此不談,讀者使用過程中如果發現少啥了,自己裝上便是。
Linux下不同發行版的互相訪問
我們已經成功地在Windows下運行Linux了,下一步就是想辦法在一個Linux系統下訪問其他Linux了。由于這些系統都是Linux,而且都在同一個文件系統里面,所以如果只是想要訪問一下里面的文件的話,掛載了用就行了。但是很多時候我們還是有需要來運行其他系統里面安裝的程序,或者對那個系統進行管理的。應對這種需求有兩種解決方案:容器跟虛擬機。
可能很多讀者并不了解這兩者的區別,這里簡單介紹一下。粗略來講,虛擬機是通過軟件的方式虛擬出一套硬件環境來,并在這套硬件環境中啟動內核,然后內核會進行一個完整的開機過程,包括進行相應的初始化,加載init程序等。相比之下,容器則要輕量很多。容器并不會虛擬出自己的硬件環境,也不會額外加載一個內核。容器所做的,就是在現有內核上,運用namespace來創建出一套獨立的進程PID、掛載點、網絡接口、用戶ID等等,由于不同namespace中的這些個ID之類的標識符都是獨立的,所以不同namespace中的進程是互相之間看不到對方的,虛擬出來的環境乍看上去就跟在單獨運行的一個系統一樣,同樣有PID為1的init進程,有自己一套獨立的rootfs,等等。虛擬機的優點是更不容易被突破,安全性更好,可以使用自己的內核,但是效率也更低。容器的優點是輕便效率高,但是安全性就要稍差一些,也沒法使用定制內核。
容器
Linux下大家最熟悉的容器就是chroot了,但是作者并不喜歡chroot,主要原因有兩點:
/proc、 /dev等東西不會自動掛載,每次手動掛載掛的心好累
沒有一個相對完整的開機過程,好多我希望自動啟動的服務并不會運行起來
基于上面的原因,作者在這里推薦的容器是systemd-nspawn。systemd-nspawn的使用非常簡單,假設你的linux分區已經mount到了/mnt上去了,那么你只需要下面步驟就能啟動一個systemd-nspawn容器(以Debian為例):
cd /mnt/debiansystemd-nspawn -b
然后就能看到刷刷刷的開機界面了,真的是非常的方便快捷。這里還有一點小技巧是,如果嫌每次開容器都要把linux分區掛載到/mnt上太麻煩,可以在/var/lib/machines里面為每個系統新建一個目錄,然后在fstab里面設置一下自動把相應的子卷掛載進去:
這么做的好處是,根目錄位于/var/lib/machines的系統,在啟動systemd-nspawn的時候可以直接使用-M選項來指定系統,而不需要進入相應目錄。比如如果想啟動Ubuntu系統:
systemd-nspawn -b -M ubuntu
虛擬機
如果只是想運行一下其他系統里面的程序,那么容器完全就夠用了,但是有的時候我們還是需要玩玩不同的內核的,這就必須得用虛擬機了。通常情況下,大家用虛擬機,都是新建一個磁盤鏡像,然后插入安裝光盤,然后把光盤安裝到鏡像上。這么做的壞處,一個是訪問鏡像中的文件不方便,另一個是,我們在本地已經有安裝過若干系統了,不去充分利用一下這些而去再重新往鏡像里面安裝那實在是舍近求遠。那我們就來找一個把子卷當成虛擬機rootfs的方法。困難在于,虛擬機是個很獨立的東西,是無法直接訪問宿主機的文件系統的。然而幸運的是,Linux的內核虛擬化方案KVM提供了一個把本地文件系統傳遞給虛擬機的解決方案,用到的東西叫做VirtFS。
好消息是,VirtFS是可以作為rootfs的。但是要能正常掛載VirtFS,內核必須要有相應的驅動才行。這里有兩種方法可以做到這一點。如果你是自己編譯內核的話,那么建議直接將相應的驅動編譯進內核而不是模塊。根據官網的指示,涉及到的內核配置如下:
CONFIG_NET_9P=yCONFIG_NET_9P_VIRTIO=yCONFIG_9P_FS=yCONFIG_9P_FS_POSIX_ACL=y
如果使用的是發行版提供的內核的話,那么可以修改initramfs的相關設置保證9p、9pnet、9pnet_virtio三個modules能被安裝到initramfs里面去。這里以Ubuntu做guest為例,具體做法是修改Ubuntu系統中的/etc/initramfs-tools/modules文件,增加下面三行:
9p9pnet9pnet_virtio
然后重新生成initramfs即可:
update-initramfs -u
內核驅動設置好了,就可以啟動qemu虛擬機了,這里假定Ubuntu的rootfs已經被mount到了/var/lib/machines/ubuntu:
qemu-system-x86_64 -enable-kvm -m 16G -kernel /var/lib/machines/ubuntu/vmlinuz -initrd /var/lib/machines/ubuntu/initrd.img -virtfs local,id=root9p,path=/var/lib/machines/ubuntu,security_model=passthrough,mount_tag=root9p -nographic -append 'root=root9p rw rootfstype=9p rootflags=trans=virtio console=ttyS0 init=/lib/systemd/systemd'
最后放一張成功的截圖:
無盤系統
在某些特定的應用場景中,無盤系統用起來還是有不少方便之處的。尤其對于計算機集群而言,使用無盤系統不光能節省購買硬盤的成本,還能大大簡化集群的管理。雖然我們并沒有集群要管理,但是做一個無盤系統放在硬盤上用來代替livecd,在需要的時候進行一些系統恢復類的操作還是不錯的。對同時安裝有多個Linux的同學來說,其實用到livecd的時候并不多,偶爾一個系統出故障了,進其他系統把故障系統修復了就好。但是有些操作還是不得不用livecd的,比如要調整Linux分區的大小跟位置,這個分區就不能處于掛載狀態,這就不得不用到livecd了。相比于livecd,自己做的無盤系統的好處主要是可定制性。舉個不少人遇到過的實際例子來說:系統出故障了,進livecd修復系統,當試圖使用vim更改某配置文件的時候,系統提示說vim并沒有安裝,想要安裝,系統又提示說文件系統是只讀的,無法安裝。其實沒有vim還只是小事,用vi或者nano將就一下也就過去了。但是如果自己千辛萬苦下載并刻錄livecd,卻發現自己修復系統必備的軟件沒有且不能安裝,那估計砸電腦的心都有了吧。既然livecd這么不好用,那為什么不搞一個跟自己平時使用的桌面一模一樣的無盤系統呢?
要做無盤系統,一種做法是在另一臺機器上搞個nfs,然后在本機啟動的時候用nfs當做root來啟動(需要在內核配置中開啟ROOT_NFS選項),這種做法優點是內存占用相對較小(跟作者接下來要介紹的方法相比簡直是小多了),但是配置起來比較麻煩,而且網絡延遲跟帶寬也嚴重制約系統的性能。由于作者的電腦內存有128G之多,可以隨便揮霍不需要節約內存,并且作者只想簡單粗暴地把自己平時使用的桌面做成無盤系統來啟動,并不想多折騰。所以,作者最終采用的方案是基于initramfs的。要想理解制作過程,需要先了解幾個術語:
ramfs、tmpfs、rootfs以及initramfs
要想理解這個方案的工作原理,需要先了解一下本小節標題中的這幾個術語。這幾個術語在內核的官方文檔中有很好的解釋,在這里我們只做一個簡單的概括。
首先要從Linux的磁盤緩存機制說起。程序訪問文件的時候,Linux會把文件讀到內存中緩存起來。磁盤緩存中的文件,如果沒被修改過,或者被修改過但是改動已經從緩存同步到磁盤中去了,這種情況下內核會把對應的磁盤緩存標記為干凈(clean)的。對于被修改過,但是還沒來得及同步到磁盤的文件,內核會將其標記為臟(dirty)的。當Linux內存不足,需要釋放內存的時候,Linux會將磁盤緩存中的一些干凈的部分釋放掉,從而將內存挪作他用。ramfs是一個虛擬的文件系統,直觀上來講,它相當于直接把磁盤緩存給掛載到相應的節點上去了:它其中的文件只存活在磁盤緩存中。并且由于沒有物理磁盤可以將數據同步出去,所以這些文件的緩存始終是臟的,這也保證了這些文件不會被內核釋放掉。而tmpfs則是對ramfs的一個擴展,相比于ramfs,它允許限制文件系統的大小,也允許數據被搬運到swap中去。
rootfs也是一個虛擬的文件系統,它是專門在啟動的時候使用的一個特殊的ramfs。要想理解rootfs,需要了解Linux內核的啟動過程。這個過程位于內核源碼init/main.c文件中的kernel_init函數中,有興趣的讀者可以讀一下以便深入了解。簡單概括就是:Linux啟動的時候,會創建一個rootfs,并把根目錄“/”掛載為rootfs。這個rootfs將會伴隨Linux終生:跟init進程無法被終止道理類似,rootfs是無法被卸載的。rootfs創建好以后,Linux內核會把bootloader提供的initramfs文件中的內容解壓到rootfs中去,如果解壓好的文件中能找到/init或者用戶通過rdinit=內核參數指定的其他init程序,那么內核會執行這個init程序,并將接下來的初始化工作(比如掛載真正的root、刪除舊的rootfs中的內容以節約內存、執行真正的root中的init程序)交由這個init程序負責。如果此時rootfs中無法找到相應的init程序,Linux就會嘗試掛載真正的root,并執行root中的init程序。
基于initramfs的無盤系統制作
了解了上述的原理,我們的無盤系統制作思路也就清晰了:我們直接把自己的桌面打包成一個cpio,然后作為initramfs提供給內核,然后通過rdinit參數告訴內核啟動systemd即可。具體做法,這里就以Ubuntu為例,并假定Linux分區被掛載在/mnt中。首先需要把我們的桌面制作成一個cpio包:
cd /mnt/ubuntufind -mindepth 1 -printf '%P 主站蜘蛛池模板: 亚洲国产成人精品女人久久久 | www.xxx.日本| 亚洲乱淫 | 巨乳色最新网址 | 永久看片 | 老色批午夜免费视频网站 | 国内黄色一级片 | 性欧美大战久久久久久久久 | 久久亚洲国产午夜精品理论片 | 操你啦在线视频 | 99视频网址 | 国产成人啪午夜精品网站 | 狠狠色网站 | 国产免费久久精品99久久 | 婷婷亚洲综合一区二区 | 中文字字幕码一二区 | 精品午夜久久福利大片免费 | 经典三级一区在线播放 | 国产手机在线观看视频 | 天天天天做夜夜夜做 | 久久夜色tv网站 | 午夜看片网 | 久久99精品久久久久久久不卡 | 五月天婷五月天综合网在线 | 羞羞答答91麻豆网站入口 | 来吧成人综合网 | 欧美在线观看一区二区三 | 国产成人精品曰本亚洲78 | 欧美日韩国产成人高清视频 | 久久精品乱子伦免费 | 在线a亚洲老鸭窝天堂新地址 | 手机看片日韩永久福利盒子 | 美女脱裤子屁屁视频 | 亚洲精品久久婷婷爱久久婷婷 | 在线91精品亚洲网站精品成人 | 国产人成精品免费视频 | 三级毛片在线播放 | 色黄网站 | 噜噜噜动态图超猛烈 | 日日摸人人拍人人澡 | 在线观看永久免费视频网站 |