arm64 伺服器中的 Debian armhf 虛擬機器

Sjoerd Simons發表於2017-07-04

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 虛擬機器作為從構建伺服器build slaves似乎是一個很好的選擇,但是設定起來可能會需要更多東西的介入。

第一個陷阱是 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 安裝程式提供的 vmlinuzinitrd.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

本文由 LCTT 原創編譯,Linux中國 榮譽推出

相關文章