virt-install 实现了网络安装的机制,并讨论了libosinfo

首先

virt-install是一個用於創建虛擬機並安裝操作系統的命令。如果要安裝的操作系統是Linux,則可以通過在–location中指定URL而不需要下載ISO映像來直接從網絡安裝。我關心的是這個URL後面的目錄結構。從執行日誌中可以知道正在下載特定的文件,但到底下載哪個文件呢?又是如何搜索這個文件的?如果目錄結構有某種規定,我就能理解了,但似乎各個發行版的目錄結構都不同。因為不了解這個機制,所以我查了一下。

创建虚拟机的示例

您可以使用以下命令创建虚拟机(操作系统为Debian 12)。由于使用了串行控制台,您可以直接在终端上进行安装操作,并且安装完成后还可以通过 virsh console 进行连接。

virt-install --name deb12 --osinfo debian12 \
  --vcpus 1 --memory 2048 --disk size=10 --network bridge=br0 --graphics none \
  --extra-args 'console=ttyS0,115200n8 --- console=ttyS0,115200n8' \
  --location 'http://deb.debian.org/debian/dists/bookworm/main/installer-amd64'

# 補足 ローカルにダウンロードした ISO ファイルからインストールする場合
virt-install --name deb12 --osinfo debian12 \
  --vcpus 1 --memory 2048 --disk size=10 --network bridge=br0 --graphics none \
  --extra-args 'console=ttyS0,115200n8 --- console=ttyS0,115200n8' \
  --location '/var/isos/debian-12.0.0-amd64-DVD-1.iso'

在Debian中安装时,最后会询问grub的安装位置(用于引导加载程序安装的设备)。请选择/dev/vda而不是默认的手动输入(Enter device manually)。

# 参考 上記で作成した仮想マシンをデータごと削除する場合
virsh destroy deb12; virsh undefine deb12 --remove-all-storage

以下是执行virt-install时显示的信息的开头部分。可以看出正在通过网络下载Linux和initrd.gz。

Starting install...
Retrieving 'linux'                                    | 7.6 MB  00:00:12 ...
Retrieving 'initrd.gz'                                |  38 MB  00:01:07 ...
Allocating 'virtinst-fqgrlje6-linux'                  |    0 B  00:00:00 ...
Transferring 'virtinst-fqgrlje6-linux'                |    0 B  00:00:00 ...
Allocating 'virtinst-2xg9sfwe-initrd.gz'              |    0 B  00:00:00 ...
Transferring 'virtinst-2xg9sfwe-initrd.gz'            |    0 B  00:00:00 ...
Allocating 'deb12.qcow2'                              |    0 B  00:00:00 ...
Creating domain...                                    |    0 B  00:00:00
Running text console command: virsh --connect qemu:///system console deb12
Connected to domain 'deb12'
Escape character is ^] (Ctrl + ])
(以下 Linux のブートログが出力される)

在位置上指定的是 http://deb.debian.org/debian/dists/bookworm/main/installer-amd64。根据URL目录结构可以看出,这相当复杂,最终下载以下路径的文件。但是,virt-install是如何知道这个路径的呢?

    current/images/netboot/debian-installer/amd64/linux
    current/images/netboot/debian-installer/amd64/initrd.gz

解開这个谜题的关键是–osinfo debian12。virt-install会参考操作系统数据库来创建虚拟机,并从该信息中获取文件路径。

虚拟机安装程序 virt-install 的不推荐选项”おまけ”。

virt-install的选项名称与以前相比已经有了很大变化。在搜索过程中经常会找到使用旧选项的例子,所以在这里做个备忘录。

現在のオプション 古いオプション --osinfo --os-variant--os-type --memory -r/--ram --metadata -u/--uuid--description --cdrom <ISO> --install no_install=yes --live --disk -f/--file-s/--file-size
--nonsparse--nodisks --network -m/--mac-b/--bridge--nonetworks --graphics --vnc--vncport--vnclisten-k/--keymap--sdl--nographics --virt-type (デフォルトの動作) --accelerate --sound --soundhw

libosinfo (osinfo) 是什么?

libosinfo是一个项目,提供有关操作系统的数据库和API,以帮助创建虚拟机。使用–osinfo选项可以确定适合指定操作系统的默认配置。以下是virt-install –help命令的部分输出。

$ virt-install --help
 ︙
OS options:
  --os-variant OS_VARIANT, --osinfo OS_VARIANT
                        The OS being installed in the guest.
                        This is used for deciding optimal defaults like VirtIO.
                        Example values: fedora29, rhel7.0, win10, ...
                        Use '--osinfo list' to see a full list.
 ︙

補充一下,當在 virt-install 中指定 ? 作為某些選項時,它將輸出該選項的子選項。

$ virt-install --osinfo=? # --osinfo のパラメータ
--os-variant options:
  detect
  id
  name
  require
  short-id

你可以使用virt-install –osinfo list命令来列举支持的操作系统类型,但其输出的末尾提到了可以使用osinfo-query os来获取附加信息。

$ virt-install --osinfo list # 対応している OS の種類の出力
almalinux9
almalinux8
alpinelinux3.18
alpinelinux3.17
 ︙
winvista
winxp

You can see additional information with:

  osinfo-query os

osinfo-query命令是什么意思?

使用osinfo-query命令可以获得如下信息。

$ osinfo-query os
 Short ID        | Name               | Version | ID
-----------------+--------------------+---------+-----------------------------------------
 almalinux8      | AlmaLinux 8        | 8       | http://almalinux.org/almalinux/8
 almalinux9      | AlmaLinux 9        | 9       | http://almalinux.org/almalinux/9
 alpinelinux3.10 | Alpine Linux 3.10  | 3.10    | http://alpinelinux.org/alpinelinux/3.10
 alpinelinux3.11 | Alpine Linux 3.11  | 3.11    | http://alpinelinux.org/alpinelinux/3.11
 ︙

当您指定参数时,可以方便地查询发布日期和支持终止日期。然而,我感觉它并没有立即反映最新数据的样子。

$ osinfo-query os vendor="Debian Project" -s release-date \
  -f short-id,vendor,release-date,eol-date

 Short ID             | Vendor                    | Release date | End of life
----------------------+---------------------------+--------------+-------------
 debian1.2            | Debian Project            | 1996-12-12   | 1998-06-05
 debian1.3            | Debian Project            | 1997-06-05   | 1999-03-09
 debian2.0            | Debian Project            | 1998-07-24   | 2000-03-09
 debian2.1            | Debian Project            | 1999-03-09   | 2000-10-30
 debian2.2            | Debian Project            | 2000-08-15   | 2003-06-30
 debian3              | Debian Project            | 2002-07-19   | 2006-06-30
 debian3.1            | Debian Project            | 2005-06-06   | 2008-03-31
 debian4              | Debian Project            | 2007-04-08   | 2010-02-15
 debian5              | Debian Project            | 2009-02-14   | 2012-02-06
 debian6              | Debian Project            | 2011-02-06   | 2016-02-29
 debian7              | Debian Project            | 2013-05-04   | 2018-05-31
 debian8              | Debian Project            | 2015-04-25   | 2020-06-30
 debian9              | Debian Project            | 2017-06-17   | 2022-06-30
 debian10             | Debian Project            | 2019-07-06   |
 debian11             | Debian Project            | 2021-08-14   |
 debian12             | Debian Project            |              |
 debiantesting        | Debian Project            |              |
 debian1.1            | Debian Project            | 1996-07-17   | 1997-06-05

(release-dateでソートしたはずなのになぜdebian1.1は最後にでてるの?)

虚拟安装程序virt-install利用libosinfo的信息,并不拥有自身的操作系统数据库。然而,实际情况可能并不那么简单,尽管我没有详细阅读过相关内容,但基本上他们会获取libosinfo的信息,但在某些操作系统中可能会进行特殊处理。

def _build_distro_list(osobj):
    allstores = [
        # Libosinfo takes priority
        _LibosinfoDistro,
        _FedoraDistro,
        _RHELDistro,
        _CentOSDistro,
        _SLESDistro,
        _SLEDDistro,
        _OpensuseDistro,
        _DebianDistro,
        _UbuntuDistro,
        _MageiaDistro,
        # Always stick GenericDistro at the end, since it's a catchall
        _GenericTreeinfoDistro,
    ]

查看 osinfo-db 的内容

libosinfo在Debian操作系统中的OS信息存储在/usr/share/osinfo/os/目录下。

$ ls -al /usr/share/osinfo/os/
total 216
drwxr-xr-x 54 root root 4096 Jun 24 12:29 .
drwxr-xr-x  8 root root 4096 Jun 24 12:29 ..
drwxr-xr-x  2 root root 4096 Jun 24 12:29 almalinux.org
drwxr-xr-x  2 root root 4096 Jun 24 12:29 alpinelinux.org
drwxr-xr-x  2 root root 4096 Jun 24 12:29 altlinux.org
 ︙

这里有布置着XML文件,但是可以通过osinfo-db从中获取相同的信息。看起来以前这些信息被包含在libosinfo中,但是现在似乎将数据分离为独立的项目。虽然我没有尝试过,但是如果将这些数据下载到本地并指定环境变量OSINFO_SYSTEM_DIR(旧名为OSINFO_DATA_DIR),应该能使用最新的数据。这可能在旧环境中想要安装新操作系统时会有用。详细信息可在libosinfo: The Operating System information database中找到。可能会使用osinfo-db-import命令。

