Actions: | Security

AllGoodBits.org

Navigation: Home | Services | Tools | Articles | Other

VM deployment: Kickstart/libvirt/kvm

My aim was to be able to automate the creation of a new virtual machines, starting with:

and after a short and unattended wait, to be able to log into my new VM using my ssh key.

The Basic Idea

Various prerequisites

If the CPU's flags [1] include either vmx (for Intel) or svm (for AMD), it can support virtualization using KVM.

Packages

The host machine should have the following packages installed:

  • qemu-kvm
  • qemu-kvm-tools
  • libvirt
  • libvirt-client
  • libvirt-python
  • python-virtinst

Software repositories/mirrors

The VM install is installed across the network, so I make local mirrors of the following repositories available over http.

Networking

  • Eliminate the default bridge:

    virsh net-destroy default
    virsh net-undefine default
    
  • Ensure that bridged networking is available

    /etc/sysconfig/network:

    NETWORKING=yes
    HOSTNAME=kvm1.allgoodbits.org
    GATEWAY=br0
    

    /etc/sysconfig/network-scripts/ifcfg-eth0:

    DEVICE="eth0"
    HWADDR="78:2B:CB:03:C2:09"
    ONBOOT="yes"
    ETHTOOL_OPTS="autoneg off speed 100 duplex full"
    BRIDGE=br0
    

    /etc/sysconfig/network-scripts/ifcfg-br0:

    DEVICE=br0
    TYPE=Bridge
    BOOTPROTO=static
    ONBOOT=yes
    IPADDR=10.19.0.32
    NETMASK=255.255.252.0
    GATEWAY=10.19.0.1
    DELAY=0
    DNS1=10.19.0.1
    

Kickstart

The kickstart file specifies exactly how the OS should be installed and what it looks like once it has booted. In other words, it is effectively providing the answers to the various questions asked by the installer during an interactive install of the operating system. For example, questions about disk partitioning, network configuration, the root password, package installation, etc., etc. It also gives the opportunity to run an arbitrary post-installation script. In my case, I use the %post section to install my ssh key, turn off some unnecessary services, start puppet and set an rc.local command so that a message is sent upon first successful boot.

Disks

Here's a sample kickstart fragment that I use as a baseline specification for virtual machines. It will:

  • remove all filesystems and partitions from all disks visible to the VM, destroying all existing data.
  • use LVM to create a single physical volume, with a volumegroup containing logical volumes for /, /boot, swap and /var
clearpart --all --initlabel
autopart
bootloader --location=mbr
part /boot --fstype ext2 --size=150
part swap --size=4096
part pv.01 --size=1 --grow
volgroup vg_root pv.01
logvol  /  --vgname=vg_root --fstype ext4 --size=16384  --name=lv_root
logvol  /var  --vgname=vg_root --fstype ext4 --size=1 --grow --name=lv_var

Networking

Fragments to specify boring, I mean 'common', network configuration.

  • Getting config via DHCP, firewalled, only allowing ssh traffic in:

    firewall --enabled --ssh
    network --device eth0 --bootproto dhcp
    

    I likely want to leave out the --device directive and change the ksdevice kernel parameter below to link, indicating that anaconda should use the first interface that has link.

  • Specifying network configuration, disabled firewall:

    network --device eth0 --bootproto static --ip 10.19.0.129 --netmask 255.255.252.0 \
    --gateway 10.19.0.1 --nameserver 10.19.0.2 --hostname test.example.com
    

Yum repositories

A fragment to specify where to find Yum repositories, this creates config in /etc/yum.repos.d/ .

repo --name="centos" --baseurl=http://mirror.example.com/pub/centos/6.0/os/x86_64 --cost=100
repo --name="EPEL" --baseurl=http://mirror.example.com/pub/epel/6/x86_64 --cost=100
repo --name="IUS" --baseurl=http://mirror.example.com/pub/ius/stable/Redhat/6/x86_64 --cost=100
repo --name="LOCAL" --baseurl=http://mirror.example.com/pub/zoll/6/x86_64 --cost=100

Create and Install a VM guest

virt-install allows the creation of new VMs by interacting with various hypervisors using libvirt

virt-install -n test.allgoodbits.org -r 2048 --vcpus=2 \
-w bridge=br0,mac=52:54:00:00:00:01 \
--disk path=/var/lib/libvirt/images/test.allgoodbits.org,size=48 \
-l http://mirror.allgoodbits.org/pub/centos/6.0/os/x86_64 \
--nographics \
-x "ks=http://prime.allgoodbits.org/kickstart/c6-test.cfg ksdevice=eth0 \
ip=10.19.0.253 netmask=255.255.252.0 \
dns=10.15.1.90 gateway=10.19.0.1 console=ttyS0,115200"
-r n              allocate <n> MiB RAM to guest
-w bridge=br0     I want all guests to use bridged networking, because NAT just causes problems and because the virtio network driver which gives much better performance, requires it
--disk opt1=foo   options for path to the disk and the size (in GiB) MUST be included
-x "extra kernel boot params"      passed to the installation kernel; don't forget the console! Consider ``ksdevice=link``
-l <location>    specifies the location of the remote installation media, could also be nfs:<hostname>:/<export>

Using iSCSI storage

If you have created an iSCSI LUN to provide storage for your VM, the kvm storage pool XML description looks like this:

<pool type='iscsi'>
  <name>MYVM</name>
  <source>
      <host name='iscsi.allgoodbits.org' />
      <device path='iqn.2004-04.com.....' />

And you can use it like this:

virsh pool-define <myvm>.xml
virsh pool-start <MYVM>
[virsh pool-autostart <MYVM>]

Then your virt-install command changes its disk parameter:

--disk vol=MYVM/unit:0:0:0
[1]/proc/cpuinfo contains lots of information about the CPU(s), including details about the feature set of the CPU (in the flags field) and the type/speed and more.

Windows

For Windows, it looks a little different, but basically the same:

virt-install --hvm -n ms1.allgoodbits.org --ram 2048 --vnc \
              --os-type=windows --os-variant=win2k \
              --network bridge \
              --disk path=/var/lib/libvirt/images/ms1.allgoodbits.org,size=10,driver=phy,subdriver=zvol \
               --cdrom /isos/ms-win.iso

Troubleshooting

Important filesystem locations

VM disk images
/var/lib/libvirt/images/
Logs
/var/log/libvirt/qemu/
Configurations
/etc/libvirt/