📜 ⬆️ ⬇️

Booting virtual linux machines from a disk without partitions

When creating root disks of virtual machines, usually on them using fdisk / gdisk, a partition table is created with a single partition to host the operating system on it. This causes some trouble on the hypervisor side, for example:


You can get rid of the partition table by directly loading the kernel, but this method is not sinless. The hypervisor should have on its side images of the kernels of virtual machines that need to be kept up-to-date during guest OS updates.
I want to tell you about an alternative boot from a disk without partitions using EFI and GRUB2.

Everything will happen in libvirt, qemu, kvm, Ubuntu.

Summary


The following describes the virtual machine boot in EFI mode from a virtual USB disk in which the directory with the EFI version grub configured to load its menu from a disk without partitions is reflected. Phew ... Plus a pair of rakes on the way.
setting up a libvirt domain to be discussed
<domain type='kvm' id='23'> <name>aster</name> <uuid>d4ee890e-658c-9ff3-6242-9569be3aa154</uuid> <memory unit='KiB'>524288</memory> <currentMemory unit='KiB'>524288</currentMemory> <vcpu placement='static'>1</vcpu> <resource> <partition>/machine</partition> </resource> <os> <type arch='x86_64' machine='pc-i440fx-1.5'>hvm</type> <loader>/opt/ovmf/OVMF.fd</loader> <boot dev='hd'/> </os> <features> <acpi/> <apic/> <pae/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <emulator>/usr/bin/kvm-spice</emulator> <disk type='block' device='disk'> <driver name='qemu' type='raw'/> <source dev='/dev/mapper/ssd-aster--root'/&qt; <target dev='vda' bus='virtio'/> <alias name='virtio-disk0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </disk> <disk type='dir' device='disk'> <driver name='qemu'/> <source dir='/var/spool/efi-grub/'/&qt; <target dev='sda' bus='usb'/> <readonly/> <alias name='usb-disk0'/> </disk> <controller type='pci' index='0' model='pci-root'> <alias name='pci.0'/> </controller> <controller type='usb' index='0'> <alias name='usb0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> </controller> <memballoon model='virtio'> <alias name='balloon0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> </devices> </domain> 


EFI BIOS


And here is the EFI? Downloading in EFI-mode allows us to place grub-efi in a regular file system and does not require an MBR. First of all, we need a BIOS for qemu with EFI support. It is called OVMF . Of all the wealth downloaded, only OVMF.fd is needed (hereinafter, it means that it is / opt / ovmf /). OVMF connects in the os section of the domain with the loader tag:
')
  <os> <type arch='x86_64' machine='pc-i440fx-1.5'>hvm</type> <loader>/opt/ovmf/OVMF.fd</loader> <boot dev='hd'/> </os> 

Loader


Now our virtual machine can boot in a modern way. This method needs a special EFI partition where the loader will be located. Prepare grub-efi:

 mkdir -p /var/spool/efi-grub/efi/boot/ grub-mkimage -O x86_64-efi -d /usr/lib/grub/x86_64-efi/ -o /var/spool/efi-grub/efi/boot/bootx64.efi -p "(hd1)/boot/grub/" part_gpt part_msdos fat ext2 normal chain boot configfile linux multiboot efi_gop efi_uga 

As you can see, there are some features in the location and name of the created loader. The fact is that by default OVMF-BIOS will try to load the file /efi/boot/bootx64.efi from the EFI partition. We will use this and send grub-efi there, which will take its config from the second disk in the system from / boot / grub /. Subsequently, this boot loader can be used for multiple virtual machines, connecting it to the readonly disk and provided that the disk with / boot / grub is second in the system.

EFI section and rake


So, now we need a bootable EFI-partition inside the guest on which we put the bootloader. You can create a small disk, place a partition table GPT and an EFI partition with a bootloader. If this disk is connected in readonly mode, then it will be possible to use one such disk for several virtual machines. But there is a rake. If we place it on the virtio bus, like any normal disk, then when booting we will have a surprise in the form of an EFI-shell instead of a loaded system. Moreover, this shell will be great to see our section and load the bootloader using the “bootx64.efi” command, but without hands, the focus cannot be done. Here the guys discuss in detail and find out why they agree that this is an OVMF bug.
Therefore it is necessary to connect the drive to the ide bus. This is a working version, but disks cannot be readonly. It will be necessary to observe hygiene with respect to this disk inside the guest and (possibly) to say goodbye to the ideas of launching several machines with one loader.
There is a better option.

Reflecting a directory to disk in Qemu

Qemu can create virtual disks from directories. It looks like this:

  <disk type='dir' device='disk'> <source dir='/var/spool/efi-grub/'/&qt; <target dev='sda' bus='usb'/> <readonly/> </disk> 

In this case, a guest disk will appear with a partition table in the MBR, a partition in FAT16 with the contents of the directory on it. This disk has a couple of important features for us - when you connect it, you need the readonly attribute and the section on it is of type 0x06, not 0xEF, as required by EFI. Fortunately, you can boot from such a partition if you hang the disk on the usb bus. In this case, the OVMF-BIOS will look for the bootloader on a regular FAT partition.

And here there is another rake. You get them in the forehead if apparmor is working, and by default it works in Ubuntu.
For each virtual user, libvirt creates an apparmor-profile, which gives it access only to the resources specified in its config. For a disk made from a directory, the rules are incorrect, so it’s worth adding lines to /etc/apparmor.d/abstractions/libvirt-qemu:

 /var/spool/efi-grub/ r, /var/spool/efi-grub/** r, 

Important notes


Now you can create virtuals by creating disks directly on lvm-volumes, easily and safely resize them, do not bother installing the bootloader on new machines deployed with debootstrap, make backup copies of root systems using dump and restore them to a simple restore.

However, there are some limitations. The disks on the usb and ide tires OVMF will always arrange the disks on virtio earlier, and we have hardcooled grub to load the menu and modules from the second disk (we have the disk with the bootloader first):

 grub-mkimage -O x86_64-efi -d /usr/lib/grub/x86_64-efi/ -o /var/spool/efi-grub/efi/boot/bootx64.efi -p "(hd1)/boot/grub/" part_gpt part_msdos fat ext2 normal chain boot configfile linux multiboot efi_gop efi_uga 

We did this with the -p "(hd1) / boot / grub /" parameter. Here (hd1) just points to the second disk (the first, respectively (hd0)). Keep this in mind if you add to the car disks other than virtio.

Also, it must be remembered that grub can dynamically load additional modules from the / boot / grub root partition, and since the guest systems may be different, then the versions of these modules may be incompatible with the bootloader from the EFI partition. You can get rid of this by ponapihav the necessary modules statically by adding their names to the above line.

Source: https://habr.com/ru/post/235133/


All Articles