Thursday, July 10, 2014

Install virtual Centos 7 with pxe and kickstart on real Centos 7 machine

I was wondering how pxe works and how to use it. In today's post I will look at it a little closer. First goal is to boot Centos 7 installation over pxe. Second goal is to perform unattended system installation with kickstart.

TOC

Overview

What will we need:
  • working virtualization (outside of scope of this post)
  • dnsmasq as bootp and dhcp
  • pxelinux images + menu
  • Centos 7 kernel + initrd
  • kickstart config file

Prepare guest domain

My domain (guest OS) is called centos-pxe and is defined this way:

[root@kra tftp]# virsh dumpxml centos-pxe
<domain type='kvm'>
  <name>centos-pxe</name>
  <uuid>1ca626c7-797d-4cec-8be6-74336cd73c2f</uuid>
  <memory unit='KiB'>1012152</memory>
  <currentMemory unit='KiB'>1012152</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='network'/> 
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='localtime'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw'/>
      <source file='/home/vajko/images/centos-pxe.img'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </disk>
    <controller type='usb' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'/>
    <controller type='ide' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='scsi' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </controller>
    <controller type='sata' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:00:44:77:e5'/>
      <source network='default'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface> 
    <input type='tablet' bus='usb'/>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='-1' autoport='yes' keymap='en-us'/>
    <sound model='ac97'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </sound> 
    <video>  
      <model type='vga' vram='9216' heads='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video> 
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </memballoon>
  </devices> 
</domain>

Notice that I have defined network card (lines 42-47) on network named "default" (line 44). Another important line is number 10 where booting from network is set.

Setup libvirt network

I'm using routed network setup. My default network (named "default") xml looks like this:

[root@kra commands]# virsh net-dumpxml default
<network>
  <name>default</name>
  <uuid>9ad54764-4d45-430d-af16-9a77808e66cf</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0' />
  <mac address='52:54:00:2a:e8:40'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <tftp root='/var/lib/tftp' /> 
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254' />
      <bootp file='pxelinux.0' /> 
    </dhcp>
  </ip>
</network>

Important lines are number 13 and 16. Number 13 tells dnsmasq to act also as tftp server with tftp server root pointing to /var/lib/tftp. 16th line tells dnsmasq to use file pxelinux.0 in tftp root directory to boot guest OS.

Prepare ks file and publish it to web

I will use kickstart file generated automatically after installation. It is stored in /root/anaconda-ks.cfg:

#version=RHEL7
# System authorization information
auth --enableshadow --passalgo=sha512

# Use network installation
url --url="http://merlin.fit.vutbr.cz/mirrors/centos/7.0.1406/os/x86_64" 
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=vda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate
network  --hostname=centos-pxe
# Root password
rootpw --iscrypted $6$rhidunBHKZEkNc7r$9elfwXn5XqCxw40OUnWcrDx4iLewOlLPUZ3OwvTq7/Eas/PkrvVcme8hGnsxblzdYibd8SxBz5Nk2.8OSF4Vf.
# System services
services --enabled="chronyd"
# System timezone
timezone Europe/Bratislava --isUtc
user --name=vajko --password=$6$4al.p6ZQYwlI/0LW$dtnLJ./SvvhMRAcOEqguvkXmksAdyn06FjIxwV29KwIggp.csSF1wKmxbyZT/xmW4HamPW3HZ3NAyqC/AA5GU0 --iscrypted --gecos="vajko"
# System bootloader configuration
bootloader --location=mbr --boot-drive=vda
autopart --type=lvm
# Partition clearing information
clearpart --all --initlabel --drives=vda

%packages
@core
chrony

%end

I have chosen network installation method. I will use one of czech centos mirrors. Feel free to pick any mirror you like.

Kickstart file must be located somewhere on the web or inside initial ramdisk (initrd). I have chosen number one. If you haven't install apache webserver do it now (yum install httpd). Place kickstart file to web root which is /var/www/html by default. Name it as you like, I will use "ks.cfg". Set proper permissions and selinux context:

[root@kra html]# pwd
/var/www/html
[root@kra html]# ls
ks.cfg
[root@kra html]# chown apache:apache ks.cfg 
[root@kra html]# chmod 400 ks.cfg 
[root@kra html]# chcon -u system_u -r object_r -t httpd_sys_content_t ks.cfg 
[root@kra html]# ls -lZ
-r--------. apache apache system_u:object_r:httpd_sys_content_t:s0 ks.cfg

Start apache if it is not started already:

[root@kra html]# systemctl is-active httpd.service 
inactive
[root@kra html]# systemctl start httpd.service 
[root@kra html]# systemctl is-active httpd.service 
active

Setup firewall

Access to apache (port 80) must be allowed from virtual network (192.168.122.0/24), which is denied by default. In CentOS 7 there is new subsystem for managing firewall stuff called firewalld:

[hasul@kra commands]$ systemctl is-active iptables.service 
inactive
[hasul@kra commands]$ systemctl is-active firewalld.service 
active

I'm not familiar with this tool, but it is not difficult to work with it. Basic concept is simple. There are zones with services and rules defined:

