QEMU - эмулятор процессора

Создан: 22.12.2008
Модиф: 29.04.2021
Иванов Аркадий



     Долгое время для работы с виртуальными машинами я пользовался купленной vmware и бесплатным vmplayer. Однажды обнаружил, что QEMU ( www.qemu.org ) отличная программа - виртуализатор для других систем. Причём оказалось, что она нормально и не конфликтуя с основной системой, вполне понятно работает с сетевыми устройствами и с USB 2.0.  Мне не удалось достичь такой понятности в VMPlayer, а в VirtualBOX OSE просто вы не можете работать с USB 2.0.

Некоторые замечания в этом документе будут упоминать kvm. Это модуль ядра, который базируется на qemu и совместим на уровне команд с qemu.

 

- Сам пакет должен быть установлен: "apt-get install qemu-kvm", либо взят с сайта, сконфигурирован и установлен.
- Ядерный модуль-ускоритель kvm должен быть загружен:

  modprobe kvm
  modpobe kvm-intel
  Чтобы непривилегированный пользователь мог воспользоваться модулем-ускорителем пользователь должен быть в группе kvm.
  Чтобы он автоматом загружался при старте системы, добавьте в /etc/modules строку:

 

Примеры использования

 

- Выделение файла в основной системе, который будет диском в виртуальной системе:

qemu-img create winXP.qcow2 -f qcow2 4096M

   Здесь выдел файл размером в 4Гб. Формат файла - qcow2 (оптимальный, расширяет файл по мере надобности)

 

- Запуск установки Windows на виртуальной машине с CD-ROMа:

  qemu-system-x86_64 -M 256 -hda winXP.qcow2 -cdrom /dev/cdrom -boot d -localtime -smp 4 -cpu host

-M               Память виртуальной машины 256Мб,
-hda            Для 1-го диска(hda) виртуальной машины используем файл winXP.qcow2,
-cdrom        В качестве CD-ROM виртуальной машины используем устройство /dev/cdrom. Если вам удобнее использовать ISO-образ, то 
                   вместо /dev/cdrom укажите имя файла с образом.
-bood d       Загрузочное устройство виртуальной машины - CD-ROM
-d localtime Часы реального времени установить в соответствии с временем локальной машины.
-smp 4        Процессоров на виртуальной машине будет 4.
-cpu host    Тип процессора в виртуальной машине будет типом основной. Это позволит виртуальной машине полностью использовать 
                   возможности основной машины.

Вместо команды qemu-system-x86_64 можно использовать команду kvm:

  kvm -M 256 -hda winXP.qcow2 -cdrom /dev/cdrom -boot d -localtime -smp 4 -cpu host

-

