QEMU KVM as a service

Now it is possible to start a virtual machine as a service at boot time, but you need to create it as SMF service. We assume that you have installed kvm package as:

dev0# apt install kvm

This is a meta-package which installs all required packages and the SMF service. After reboot you will see default instance of the kvm service:

dev0# svcs kvm
STATE          STIME    FMRI
disabled       18:18:16 svc:/system/kvm:default

Don't try to enable it, it will not start, anyway, it is a template only for default parameters that you don't configure. Let's create one.

First you need to add an instance of the service, type in the command line:

dev0# svccfg -s kvm add vm01

Now you need to create 3 groups of properties: hvm, net and disks:

dev0# svccfg -s kvm:vm01 addpg hvm application 
dev0# svccfg -s kvm:vm01 addpg net application
dev0# svccfg -s kvm:vm01 addpg disk application

Now you can configure the new VM. Specify amount memory size:

dev0# svccfg -s kvm:vm01 setprop hvm/mem = astring: 1g

By default the size is set to 512m. Create a zvol for the new VM and add it to the service:

dev0# zfs create -b 4k -V 10g data/kvm/disk0
dev0# svccfg -s kvm:vm01 setprop disk/disk0 = astring: disk0
dev0# svccfg -s kvm:vm01 addpg disk0 application
dev0# svccfg -s kvm:vm01 setprop disk0/zvol = astring: data/kvm/disk0        

Second command specifies a "label" of the disk, in our example it is disk0, but you can choose something else. This label point to another program group which is created in next line. The latest command adds our new zvol as the disk device in the new section. By default, the model of disk is virtio.

In the real world we need a network for our VM, let's do it:

dev0# svccfg -s kvm:vm01 setprop net/net0 = astring: net0

This command adds a lablel of the network, like we did it for disks. Now configure the new section:

dev0# svccfg -s kvm:vm01 addpg net0 application
dev0# svccfg -s kvm:vm01 setprop net0/name = astring: vnic0
dev0# svccfg -s kvm:vm01 setprop net0/link = astring: zsw0
dev0# svccfg -s kvm:vm01 setprop net0/ip = astring: 172.16.0.10
dev0# svccfg -s kvm:vm01 setprop net0/netmask = astring: 255.255.255.0
dev0# svccfg -s kvm:vm01 setprop net0/gateway = astring: 172.16.0.1
dev0# svccfg -s kvm:vm01 setprop net0/dns0 = astring: 10.20.30.1
  • net0/link defines a VNIC for the VM
  • net0/link defines the parent NIC for the vnic
  • net0/ip defines an IP-address which will be assigned to the nic inside VM (as DHCP)
  • net0/netmask define the netmask for the network
  • net0/gateway is the default router for the network
  • net0/dns0 is an IP-address of your name server

You need to refresh the data:

dev0# svccfg -s kvm:vm01 refresh

That's all, you are ready to start our new VM:

dev0# svcs kvm
STATE          STIME    FMRI
disabled       18:18:16 svc:/system/kvm:default
-              -        svc:/system/kvm:vm01
dev0# svcadm enable kvm:vm01
dev0# svcs kvm
STATE          STIME    FMRI
disabled       18:18:16 svc:/system/kvm:default
online         21:55:01 svc:/system/kvm:vm01

But wait, you may say that the VM is not installed yet, what does it boot?

Right! Don't worry, let's configure it at run-time, first you need to see the output, i.e. create a VNC server, you need to connect the control monitor and change it:

dev0# nc -U /var/run/kvm/vm01/ctl
QEMU 0.14.1 monitor - type 'help' for more information
(qemu)

At start time the service creates a working directory to store there some control files such as a socket, pid-file, console, vnc socket. These files used to control the VM, let's use it too!

First, let's configure our vnc:

(qemu) info vnc
info vnc
(qemu) change vnc ::5900
change vnc ::5900
(qemu) info vnc
info vnc
Server:
     address: :::5900
        auth: none
Client: none
(qemu) 

By default we use a UNIX socket for VNC server but here we changed it and assign port 5900, second query shows us that the VM is now configured as a vnc server.

Now we need a boot device, let's add a removable cd-rom to boot:

(qemu) info block
info block
virtio0: type=hd removable=0 file=/dev/zvol/rdsk/data/kvm/disk0 ro=0 drv=raw encrypted=0
ide1-cd0: type=cdrom removable=1 locked=0 [not inserted]
floppy0: type=floppy removable=1 locked=0 [not inserted]
sd0: type=floppy removable=1 locked=0 [not inserted]
(qemu) change ide1-cd0 /export/home/denis/ISO/FreeBSD-11.2-RELEASE-amd64-disc1.iso
change ide1-cd0 /export/home/denis/ISO/FreeBSD-11.2-RELEASE-amd64-disc1.iso
(qemu) info block
info block
virtio0: type=hd removable=0 file=/dev/zvol/rdsk/data/kvm/disk0 ro=0 drv=raw encrypted=0
ide1-cd0: type=cdrom removable=1 locked=0 file=/export/home/denis/ISO/FreeBSD-11.2-RELEASE-amd64-disc1.iso ro=0 drv=raw encrypted=0
floppy0: type=floppy removable=1 locked=0 [not inserted]
sd0: type=floppy removable=1 locked=0 [not inserted]
(qemu)

Unfortunately, to boot the system you need to reset it:

(qemu) system_reset
system_reset
(qemu)

In some time you will see the booted system:

Bingo! It works! (wink)

Boot options example:

dev0# svccfg -s kvm:vm01 addpg boot application
dev0# svccfg -s kvm:vm01 setprop boot/order = astring: cd
dev0# svccfg -s kvm:vm01 setprop boot/once = astring: d
dev0# svccfg -s kvm:vm01 setprop boot/menu = astring: on


Serial properties example:

dev0# svccfg -s kvm:vm01 addpg serial application
dev0# svccfg -s kvm:vm01 setprop serial/type = astring: telnet
dev0# svccfg -s kvm:vm01 setprop serial/mode = astring: server
dev0# svccfg -s kvm:vm01 setprop serial/option = astring: nowait
dev0# svccfg -s kvm:vm01 setprop serial/bind = astring: localhost:4444

By default we create a UNIX socket for the serial console (/var/run/kvm/vm01/console). You may use nc -U to connect it (like for control socket).


VNC

For a security reason we use a UNIX socket for the VNC server too. At any time you can change it as shown above but the better way is to use noVNC project to connect it. To do it you need a web socket proxy:

dev0# apt install -y novnc websockify

And start it:

dev0# websockify --web=/usr/share/novnc/ 6080 --unix-target=/var/run/kvm/vm01/vnc -D

The proxy will redirect all queries from the port 6080 to the specified UNIX socket. Also you can read about it here: How To use noVNC on DilOS

APPENDIX

HVM configurable properties:

  • hvm/cpu - emulating cpu type (qemu64 by default)
  • hvm/smp - number of cpus (1)
  • hvm/cores - number of processor cores (1)
  • hvm/threads - number of processor threads (1)
  • hvm/sockets - number of processor sockets (1)
  • hvm/mem - amount memory size for the VM (512M)
  • hvm/vga - type of the video device (std)

Network configurable properties:

  • netX/name - name of VNIC
  • netX/link - parent interface for the vnic
  • netX/model - emulating model of the nic (virtio)
  • netX/mac - ethernet address of the nic, it it generated value if you did not specify it
  • netX/vlan - VLAN id if the parent interface is a trunk

You don't need to create a VNIC manually using dladm, also you don't need to create a vnd device. The service will do it for you automatically. Also the will be removed when you disable the service for your VM. You may not specify the name of VNIC, the service does it for you too. A new vnic will be named kvmX (where X is a unused number, if you already have lot of such interfaces). Cool, isn't it? (smile)

Disk configurable properties:

  • diskX/zvol - name of zvol which will be used as storage device for the VM
  • diskX/model - emulating model of the interface (virtio)
  • diskX/serial - serial no of the device (yes, we can specify it too!)

Boot options:

  • boot/order - devices order to boot the VM
  • boot/once - used to boot the VM only once (at first boot)
  • boot/menu - used to choose boot device at boot time (on/off)

Serial console properties:

  • serial/type - type of the connection (unix/tcp/udp/telnet)
  • serial/mode - mode of the connection (should be server or leave it empty)
  • serial/option - comma separated options of the connection (nowait,nodelay)
  • serial/path - UNIX socket full path (/var/run/kvm/vm01/console)
  • serial/bind - use this address:port pair where server is listen connections (empty by default)
  • serial/target - use this address:port pair to send all console data to this point (for tcp client type, for example)