Balling’s Bits

Run a QEMU/KVM Virtual Machine in an OmniOS Zone

It is possible to run QEMU/KVM virtual machines inside an OmniOS zone but it requires that the kvm kernel module is made available to the zone. Also, any raw volumes for the virtual machines must be made available to the zone. Here is an example zone configuration file for a QEMU/KVM capable zone:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
create -b
set zonepath=/tank/zones/example
set ip-type=exclusive
set autoboot=true
add net
set physical=dmzexample0
end
add net
set physical=dmzexample1
end
add device
set match=/dev/kvm
end
add device
set match=/dev/zvol/dsk/tank/zones/kvmexample-vol
end
commit

The set match=/dev/kvm makes the kernel kvm module available to the zone and the set match=/dev/zvol/dsk/tank/zones/kvmexample-vol makes the zfs volume tank/zones/kvmexample-vol available in the zone.

The presence of two virtual network interfaces (dmzexample0 and dmzexample1) makes it possible to use one for the zone (and thus VNC into the virtual machine) and the other for the virtual machine.

A sample QEMU/KVM configuration script (/root/kvmexample.sh), in this case for a Plex Media Server, could look like this (ubuntu 14.04 iso mounted in the zone at med/iso via nfs):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
NAME=kvmexample
VNIC0=dmzexample1
HDD0=/dev/zvol/dsk/tank/zones/kvmexample-vol
CD=/med/iso/ubuntu-14.04-server-amd64.iso
VNC=1
MEM=8192

mac0=`dladm show-vnic -po macaddress $VNIC0`

/usr/bin/qemu-system-x86_64 \
-name $NAME \
-boot cd \
-enable-kvm \
-vnc 0.0.0.0:$VNC -k da \
-smp cores=10,threads=1,sockets=1 \
-m $MEM \
-no-hpet \
-localtime \
-drive file=$HDD0,if=virtio,cache=none,index=0 \
-drive file=$CD,media=cdrom,if=ide,index=2  \
-net nic,vlan=40,name=net0,model=virtio,macaddr=$mac0 \
-net vnic,vlan=40,name=net0,ifname=$VNIC0,macaddr=$mac0 \
-vga std \
-pidfile /root/$NAME.pid \
-daemonize

if [ $? -gt 0 ]; then
    echo "Failed to start VM"
fi

port=`expr 5900 + $VNC`
public_nic=$(dladm show-vnic|grep vnic0|awk '{print $2}')
public_ip=$(ifconfig $public_nic|grep inet|awk '{print $2}')

echo "Started VM: $NAME"
echo "VNC available at: host IP ${public_ip} port ${port}"
echo "QEMU Monitor, do: # telnet localhost $TLN. Note: use Control ] to exit monitor before quit!
"

To control (start/stop) the virtual machine as a service using svcadm create a /root/kvmexample.xml manifest (file):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='export'>
    <service name='kvm/kvmexample' type='service' version='0'>
        <create_default_instance enabled='true'/>
        <single_instance/>
        <dependency name='network' grouping='require_all' restart_on='none' type='service'>
            <service_fmri value='svc:/milestone/network:default' />
        </dependency>
        <dependency name='filesystem' grouping='require_all' restart_on='none' type='service'>
            <service_fmri value='svc:/system/filesystem/local:default' />
        </dependency>
        <exec_method name='start' type='method' exec='/root/kvmexample.sh' timeout_seconds='60'/>
        <exec_method name='stop' type='method' exec=':kill' timeout_seconds='60'/>
        <stability value='Unstable'/>
        <template>
            <common_name>
                <loctext xml:lang='C'>KVM-kvmexample</loctext>
            </common_name>
        </template>
    </service>
</service_bundle>

Import the manifest:

1
svccfg import -f kvmexample.xml

And start the virtual machine:

1
svcadm enable kvmexample

Use a VNCviewer to connect to the zones ip-address (on port 5901) to view the display output from the virtual machine.

Stop the virtual machine using:

1
svcadm disable kvmexample

Comments