Работа с USB:


  в командной строке следует указать -usbdevice host:058f:6387 и у вас будет подключено в виртуальной машине это устройство.
  Предварительно, конечно, должна быть смонтирована usbfs. Примерно так:

  mount -t usbfs none /proc/bus/usb

  ID устройства можно получить командой lsusb.
  Предварительно следует сделать USB-устройства доступными QEMU, запущенному из под обычного юзера. Для этого из под рута   грубо делаем:

  chmod -R 777 /proc/usb/bus/*  и chmod -R 777 /dev/bus/usb/*

Можно подключить образ диска, сохранённый в файле с именем image.raw, как флешку:

 kvm ... -usbdevice disk:image.raw

 

Настройка сети для QEMU:


- В системе должен быть загружен драйвер tun
    Загрузить его в запущеной системе:

    modprobe tun

    Для того, чтобы он автоматически загружался после перезапуска в /etc/modules добавляется строка:
    tun


- Установить пакет bridge-utils :

   apt-get install bridge-utils

- При перезагрузке должен быть сделан мост из реального ethernet-контроллера (eth0) и псевдо ethernet-контроллера (tap1).
    Если Ethernet-устройство называется eth0 и имеет адрес 192.168.1.1, то команды  создания моста следующие:

# Отключу eth0

    ifconfig eth0 0.0.0.0 promisc         # (устарело)
    ip addr replace 0.0.0.0/0 dev eth0
    ip link set eth0 up

# Создам псевдо ethernet-интерфейс tap1 и отдаём права на него юзеру "arc" (тому  юзеру, из под которого будет запускаться qemu).

    tunctl -t tap1 -u arc                  # (устарело)
    ifconfig tap1 0.0.0.0 up               # (устарело)
    ip tuntap add tap1 mode tap user arc
    ip link set tap1 up

# Создам мост br0 и добавлю в него eth0

    brctl addbr br0                         # (устарело)
    brctl addif br0 eth0                    # (устарело)
    ip link add br0 type bridge             # создаю мост br0
    ip link set eth0 master br0             # добавляю в мост br0 интерфейс eth0

# В этот же мост добавлю tap1

    brctl addif br0 tap1                    # (устарело)
    ip link set tap1 master br0             # добавляю в мост br0 интерфейс tap1

# Назначу IP мосту (обычно это тот адрес, что раньше был у нашего физического интерфейса eth0)

   ifconfig br0 192.168.1.1 netmask 255.255.255.0 up  (устарело)
   ip addr add 192.168.1.1/24 dev br0
   ip link set br0 up


- Запуск QEMU с поддержкой сети выглядит так:

kvm ... -net tap,ifname=tap1,script=no -net nic  #устарело
kvm ... -device virtio-net-pci,netdev=id1,mac=00:00:00:00:01:00 -netdev tap,id=id1,ifname=tap1,script=no

В самой гостевой системе стандартными средствами системы назначаем её ethernet-контроллеру нужный мне IP-адрес.

Если вам не нужен режим моста, то, устройство tap1 вы создаёте, внутри гостевой системы вы имеете сетевой интерфейс,
назначаете ему IP и устройству tap1 из одной сети, а маршрутизацию в вашей основной сети решаете так, как вам будет удобно.

 

Одновременная работа с сетью нескольких гостевых систем

 

Для каждого интерфейса в каждой гостевой системе следует создать отдельное устройство псевдо ethernet-контроллера (TAP) и добавить его в мост (если мост вообще нужен). Пример:

...
tunctl -t tap1 -u arc       #устарело
ifconfig tap1 0.0.0.0 up    #устарело
tunctl -t tap2 -u arc       #устарело
ifconfig tap2 0.0.0.0 up    #устарело
...
brctl addif br0 tap1        #устарело
brctl addif br0 tap2        #устарело
...

ip tuntap add tap1 mode tap user arc
ip link set tap1 up
ip tuntap add tap2 mode tap user arc
ip link set tap2 up
...
ip link set tap1 master br0

Если не предпринять ничего дополнительно, то интерфейсы гостевых систем будут иметь MAC-адрес реального ethernet-контроллера eth0, который является частью моста. В результате IP-пакеты между гостевыми машинами ходить не будут. Чтобы этого избежать, при старте виртуальной машины следует указать свой собственный MAC-адрес для каждого TAP-интерфейса. Пример:

kvm ... -net tap,ifname=tap1,script=no -net nic,macaddr=00:00:00:00:00:01 #устарело
kvm ... -net tap,ifname=tap2,script=no -net nic,macaddr=00:00:00:00:00:02 #устарело
kvm ... -device virtio-net-pci,netdev=id1,mac=00:00:00:00:01:00 -netdev tap,id=id1,ifname=tap1,script=no
kvm ... -device virtio-net-pci,netdev=id2,mac=00:00:00:00:01:01 -netdev tap,id=id2,ifname=tap2,script=no 

 

Замечание для гостевых систем Linux с UDEV: 
UDEV запоминает MAC-адрес и в соответствии с ним присваивает имя сетевому интерфейсу.

В моём случае с AltLinux-ом соответствие прописано в файле /etc/udev/rules.d/70-persistent.net.rules.

Если вы поменяете MAC при старте kvm, udev пропишет в этот файл дополнительное устройство и даст ему имя eth1. Последующие скрипты (обычно это подсистема etcnet), инициализирующие сеть, вряд ли смогут справиться с этим переименованием. Так что, если поменяли MAC, правьте xxx.net.rules.

 

Несколько интерфейсов в гостевой системе:

Можно использовать до 6 интерфейсов в гостевой системе. Их создание в командной строке:

kvm ... -net tap,ifname=tap0,script=no  -net nic  -net nic ... -net nic

 

Если необходимо использовать разные сетевые интерфейсы хоста для разных интерфейсов гостя, используется опция vlan:

kvm ... -net tap,ifname=tap0,script=no,vlan=0  \
-net tap,ifname=tap1,script=no,vlan=1 -net nic,vlan=0  -net nic,vlan=1

 

Очень полезные фишки:

- Можно запустить гостевую систему без графики в хост-системе. Т.е. вам не нужно запускать X-сервер. Ключ -nographics.

- Можно оставить графику в фоне и иметь к ней доступ через VNC. Пример ключа:   -vnc   :2
  :2 - это номер графического дисплея, к которому надо будет цепляться с помощью vncviewer.

- При запуске без графики и подключении через vncclient есть баг в разнице движений реальной и виртуальной мыши по экрану. Чтобы его не было, используйте дополнительный ключ:

  -usbdevice tablet

- Вот пример команды с запуском без графики и с доступом через VNC:

kvm  sys1.qcow -boot c -nographics -vnc :3 -usbdevice tablet

В данном примере экран виртуальной машины будет доступен через команду:

vncclient hostname:3

, где hostname - имя компьютера, где вы запустили виртуальную машину.

 

Иногда нужно провести изменения на диске виртуальной машины не запуская её.
Для образов дисков в формате qcow2, используя устройство nbd (network block device), монтировать образ можно так:

modprobe nbd max_part=63
qemu-nbd -c /dev/nbd0 vmdisk.qcow2
mount /dev/nbd0p1 /mnt/partition1

Здесь первый раздел на виртуальном диске будет смонтирован на каталог /mnt/partition1
 

Если работа ведётся с raw-образом диска, то используем losetup:

losetup /dev/loop0 image.raw
mount /dev/loop0p1 /mnt/partition1

 

Оптимизация скорости работы виртуальной машины:
 

Если всё делать стандартно, скорость сети у меня получалась на уровне 1Mбайт/сек, да и виртуальный диск не больно то шустрый.

Лечится эта проблема с помощью того, что в гостевой системе используются драйверы virtio для сетевой карты и контроллера дисков, а KVM на хосте запускается

с указанием использования этого оборудования:

kvm  -drive file=linuxguest.qcow,if=virtio -net tap,ifname=tap1,script=no -net nic,model=virtio

 

На 100 мегабитной сети скорость в виртуальной машине у меня не уступала скорости работы сети на хост-системе.

 

Модули virtio есть и для Windows. Скачивайте из Интернета.

Основная ссылка для модулей: http://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/

Пред. версия драйверов, которые без проблем у меня заработали в гостевой Win XP: http://autosetup1.googlecode.com/files/virtio-win-1.1.16.vfd

 

Установка virtio в Windows довольно забавная, поскольку контроллер основного диска Windows ничего про virtio не знает.

Процедура следующая:

1. При запуске kvm указываю образ floppy-диска, где лежат драйвера, и указываю для CD-привода интерфейс virtio:

kvm -drive=win.qcow2,media=disk \
-drive file=/VM/kvm/virtio-win-1.1.11-0.vfd,media=disk,if=floppy \
-drive file=/VM/kvm/virtio-win-1.1.11-0.iso,media=cdrom,if=virtio

Тем самым я заставляю Windows поставить Virtio-драйвер для CD-диска (драйвер беру с флоппика).

2. Перезагружаюсь, указывая интерфейс virtio уже и для основного диска:

kvm -drive=win.qcow2,media=disk,if=virtio \
-drive file=/VM/kvm/virtio-win-1.1.11-0.vfd,media=disk,if=floppy

Windows автоматически использует ранее установленные драйвера и для основного диска.

 

Оптимизации для дисплея виртуальной машины.

То, что дополнительно надо для комфортной работы с виртуальной системой - это настройка всевозможных разрешений экрана и копирование текста между программами виртуальной машины и основной.

  • Это задача решается так:
    В параметрах запуска гостя для VGA-устройства выбирается тип QXL:
    -vga qxl
  • В гостевую систему ставятся дополнительные драйвера. На момент написания этого руководства я воспользовался spice-guest-tools-0.74.exe с сайта www.spice-space.org. 

 

Проброс USB-устройств по сети:

 Это важная и полезная фича для виртуализации. Последний раз тренировался в Ubuntu 12.04 с PPA-репозиторием от Бориса Державеца.

Вот ссылка на его репозиторий:

deb http://ppa.launchpad.net/bderzhavets/lib-usbredir87/ubuntu precise main

Всё нужно делать при помощи SPICE-сервера (KVM можно запустить с его поддержкой) и SPICE-клиента (в Linux это, например, программа spicy).

С помощью GUI программы virt-manager можно настроить и запустить KVM с поддержкой SPICE и поиграться с настройками виртуализации.

Я предпочитаю запускать виртуальную машину из командной строки. Вот пример строки для запуска машины:

/usr/bin/kvm \
-enable-kvm \
-M 512 \
-smp 1,sockets=1,cores=1,threads=1 \
-name finereader \
-uuid e6026421-2e39-aba5-013f-7eb6a7f5ccf3 \
-boot order=c \
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/finereader.monitor,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=localtime \
-no-shutdown \
-device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
-device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x7.0x7 \
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x7 \
-drive file=/VM/kvm/winFineReader.qcow2,media=disk,index=0,format=qcow2,if=virtio \
-drive file=/VM/kvm/virtio-win-1.1.11-0.vfd,media=disk,if=floppy \
-net tap,ifname=tap73,script=no -net nic,macaddr=00:00:00:02:11:01,model=virtio \
-chardev pty,id=charserial0 \
-device isa-serial,chardev=charserial0,id=serial0 \
-chardev spicevmc,id=charchannel0,name=vdagent \
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 \
-device usb-tablet,id=input0 \
-spice port=5900,addr=0.0.0.0,disable-ticketing \
-device intel-hda,id=sound0,bus=pci.0,addr=0x4 \
-device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 \
-chardev spicevmc,id=charredir0,name=usbredir \
-device usb-redir,chardev=charredir0,id=redir0 \
-chardev spicevmc,id=charredir1,name=usbredir \
-device usb-redir,chardev=charredir1,id=redir1 \
-chardev spicevmc,id=charredir2,name=usbredir \
-device usb-redir,chardev=charredir2,id=redir2 \
-chardev spicevmc,id=charredir3,name=usbredir \
-device usb-redir,chardev=charredir3,id=redir3 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 &

 

Здесь указано использование USB 2.0 контроллера, 4 Spice-канала для подключения.

В командной строке spicy указываю:

spicy -h remoteserver -p 5900

 

remoteserver - машина, где работает kvm.

Порт для SPICE-протокола используется 5900.

 

На локальном хосте в меню spicy выбираем:

[Input] -> [Select USB device for redirection]

 

и выбираю устройство для проброса на виртуальную машину.

 

Примечание: Для того, чтобы spicy не пугала юзеров локальных машин просьбами ввести пароль root-а при пробросе USB, изменяю политику в файле:

/usr/share/polkit-1/actions/org.spice-space.lowlevelusbaccess.policy
Cтроку:
<allow_active>auth_admin_keep</allow_active>
заменяю на:
<allow_active>yes</allow_active>

 

Backup работающей системы:

Для управления гостевой системой в командной строке запуска QEMU можно указать монитор, через который можно передавать команды. Вот ключ командной строки:

-monitor telnet:localhost:4444,server=on,wait=off
 

Чтобы подключиться к работающей QEMU, использую telnet:

telnet localhost 4444

Получаю подсказку (qemu). Можно вводить команды. Их много. Есть help.

Для начала посмотрю какие у меня есть диски и как они называются в QEMU:

(qemu) info block
virtio1 (#block183): /backup0/tmp/vm/ubuntu-server-min-20.04.qcow2 (qcow2)
   Attached to:      /machine/peripheral-anon/device[0]/virtio-backend
   Cache mode:       writeback

ide1-cd0: [not inserted]
   Attached to:      /machine/unattached/device[24]
   Removable device: not locked, tray closed

floppy0: [not inserted]
   Attached to:      /machine/unattached/device[17]
   Removable device: not locked, tray closed

sd0: [not inserted]
   Removable device: not locked, tray closed
(qemu)

 

Меня интересует диск virtio1. Его и буду бэкапить командой:

drive_backup virtio1 /backup0/tmp/vm/test.img qcow2

В результате получу точный образ диска virtio1 виртуальной машины в файле test.img на момент издания команды. Формат диска будет qcow2.

 

Чтобы запустить бэкап из командной строки системы, использую программу nc:

echo "drive_backup virtio1 /backup0/tmp/vm/test.img qcow2" |nc -N localhost 4444