前言

QEMU是個開源的虛擬機軟體,與之對應的還有強大的virtualbox和vmware player。QEMU在linux下安裝非常簡單,debian系可能就是一個aptitude/apt-get。但是我需要的從源碼開始構建一個QEMU,因為項目中需要學習一下ARM AARCH64體系結構下的MMU translation,所以初衷是自己寫一個software的MMU Model,然後掛載到QEMU中,看看能不能正常工作。要實現這個目的,就需要自行編譯QEMU了。網上搜羅了一圈,很多安裝都是基於已經編譯好的二進位文件,所以在這裡把我踩過的坑一一說明,也算是做個記錄吧。

本部分基本都是用命令行實現,可能需要一些bash的知識才能夠理解。

源代碼獲取和編譯

QEMU的官網在這裡。在官網的下載頁面,詳細說明了如何獲取QEMU(預編譯包或者源代碼)。對於我們所關注的源代碼獲取方式,其一是直接下載下載頁面中的xz壓縮包,第二個方法就是去git倉庫拉去最新的代碼了。兩種方式各有利弊,git倉庫獲取的代碼保證是最新的,但是git倉庫一方面保存了很多歷史信息,造成空間佔用非常大,另一方面就是小文件太多,下載起來比較費時間。這裡我們不追新,直接下載官網的xz文件就可以了。

下載完文件以後,xz解壓一下,以下都用$QEMU代表解壓後的代碼路徑。

cd $QEMU
mkdir bin && cd bin
../configure | tee cfg.log

這樣可以創建一個叫bin的子目錄。這裡我們不想把source code和中間build的臨時文件混在一起,所有的configure和build都在$QEMU/bin下執行。configure的結果我們也同時輸出到cfg.log文件,方便後續查看。

configure之後,先仔細檢查一下我們需要的選項是不是都打開了。configure會檢測環境中相關的開發組件開發包是否安裝或者是否支持,來決定是否打開一些選項。一般情況下,gtk最好能夠打開,不然我們的GUI界面都沒有了。如果gtk支持一項是no,我們可以

../configure --enable-gtk | tee cfg.log

來強制要求打開gtk,這個時候configure一般就會抱怨說沒找到gtk,並且給出安裝gtk支持的方法,這點configure倒是做的挺不錯的。想看看如何讓QEMU支持其他的組件也可以用這種方法來獲取依賴軟體包的安裝方法。照著configure給出的方法安裝需要依賴的包,再次運行上述命令,這次就能在cfg.log中看到gtk的支持打開了。

不過檢測cfg.log的時候,我們發現target-list一項似乎有非常多。QEMU本身支持虛擬多種CPU體系結構,並且每一種體系結構都有softmmu和linux-user兩種後綴。softmmu是用來做系統構建的,簡單說就是模擬CPU,以及提供支持運行OS。linux-user則只模擬CPU以及提供支持運行application。如果你只是需要運行一個特定cpu的application,不需要裝個OS再在OS里運行application,可以使用linux-user。看起來linux-user的用途跟wine差不多啊。

這裡我們只需要挑選我們需要的CPU平台和模式就行了,其他的沒必要編譯,例如,這裡我們選擇x86_64平台

../configure --target-list=x86_64-softmmu | tee cfg.log

仔細檢查輸出和cfg.log,確保所有需要的支持都到位了,然後

make -j4

並行構建還是非常快的。所以就算configure有啥東西後來發現還是缺了,再次構建還是非常快的。

現在,我們編譯出來的文件已經放在了$QEMU/bin/x86_64-softmmu下邊了。另外,QEMU也會在$QEMU/bin下生成一些額外需要的管理工具,例如管理磁碟鏡像的qemu-img等。如果需要安裝到系統中,就可以make install了。不過我們這裡自己用,不需要安裝到系統中。

安裝OS

要安裝OS,這裡我們還是在$QEMU下新建一個子目錄用來放我們需要的東西,和源代碼分開管理

mkdir $QEMU/vm && cd vm
ln -s ../bin/qemu-img
ln -s ../bin/x86_64-softmmu/qemu-system-x86_64

這裡主要將qemu-img(磁碟鏡像管理工具)和用到的qemu-system-x86_64軟連接過來。安裝OS之前可以下載對應OS的iso文件,這裡我們以arch為例,找一個叫arch.iso,並且假設已經在$QEMU/vm/下存在一個archlinux.iso指向我們下載的ISO文件了。

./qemu-img create -f qcow2 archlinux.qcow2 4G

創建一個4G大小的磁碟鏡像,名稱為archlinux.qcow2,格式是qcow2。qcow2是qemu自己的一種格式,不過後續可以很方便地轉成vdi或者vdisk等vbox/vmware的格式。創建磁碟鏡像的時候最好就把需要用的空間預留足夠,因為qcow2實際佔用的空間會隨著使用增大,而不是一開始分了4G就佔用4G的磁碟空間,所以分大一些不會造成空間的浪費。雖然qemu-img可以後續為磁碟增加新的空間,但是新增加的空間需要重新格式化和掛載,相對來說還是比較麻煩的,這裡我們分配4G,是因為只是做個實驗,不用啟動GUI,4G對於archlinux來說已經足夠了。

分好磁碟鏡像以後,現在就可以安裝OS了

./qemu-system-x86_64 -hda archlinux.qcow2 -cdrom archlinux.iso -boot order=d -m 1024