[root@kra syslinux]# firewall-cmd --get-zones
block dmz drop external home internal public trusted work
[root@kra syslinux]# firewall-cmd --get-active-zones
public
  interfaces: enp0s25
[root@kra syslinux]# firewall-cmd --get-default-zone
public
[root@kra syslinux]# firewall-cmd --zone public --list-services
dhcpv6-client ssh

Let's look what services are in internal zone:

[root@kra syslinux]# firewall-cmd --zone internal --list-services
dhcpv6-client http ipp-client mdns samba-client ssh

I'm lucky! Http service is in internal zone. Therefore I will add virtual network interface (virbr0) to internal zone:

[root@kra syslinux]# firewall-cmd --zone internal --add-interface virbr0
success
[root@kra syslinux]# firewall-cmd --get-active-zones
internal
  interfaces: virbr0
public
  interfaces: enp0s25

Access is granted now. It will last until reboot. To keep changes permanently use --permanent option when adding interface to interal zone.

Create and fill /var/lib/tftp

Now it's time to prepare netboot environment. First step is to install syslinux package:

yum install syslinux

Create tftp directory in fill it with files from syslinux:

[root@kra ~]# mkdir /var/lib/tftp
[root@kra ~]# cd /usr/share/syslinux
[root@kra syslinux]# cp mboot.c32 menu.c32 chain.c32 pxelinux.0 /var/lib/tftp/

Uninstall syslinux package, there is no need for it now (yum remove syslinux). Download kernel and initial ramdisk from a centos mirror:

[root@kra ~]# mkdir /var/lib/tftp/images/centos/7/x86_64
[root@kra ~]# cd /var/lib/tftp/images/centos/7/x86_64
[root@kra x86_64]# curl -# \
> http://merlin.fit.vutbr.cz/mirrors/centos/7.0.1406/os/x86_64/images/pxeboot/vmlinuz -o vmlinuz
######################################################################## 100.0%
[root@kra x86_64]# curl -# \
> http://merlin.fit.vutbr.cz/mirrors/centos/7.0.1406/os/x86_64/images/pxeboot/initrd.img -o initrd.img
######################################################################## 100.0%
[root@kra x86_64]# ls
initrd.img  vmlinuz

Create directory for boot configuration/menu:

[root@kra ~]# cd /var/lib/tftp/
[root@kra tftp]# mkdir pxelinux.cfg

My boot menu has only one entry. It uses downloaded kernel and initrd and kickstart file published on apache:

[root@kra tftp]# cat pxelinux.cfg/default
default menu.c32
prompt 0
timeout 300
ONTIMEOUT local

MENU TITLE PXE Menu

LABEL CentOS 7 x86_64 pxe
        MENU LABEL CentOS 7 pxe
        KERNEL images/centos/7/x86_64/vmlinuz
        APPEND ks=http://192.168.122.1/ks.cfg initrd=images/centos/7/x86_64/initrd.img

Fix permissions and selinux context on /var/lib/tftp

Finally I need to fix permission and selinux context. Actual state:

[root@kra tftp]# pwd
/var/lib/tftp
[root@kra tftp]# ls -lZd
drwxr-xr-x. root root unconfined_u:object_r:var_lib_t:s0 .
[root@kra tftp]# ls -lZ .
-rw-r--r--. root root unconfined_u:object_r:var_lib_t:s0 chain.c32
drwxr-xr-x. root root unconfined_u:object_r:var_lib_t:s0 images
-rw-r--r--. root root unconfined_u:object_r:var_lib_t:s0 mboot.c32
-rw-r--r--. root root unconfined_u:object_r:var_lib_t:s0 menu.c32
-rw-r--r--. root root unconfined_u:object_r:var_lib_t:s0 pxelinux.0
drwxr-xr-x. root root unconfined_u:object_r:var_lib_t:s0 pxelinux.cfg

Permissions looks good, but I have to fix selinux context (selinux user -> system_u and selinux type -> virt_var_lib_t):

[root@kra tftp]# chcon -R -u system_u -t virt_var_lib_t .
[root@kra tftp]# ls -ldZ .
drwxr-xr-x. root root system_u:object_r:virt_var_lib_t:s0 .
[root@kra tftp]# ls -lZ 
-rw-r--r--. root root system_u:object_r:virt_var_lib_t:s0 chain.c32
drwxr-xr-x. root root system_u:object_r:virt_var_lib_t:s0 images
-rw-r--r--. root root system_u:object_r:virt_var_lib_t:s0 mboot.c32
-rw-r--r--. root root system_u:object_r:virt_var_lib_t:s0 menu.c32
-rw-r--r--. root root system_u:object_r:virt_var_lib_t:s0 pxelinux.0
drwxr-xr-x. root root system_u:object_r:virt_var_lib_t:s0 pxelinux.cfg

And that's it! Just start virtual machine (virsh start centos-pxe && vncviewer :) and it will do the magic.

Sources

  • http://wiki.centos.org/HowTos/PXE/PXE_Setup/Menus
  • http://www.thegeekstuff.com/2009/07/how-to-view-modify-and-recreate-initrd-img/
  • http://fedoraproject.org/wiki/FirewallD

No comments:

Post a Comment