Howto deploy VM using KVM & kickstart on CentOS/Red Hat - Part 1

Introduction

This is the first post of a short serie of articles about automation in the deployment of VM guests using Linux as a host server and KVM as platform. The procedure is compatible with CentOS 7.3 / Red Hat Enterprise Linux 7.3 (been tested with CentOS 7.3).

The series will be composed of the following posts as minimum:
  1. General concepts, creating a virtual storage, creating a VM using virt-install
  2. Automate the deployment using kickstart
KVM is the free Virtualization Environment for Linux.is the free Virtualization Environment for Linux.
Kickstart is a tool to automate the installation/deployment of an OS. It will basically "automate" answers to the questions the GUI ask you during the installation phase.

libvirt tools

Let's get started!

Requirements

Minimum host system hardware requirements: Intel VT-x and Intel 64 extensions or AMD-V and AMD64 extensions + an additional core for the guest, RAM and disk space depending on the guest.

To check the CPU on the host:
$ cat /proc/cpuinfo

To build a Virtualization environment on Red Hat you need to install as a minimum the following packages:
qemu-kvm & qemu-img

To check if they are already installed:
$ rpm -qa | grep qemu

To install from the repository:
# yum install qemu-kvm qemu-img

To make your life easier you should also install the following packages:
python-virtinst
libvirt
libvirt-python
libvirt-client

The tool we are going to use the most (virsh) is part of libvirt packages.

In my Lab I have been using a CentOS 7.3 host running on a hardware based on Intel CORE i7vPro CPU with 8GB of RAM. I have installed the above packages (all the set). To make things more "realistic" I used another laptop connected to my Linux host through ssh; similar to an enterprise environment.

Now you need to downloaded the ISO of CentOS 7.3; as you are connected through ssh you need to use a command line tool to download the ISO. I have been using wget.

Then connected to the host as a standard user, I switched to root using su to be able to:
1) create a new directory under /opt called VM:
    # mkdir /opt/VM
2) change the group ownership of the directory so my standard user can work in that directory:
    # chown root:vmusers /opt/VM
3) added my standard user to the group "vmusers":
    # usermod -aG vmusers user-name
   the "G" option is used to set the secondary groups for a user (they have to be comma separated)
   the "a" option allow to append groups: if the user is already part of several groups, you need to use this option to be able to just add the user to a new group without modifying the existing list

Creating the virtual storage

There are several type of storage you can use. We choose qcow2 as it is the standard for KVM virtual machines.
The following command will create a 32GB image which you will be able to use and partition via kickstart and virt-install. 

# qemu-img create -f qcow2 /opt/VM/CentOS-server1/guest.qcow2 32768M
Formatting '/opt/VM/CentOS-server1/guest.qcow2', fmt=qcow2 size=34359738368 encryption=off cluster_size=65536 lazy_refcounts=off

The file created does not use all the 32GB of space but it can grow up to that size:

# ls -l /opt/VM/CentOS-server1/
total 196
-rw-r--r-- 1 root root 197120 Jul 22 18:24 guest.qcow2

Check the host network configuration

When you have the KVM virtual environment working, you should have a network interface called something like virbr0. If you execute the "Network Management CLI" or any other way to get network information (ip addr sho, ifconfig ...) you should get something like this:

# nmcli device show
GENERAL.DEVICE:                         virbr0
GENERAL.TYPE:                           bridge
GENERAL.HWADDR:                         52:54:00:88:4E:4B
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     virbr0
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/1
IP4.ADDRESS[1]:                         192.168.122.1/24
IP4.GATEWAY:
IP6.GATEWAY:

GENERAL.DEVICE:                         enp0s25
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         F0:DE:F1:4C:49:45
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     enp0s25
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/9
WIRED-PROPERTIES.CARRIER:               on
IP4.ADDRESS[1]:                         192.168.0.18/24
IP4.GATEWAY:                            192.168.0.1
IP4.DNS[1]:                             
IP4.DNS[2]:                             
IP6.ADDRESS[1]:                         
IP6.GATEWAY:

These means that you have a virbr0 interface ready to be used for your new VM guest ! If this is not happening ... you need to review your KVM host environment.

Installing the VM

So now you just need to run the following command. It will create a new VM guest, named "CentOS-Server1" with 1GB of RAM, using the qcow2 storage we just created, the network bridge virbr0 and the CentOS ISO file which we downloaded with wget. As we don't was to use VNC but just CLI, we need to set "nographics" and forward the console using the extra-args option.
To run this command you need to move into the folder where you have created the qcow2 storage file.

# virt-install \
--name CentOS-Server1 \
--ram 1024 \
--disk path=./guest.qcow2,size=32 \
--vcpus 1 \
--os-type linux \
--os-variant centos7.0 \
--network bridge=virbr0 \
--nographics \
--location /opt/VM/CentOS-7-x86_64-DVD-1611.iso \
--extra-args "console=ttyS0"

The installation will start and you will be prompted for several questions:


You need to complete the steps which have an esclamation mark in it. And then proceed with the installation.
Remember, the scope of this test is just create the baseline for your kickstart configuration file (generated by the anaconda installer during the setup).


After a minute or two you will have your VM created. We now need to start and connect to it !

Testing your VM

Just hit Enter and the jus created VM will reboot. Login and type df -h to check the disks and ip addr show to check the network configuration.
This is my just created kickstart file (I left the hashed password of root as this is just a lab):

# cat anaconda-ks.cfg
#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use text mode install
text
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=vda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts=''
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=dhcp --device=eth0 --onboot=off --ipv6=auto --no-activate
network  --hostname=localhost.localdomain

# Root password
rootpw --iscrypted $6$f8wdfFwzzYkMM4st$yA16u58XLpN/tGOYAfQ0VHgBUkgGHCGXV3xQiFAzYcv.7JDmsJ0dosOuZRWrzq7TSyLDG.sD9iSLFwcLIohnB0
# System services
services --enabled="chronyd"
# Do not configure the X Window System
skipx
# System timezone
timezone Europe/London --isUtc
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda
autopart --type=lvm
# Partition clearing information
clearpart --all --initlabel --drives=vda

%packages
@core
chrony
kexec-tools

%end

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%anaconda
pwpolicy root --minlen=6 --minquality=50 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=50 --notstrict --nochanges --notempty
pwpolicy luks --minlen=6 --minquality=50 --notstrict --nochanges --notempty
%end

Troubleshooting your VM

I have been playing "too much" with the network configuration of the host months ago ... removing the Network Manager, manually configuring the WiFi and later re-installing the Network Manager ... the results are that I have the virbr0 bridge listed in my host network interface but when I start my guest it does not seems to work (cable disconnected).
The interface virbr0 is configured through virsh. Three are the commands you need to remember:

stop network:
# virsh net-destroy default

start it:
# virsh net-start default

edit the default.xml file in the right way (locking the file so you are the only user which is effectively manipulating the file):
# virsh net-edit default

My file look like this:
# cat /etc/libvirt/qemu/networks/default.xml
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
  virsh net-edit default
or other application using the libvirt API.
-->

<network>
  <name>default</name>
  <uuid>cd61f19c-de54-41ff-bb09-94089f52fe1d</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:88:4e:4b'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

I don't see any here ... so let's move inside the guest and check how the network card is configured.

So as I did power off my VM before, now I need to start it again. Let's have a look at my VM (the inactive VMs):

# virsh list --inactive
 Id    Name                           State
----------------------------------------------------
 -     CentOS-Server1                 shut off
 -     Kali                           shut off

To check if the network is active:

# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

You cannot connect to an "inactive" (powered-off guest), you need first to start it (power-on):

# virsh start CentOS-Server1
Domain CentOS-Server1 started

Now that it is powerd on you can open it's serial console (it is like if the host is connected to the serial console of the guest):

# virsh console CentOS-Server1
Connected to domain CentOS-Server1
Escape character is ^]

CentOS Linux 7 (Core)
Kernel 3.10.0-514.el7.x86_64 on an x86_64

localhost login: root
Password:
Last login: Sat Jul 22 21:47:50 on ttyS0

As you may see, you can jump back to the host using the Escape character ^] ( which is CTRL-] )

So back to the original issue ... the network! The virbr0 interface seems to be configured correctly but if I check the guest network configuration I got this:

# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:75:69:70 brd ff:ff:ff:ff:ff:ff

As you can see, there is something wrong: eth0 does not have any IP associated

So let's have a look to what Network Manager suggest:

# nmcli
eth0: disconnected
        "Red Hat Virtio network device"
        1 connection available
        ethernet (virtio_net), 52:54:00:75:69:70, hw, mtu 1500

lo: unmanaged
        loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536

Use "nmcli device show" to get complete information about known devices and
"nmcli connection show" to get an overview on active connection profiles.

Consult nmcli(1) and nmcli-examples(5) manual pages for complete usage details.

So at the moment the state shows as "disconnected" ... what to do now?

# nmcli device show
GENERAL.DEVICE:                         eth0
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         52:54:00:75:69:70
GENERAL.MTU:                            1500
GENERAL.STATE:                          30 (disconnected)
GENERAL.CONNECTION:                     --
GENERAL.CON-PATH:                       --
WIRED-PROPERTIES.CARRIER:               on

# nmcli connection show
NAME  UUID                                  TYPE            DEVICE
eth0  65c3d95b-9ff4-480b-954c-63248335cef5  802-3-ethernet  --

As everything seems to be correct, I normally have a look to the configuration files for the interface:

# cat /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eth0
UUID=65c3d95b-9ff4-480b-954c-63248335cef5
DEVICE=eth0
ONBOOT=no

So I guess the issue is that the "ONBOOT" option is set to "no" so the OS is not sending the request to DHCP to get an IP ... let's use nmcli to enable connetion:

# nmcli con up id eth0
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/0)

Let's check if it does work now:

# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:75:69:70 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.251/24 brd 192.168.122.255 scope global dynamic eth0
       valid_lft 3588sec preferred_lft 3588sec
    inet6 fe80::d4cf:56f3:675b:221d/64 scope link
       valid_lft forever preferred_lft forever

When you reboot the guest, the interface will not have an IP again (not connected). Let's make it permanent! If you edit the file ifcfg-eth0 you have later to inform the Network Manager to reload the file.

Using vi let's change ONBOOT=no into ONBOOT=yes in the file /etc/sysconfig/network-scripts/ifcfg-eth0.

Then reload the file:

# nmcli con load !$
nmcli con load /etc/sysconfig/network-scripts/ifcfg-eth0

I love the shortcut !$ which repeat the last used argument!

# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:75:69:70 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.251/24 brd 192.168.122.255 scope global dynamic eth0
       valid_lft 3590sec preferred_lft 3590sec
    inet6 fe80::d4cf:56f3:675b:221d/64 scope link
       valid_lft forever preferred_lft forever

So, reboot for the last time and check again the network ... done! Issue sorted and learnt some useful nmcli commands!

In the next post of this short serie we will work on the kickstart file to customize both the partitioning of the storage and the network configuration (I want to have the above correction automated during the  guest deployment).

If you enjoyed this post, please follow us and comment!

No comments:

Post a Comment