看一下 debian12 数据中的 debian-12.xml.in 文件,可以看到下面写着下载文件路径的内容。看起来从这里获取了内核和 initrd 的路径。

    <tree arch="x86_64">
      <url>http://deb.debian.org/debian/dists/bookworm/main/installer-amd64</url>
      <kernel>current/images/netboot/debian-installer/amd64/linux</kernel>
      <initrd>current/images/netboot/debian-installer/amd64/initrd.gz</initrd>
    </tree>

只要到这里,接下来只需要读取 XML 文件。可以知道文件中包含了各种信息。通过查看这些信息,也可以知道应该把哪个 URL 指定给 –location 参数。顺便提一下,上述的 地址(可能)在 virt-install 中并不会使用。也许从 –ososinfo 的值来默认选择这个 地址也不错,但为了减轻负荷,应该是建议使用相同结构的镜像。

现在可以从每个操作系统的XML文件中得到一个事实。至少目前为止,使用–location选项进行安装在Linux之外的操作系统中是不支持的。其他操作系统不包含等相应的数据。即使在Linux中,也似乎存在一些不支持的情况。因此,在其他操作系统上使用串行控制台进行安装可能会更加困难。也许有其他的方法,但是我认为它不会像Linux那样简单。

关于osinfo-detect命令

osinfo-detect命令是libosinfo库附带的一个方便的工具。您可以使用它来检查指定的ISO文件是否可启动,以及(如果有的话)它是哪个操作系统的安装程序。如果指定了PATH或URI,您还可以检查指定的目录结构是哪个操作系统的安装程序。如果指定了PATH或URI,似乎会确认是否存在.treeinfo(可能是隐藏文件,看不见的情况)或treeinfo文件。

$ osinfo-detect debian-12.0.0-amd64-DVD-1.iso
Media is bootable.
Media is an installer for OS 'Debian 12 (x86_64)'

$ osinfo-detect FreeBSD-12.4-RELEASE-amd64-disc1.iso
Media is bootable.
Media is an installer for OS 'FreeBSD 12.4 (x86_64)'
$ osinfo-detect FreeBSD-13.2-RELEASE-amd64-disc1.iso # 起動可能かしかわからない
Media is bootable.

$ osinfo-detect --type tree 'https://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/'
Tree is an installer for OS 'AlmaLinux 9 (x86_64)'

$ curl 'https://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/.treeinfo'
[checksums]
images/boot.iso = sha256:f501de55f92e59a3fcf4ad252fdfc4e02ee2ad013d2e1ec818bb38052bcb3c32
images/efiboot.img = sha256:7239e305f99a67fb41068b92f29d030f8b44d6775df00a3de509cb620cefd89d
images/install.img = sha256:5b8202efb6f679a273fdd9b52d7b1e092fcd36d056980939e29a1b6087415d1f
images/pxeboot/initrd.img = sha256:d134cc209cd17a6764ba7d17846742a320da27850c070dc6c2d4372fe273e82d
images/pxeboot/vmlinuz = sha256:c09cd123fd96d36e565a5983d22f448f03be675f84f2e6d20be6579087102338

[general]
arch = x86_64
family = AlmaLinux
name = AlmaLinux 9
packagedir = Packages
platforms = x86_64,xen
repository = .
timestamp = 1683740651
variant = BaseOS
variants = AppStream,BaseOS
version = 9

[header]
type = productmd.treeinfo
version = 1.2

[images-x86_64]
boot.iso = images/boot.iso
efiboot.img = images/efiboot.img
initrd = images/pxeboot/initrd.img
kernel = images/pxeboot/vmlinuz

[images-xen]
initrd = images/pxeboot/initrd.img
kernel = images/pxeboot/vmlinuz

[release]
name = AlmaLinux
short = AlmaLinux
version = 9

[stage2]
mainimage = images/install.img

[tree]
arch = x86_64
build_timestamp = 1683740651
platforms = x86_64,xen
variants = AppStream,BaseOS

[variant-AppStream]
id = AppStream
name = AppStream
packages = ../../../AppStream/x86_64/os/Packages
repository = ../../../AppStream/x86_64/os
type = variant
uid = AppStream

[variant-BaseOS]
id = BaseOS
name = BaseOS
packages = Packages
repository = .
type = variant
uid = BaseOS

关于 osinfo-install-script 命令,请给出一种中文翻译选项:

osinfo-install-script 命令可能是一个生成自动安装文件(如 kickstart script)的程序。(仍未?)使用过并且执行 EXAMPLE USAGE 也报错,所以并不了解它的用法。我只是简单介绍一下它的存在。虽然我还没有进行过详细的调查,但我想对于了解的人来说,他们可能知道它默认生成 JEOS 风格脚本的功能。请有经验的人总结一下用法。

最后

我知道可以使用virt-install通过URL进行安装,但我一直不清楚应该指定什么样的URL以及目录结构是什么样的,一直感到困惑。正好有机会重新构建虚拟机,我把这些总结了一下。

bannerAds