hda指定第一塊硬體,總共支持四塊,從hda到hdd。cdrom指明ISO鏡像,boot的話則說明啟動順序。最後需要強調一點的就是,一定要用-m 1024指明分配1G內存(或者以上)。現在的linux大多在安裝的時候需要較大內存的支持(儘管運行起來就沒必要了),而QEMU默認分配的內存好像是128MB還是256MB,對於安裝來說是不夠的。如果沒有在安裝的時候分配足夠的內存,就會出現initramfs錯誤,造成kernel panic。我剛開始沒注意出錯提示,還以為下載的ISO文件有問題,找了好幾個版本,都是拜這個坑所賜。

接下來就沒啥好說的了,按照傳統的安裝OS路子一路下去就是。安裝完畢以後,再次啟動可以不要cdrom選項了,就是:

./qemu-system-x86_64 -hda archlinux.qcow2 -m 1024

磁碟鏡像管理

QEMU編譯結束後,會生成qemu-img工具,這個工具主要用來管理QEMU所使用的磁碟鏡像的,支持的磁碟鏡像格式包括raw, vdi, cow, qcow, qcow2等一大堆,挺豐富多彩的。

這個工具還有快照功能,不過快照只對特定的特使有效。例如,我們上述裝完arch linux之後,想要個磁碟建一個快照,以後折騰壞掉了可以隨時恢復過來。建立快照的命令行格式如下:

./qemu-img snapshot -c init_status archlinux.qcow2

想要查看一下磁碟的快照和其他情況,可以使用:

./qemu-img info archlinux.qcow2

qemu-img工具也可以用來給磁碟增加或者縮減空間,具體的用法可以參考:

./qemu-img --help

網路

虛擬OS運行起來以後,我們可能需要在虛擬OS中訪問網路,這裡我們以NAT為例子,說明掛載QEMU中怎麼使用網路。說實話,網路折騰起來還是有點兒複雜的。這裡主要參考官網設置部分。

首先,需要安裝相關的工具,這些工具都是在宿主host OS上安裝,而不是guest OS上安裝的:

sudo apt-get install bridge-utils iptables dnsmasq

安裝過程中可能出現dnsmasq報出錯誤,說53號埠無法監聽。dnsmasq使我們安裝用來做動態DNS分配和解析的tool set,53號埠就是默認的DNS埠,這個一般被host OS自帶的工具給監聽了,dnsmasq報錯並不影響後續的功能,這裡忽視就可以了。

此外,我們還需要在host OS上準備兩個文件,分別指明啟用NAT的設置和停用NAT的設置,這兩個文件默認的位置都是/etc下,一個叫qemu-ifup,一個叫qemu-ifdown。在官網設置里給了一個qemu-ifup的例子,但是沒有給ifdown。這樣虛擬機關閉之後再次打開就會出錯,我這裡給了一個簡單的qemu-ifdown,可以與之配合。熟悉相關工具的開發人員可以自行編寫自己的ifup/ifdown。我們這裡都是為了快速bringup,就不考慮那麼多了。

if [ -n "$1" ]; then
echo "Tearing down network bridge for $1" > /tmp/temp-nat.log
ip link set $1 down
brctl delif "$BRIDGE" $1
ip link set "$BRIDGE" down
brctl delbr "$BRIDGE"
iptables -t nat -F
pkill dnsmasq
exit 0
else
echo "Error: no interface specified" > /tmp/temp-nat.log
exit 1
fi

需要註明一點的時,在退出的時候,我們強制把dnsmasq殺掉了。如果同時運行多台guest OS,一台退出的時候殺死dnsmasq,會導致另外正在運行的guest OS無法訪問。這算是一個小bug吧。

設置完之後,需要將兩個文件加上可執行許可權

chmod 755 /etc/qemu-ifup
chmod 755 /etc/qemu-ifdown

接下來,就可以使用以下命令啟動guest os了

./qemu-system-x86_64 -hda archlinux.qcow2 -m 1024 -nic tap

在archlinux中可以使用相關命令查看是否獲取了IP地址,注意archlinux的dns要打開,不然沒法拿到動態IP的。使用網路可能要root用戶許可權才行,這點需要注意。

KVM加速

QEMU支持硬體加速,首先要確認一下我們在configure的時候,KVM支持是否打開(其他加速機制同理),這個要回去翻一下cfg.log文件。如果編譯的時候KVM已經打開,在運行guest OS的時候,只需要多加入一個--enable-kvm選項就可以了。

經過我自己的測試,沒有打開KVM的時候,guest OS運行起來後,host OS的一個CPU核心長期處於100%狀態,guest OS的反應也比較慢。但是打開了KVM加速之後,guest OS的啟動和載入都非常快,基本等同於直接在硬體上運行的速度。host OS的CPU佔用相對來說很正常,沒有一個core超過10%的。

後記

折騰了一圈QEMU,突然發現現在硬體性能真的過剩,我12年買的X220,2代I5,4核(還是雙核四線程?),開了KVM加速,同時運行兩個guest OS沒有任何問題。我自己平常的時候都是看代碼看文檔,寫代碼寫文檔,這台六年前的電腦仍然沒有任何不堪重負的痕迹,反而還遊刃有餘。牙膏廠不愧是牙膏廠,不過這也可能是我運行linux以及SSD加成的緣故。


推薦閱讀:
相关文章