arm64 伺服器中的 Debian armhf 虛擬機
在 Collabora 公司,我們所做的許多工作之一就是為客戶構建包括 32 位和 64 位 ARM 系統在內的各種架構的 Debian 衍生版。就像 Debian 做的那樣,我們的 OBS 系統建立在原生系統而不是模擬器上。
幸運的是隨著幾年前 ARM 伺服器系統的出現,為這些系統原生構建不再像以前那麼痛苦了。對於 32 位的 ARM,我們一直依賴 Calxeda 刀片伺服器,然而不幸的是 Calxeda 在不久前淘汰,硬體開始顯露其年齡(儘管幸運的是 Debian Stretch 還支持它,因此至少軟體還是新的)。
在 64 位 ARM 方面,我們運行在基於 Gigabyte MP30-AR1 的伺服器上,該伺服器可以運行 32 位的 ARM 代碼(與之相反,比如基於 ThunderX 的伺服器只能運行 64 位代碼)。像這樣在它們之上運行 armhf 虛擬機作為 從構建伺服器 似乎是一個很好的選擇,但是設置起來可能會需要更多東西的介入。
第一個陷阱是 Debian 中沒有標準的 bootloader 或者 boot 固件來啟動 qemu 模擬的 「virt」 設備(我不想使用真實機器的模擬)。這也意味著在啟動時客戶機內沒有任何東西會載入內核,也不會從客戶機網路引導,這意味著需要直接的內核引導。
第二個陷阱是當前的 Debian Stretch 的 armhf 內核並不支持 qemu 虛擬機所提供的通用 PCI 主機控制器,這意味著客戶機中不會出現存儲器和網路。希望這會被儘快解決(Debian bug 864726),並出現在 Stretch 更新中,那在之前需要使用 bug 報告中附帶的補丁的自定義內核,但在這篇文章中我不想進一步說。
高興的假設我們有一個可用的內核,剩下的挑戰是很好地管理直接內核載入。或者更具體地說,如何確保主機啟動客戶機通過標準 apt 工具安裝的內核,而不必在客戶機/主機之間複製內核,這本質上歸結於客戶機將 /boot
暴露給主機。我們選擇的方案是使用 qemu 的 9pfs 支持來從主機共享一個文件夾,並將其用作客戶機的 /boot
。對於 9p 文件夾,似乎需要 「mapped」 安全模式,因為 「none」 模式對 dpkg 有問題(Debian bug 864718)。
由於我們使用 libvirt 作為我們的虛擬機管理器,剩下的事情就是如何將它們組合到一起。
第一步是安裝系統,基本和平常一樣。可以直接引導進入由普通的 Stretch armhf netboot 安裝程序提供的 vmlinuz
和 initrd.gz
(下載到如 /tmp
中)。 設置整體來說很直接,會有一些小的調整:
/srv/armhf-vm-boot
設置為 9p 共享文件夾(這個應該存在,並且由 libvirt-qemu 擁有),這之後會被用於共享/boot
。- 內核參數中在
root=
後面加上 VM 中的 root 分區,根據你的情況調整。 - 鏡像文件使用 virtio 匯流排,這似乎不是默認的。
除了這些調整,最後的示例命令與 virt-install 手冊頁中的相似。
virt-install --name armhf-vm --arch armv7l --memory 512
--disk /srv/armhf-vm.img,bus=virtio
--filesystem /srv/armhf-vm-boot,virtio-boot,mode=mapped
--boot=kernel=/tmp/vmlinuz,initrd=/tmp/initrd.gz,kernel_args="console=ttyAMA0,root=/dev/vda1"
按照通常的方式運行安裝。到最後安裝程序可能會提示它不知道如何安裝引導程序,這個沒什麼問題。只要在結束安裝和重啟之前,切換到 shell 並以某種方式將目標系統中的 /boot/vmlinuz
和 /boot/initrd.img
複製到主機中(比如 chroot 進入 /target
並在已安裝的系統中使用 scp)。 這是必需的,因為安裝程序不支持 9p,但是要啟動系統,需要 initramfs 以及能夠掛載根文件系統的模塊,這由已安裝的 initramfs 提供。這些完成後,安裝就可以完成了。
接下來,引導已安裝的系統。調整 libvirt 配置(比如使用 virsh 編輯並調整 xml)來使用從安裝程序複製過來的內核以及 initramfs,而不只是使用它提供的。再次啟動虛擬機,它應該就能愉快地進入安裝的 Debian 系統中了。
要在客戶機這一側完成,/boot
應該移動到共享的 9pfs 中,/boot
的新 fstab 條目看上去應該這樣:
virtio-boot /boot 9p trans=virtio,version=9p2000.L,x-systemd.automount 0 0
有了這一步,這只是將 /boot
中的文件混到新的文件系統裡面,並且客戶機完事了(確保 vmlinuz
/initrd.img
保持符號鏈接)。內核可以如常升級,並對主機可見。
這時對於主機端,有另外一個問題需要跨過,由於客戶機使用 9p 映射安全模式,客戶機的符號鏈接對主機而言將是普通的包含鏈接目標的文件。為了解決這個問題,我們在客戶機啟動前使用 libvirt qemu 的 hook 支持來設置合適的符號鏈接。作為一個例子,下面是我們最終使用的腳本(/etc/libvirt/hooks/qemu
):
vm=$1
action=$2
bootdir=/srv/${vm}-boot
if [ ${action} != "prepare" ] ; then
exit 0
fi
if [ ! -d ${bootdir} ] ; then
exit 0
fi
ln -sf $(basename $(cat ${bootdir}/vmlinuz)) ${bootdir}/virtio-vmlinuz
ln -sf $(basename $(cat ${bootdir}/initrd.img)) ${bootdir}/virtio-initrd.img
有了這個,我們可以簡單地定義 libvirt 使用 /srv/${vm}-boot/virtio-{vmlinuz,initrd.img}
作為機器的內核 / initramfs
,並且當 VM 啟動時,它會自動獲取客戶機安裝的最新內核 / initramfs
。
只有最後一個邊緣情況了,當從 VM libvirt 重啟會讓 qemu 處理它而不是重啟 qemu。如果這不幸發生的話,意味著重啟不會載入新內核。所以現在我們通過配置 libvirt 來解決這個問題,從而在重啟時停止虛擬機。由於我們通常只在升級內核(安裝)時重啟 VM,雖然這有點乏味,但這避免了重啟載入的是舊內核 / initramfs
而不是預期的。
via: https://www.collabora.com/news-and-blog/blog/2017/06/20/debian-armhf-vm-on-arm64-server/
作者:Sjoerd Simons 譯者:geekpi 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive