Monday, October 7, 2019

Create virutal machine on KVM hypervisor using Libvirt API with Python and cloud-init

Summary:

In a cloud environment, we use images to install systems. The system automation is generally done by cloud-init. Cloud-init was originally developed for Ubuntu GNU/Linux on the Amazon EC2 cloud. It has become the de facto installation configuration tool for most Unix like systems on most cloud environments.

Cloud-init uses a YAML file to configure the system.


Environment:

  • GCP environment
  • server1 - Centos 7 with cloud-init utility
  • server2 - Centos 7 with KVM hypervisor
On Server1 :
Download  Centos 7 Genericcloud image:

wget https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1809.qcow2
wget https://cloud.centos.org/centos/7/images/sha256sum.txt
wget https://cloud.centos.org/centos/7/images/sha256sum.txt.asc


Verify the fingerprint:

# gpg --with-fingerprint /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
gpg: keyring `/root/.gnupg/secring.gpg' created
pub  4096R/F4A80EB5 2014-06-23 CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>
      Key fingerprint = 6341 AB27 53D7 8A78 A7C2  7BB1 24C6 A8A7 F4A8 0EB5

Import the pub centos gpg key:

# gpg --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key F4A80EB5: public key "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

List the trusted gpg key:

# gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub   4096R/F4A80EB5 2014-06-23
uid                  CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>

Verify the sha256sum file:

# gpg --verify sha256sum.txt.asc
gpg: Signature made Fri 09 Aug 2019 12:08:54 PM UTC using RSA key ID F4A80EB5
gpg: Good signature from "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 6341 AB27 53D7 8A78 A7C2  7BB1 24C6 A8A7 F4A8 0EB5

Image information :

The image we download is a normal qcow2 image, we can see the image information with qemu-info

# yum install qemu-img -y

# qemu-img info CentOS-7-x86_64-GenericCloud-1809.qcow2
image: CentOS-7-x86_64-GenericCloud-1809.qcow2
file format: qcow2
virtual size: 8.0G (8589934592 bytes)
disk size: 873M
cluster_size: 65536
Format specific information:
    compat: 0.10

   
Resize the image to be copy to kvm server:   
   
The default image is small - 8GB - we might be using the image to provision other systems so it better to leave it untouched.
Copy the image to the location where we’ll run the virtual system.

Resize the qcow2 size if required:

# qemu-img resize /var/lib/libvirt/images/test-vm.qcow2 15G
Image resized.


cloud-init utility installation :

We’ll create a simple cloud-init configuration file and generate an iso image with cloud-localds.
This iso image holds the cloud-init configuration and will be used to setup the system during the bootstrap.

** It’s important to NOT install cloud-init on your KVM host machine. **
This creates a cloud-init service that runs during the boot and tries to reconfigure your host.
Something that you probably don’t want on your KVM hypervisor host.

The cloud-util package has all the tool we need to convert the cloud-init configuration files to an iso image.



# yum remove gce-disk-expand-1.0.5-1505406172.el7.x86_64 

# yum install -y cloud-utils 


To Generate hash password use below command
 


# python -c 'import crypt,getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))'
Password:
<your hash>

# vim user-data


#cloud-config

package_upgrade: false
users:
  - name: demo
    groups: wheel
    lock_passwd: false
    passwd: < your hash >

    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']

# vim meta-data


instance-id: 5
local-hostname: test-vm


Generate the configuration iso image:

# yum install genisoimage -y

#
genisoimage -output test-vm.iso -volid cidata -joliet -rock user-data meta-data

Copy qcow2 cloud image and iso config files to KVM server :

# scp test-vm.iso root@10.152.0.47:/var/lib/libvirt/images/.



# scp CentOS-7-x86_64-GenericCloud-1809.qcow2 root@10.152.0.47:/var/lib/libvirt/images/test-vm.qcow2
 

On Server2 :

Create instance (domain) on KVM server using virt-install :


# virt-install \
--name=test-vm \
--virt-type kvm \
--arch=x86_64 \
--vcpus=1 \
--ram=2048 \
--os-type=linux \
--os-variant=centos7.0 \
--accelerate \
--network bridge:virbr0,model=virtio \
--disk /var/lib/libvirt/images/test-vm.qcow2,device=disk,cache=none,bus=virtio \
--disk /var/lib/libvirt/images/config.iso,device=cdrom \
--graphics none \
--import \
--boot useserial=on





Create vm input xml file :

# vim /root/vm-input.xml

<domain type='kvm' id='5'>
  <name>test-vm</name>
  <memory unit='KiB'>2097152</memory>
  <currentMemory unit='KiB'>2097152</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='hd'/>
    <bios useserial='yes'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>Westmere-IBRS</model>
    <feature policy='require' name='md-clear'/>
    <feature policy='require' name='spec-ctrl'/>
    <feature policy='require' name='ssbd'/>
    <feature policy='require' name='pclmuldq'/>
    <feature policy='require' name='x2apic'/>
    <feature policy='require' name='hypervisor'/>
  </cpu>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/test-vm.qcow2'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/var/lib/libvirt/images/config.iso'/>
      <backingStore/>
      <target dev='hda' bus='ide'/>
      <readonly/>
      <alias name='ide0-0-0'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>
    <controller type='usb' index='0' model='ich9-ehci1'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <alias name='usb'/>
      <master startport='0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <alias name='usb'/>
      <master startport='2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <alias name='usb'/>
      <master startport='4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <controller type='ide' index='0'>
      <alias name='ide'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </controller>
    <interface type='bridge'>
      <mac address='52:54:00:d7:f4:46'/>
      <source bridge='virbr0'/>
      <target dev='vnet0'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='mouse' bus='ps2'>
      <alias name='input0'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input1'/>
    </input>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </memballoon>
    <rng model='virtio'>
      <backend model='random'>/dev/urandom</backend>
      <alias name='rng0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </rng>
  </devices>
</domain>



Create instance on KVM server using python with libvirt api :

# python
>>> import libvirt
>>> connection = libvirt.open("qemu:///system")
>>> f=open("/root/vm-input.xml")
>>> xml=f.read()
>>> connection.defineXML(xml)

<libvirt.virDomain object at 0x7fa196ba4d10>





 





No comments:

Post a Comment