Automated installation of centos with PXE

Automated installation of centos with PXE

When you want to install a huge amount of servers it is not very practical to install it manually. Obvious solution would be to setup automated installation for example with PXE.

So first we need to build a server with dhcp and tftp services and make a kickstart file. After server is installed manually, we can install services.

For dhcp we can use dnsmasq. It is very simple daemon which can be used as DNS and DHCP.

yum install dnsmasq
mv /etc/dnsmasq.conf  /etc/dnsmasq.conf.backup
vi /etc/dnsmasq.conf

Than create a dnsmasq.conf as follows:
interface=enp0s8,lo
domain=centos7.test
dhcp-range= enp0s8,192.168.56.11,192.168.56.250,255.255.255.0,1h
dhcp-boot=pxelinux.0,pxeserver,192.168.56.10
#Gateway
#dhcp-option=3,192.168.56.1
#DNS
#dhcp-option=6,192.168.56.1, 8.8.8.8
#NTP Server
#dhcp-option=42,192.168.56.10
pxe-prompt="Press F8 for menu.", 60
pxe-service=x86PC, "Install CentOS 7 from network server 192.168.56.10", pxelinux
enable-tftp
tftp-root=/var/lib/tftpboot

Than install syslinux bootloader and tftp server:
yum install syslinux
rpm -ql syslinux
yum install tftp-server
cp -r /usr/share/syslinux/* /var/lib/tftpboot
mkdir /var/lib/tftpboot/pxelinux.cfg

If you want to make specific configurations for specific server, you can make a file „/var/lib/tftpboot/pxelinux.cfg/MAC_ADDRESS_OF_SERVER“. If not, you can use default file for all the servers.
vi /var/lib/tftpboot/pxelinux.cfg/default

And fill it with content:
If you want to modify the syslinux config be aware of this man page.
https://www.syslinux.org/wiki/index.php?title=Menu#MENU_LABEL
For our purpose the most important is ONTIMEOUT possibility. It tells the pxe loader to use the option number 1 if there is no interaction during installation.
default menu.c32
prompt 0
timeout 300
ONTIMEOUT 1
menu title ########## PXE Boot Menu ##########
label 1
menu label ^1) Install CentOS 7 x64 with Kickstart
kernel centos7/vmlinuz
append initrd=centos7/initrd.img inst.ks=ftp://192.168.56.10/pub/anaconda-ks.cfg 
label 2
menu label ^2) Boot from local drive
label 3
menu label ^3) Install CentOS 7 x64 with Local Repo
kernel centos7/vmlinuz
append initrd=centos7/initrd.img method=ftp://192.168.56.10/pub devfs=nomount

Now copy installation files from centos.iso to you tftp server.
mount -o loop /dev/cdrom  /mnt
mkdir /var/lib/tftpboot/centos7
cp /mnt/images/pxeboot/vmlinuz  /var/lib/tftpboot/centos7
cp /mnt/images/pxeboot/initrd.img  /var/lib/tftpboot/centos7

Than download some ftp daemon, copy the contents to ftp directory, run the services, check and modify iptables rules if needed, check local ports to see if ftp daemon is listening.
yum install vsftpd -y
cp -r /mnt/*  /var/ftp/pub/ 
chmod -R 755 /var/ftp/pub
systemctl start dnsmasq
systemctl start vsftpd
systemctl enable dnsmasq
systemctl enable vsftpd
iptables -nvL
netstat -tulpn

Now in your browser you can check if the ftp is reachable:
ftp://192.168.56.10/pub

The last thing we need to do and you may notice it from a configuration number 1 „inst.ks=ftp://192.168.56.10/pub/anaconda-ks.cfg“ is to write a kickstart file to install the centos automatically. When a RHEL based distribution is installed, the kickstart file is generated in a /root directory. A Kickstart file has the answer to all the questions that the CentOS 7 installer asks when you manually install it so we can use it for our purpose. (If it is not enough, you can generate new kickstart file with kickstarter generator, you will find it in packages).
This is how it looks like:

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

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

# Root password
rootpw --iscrypted $6$gWNZ80EdC.P24yhX$FYdrTf97bDClZY7AP8.mw6fwiWbeJPuyJ96QquWoedfDYzOm.FdGJFGA1Y5u801KJVJuE35p5wS0Elqyq8UQV0
# System services
services --enabled="chronyd"
# System timezone
timezone America/New_York --isUtc
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
autopart --type=lvm
# Partition clearing information
clearpart --none --initlabel

%packages
@^minimal
@core
chrony
kexec-tools

%end

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

%end

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


There are a few things that I modified. (The diff file)
#diff anaconda-ks.cfg /var/ftp/pub/anaconda-ks.cfg 
4,7c4
< # Use CDROM installation media
< cdrom
< # Use graphical install
< graphical
---
> url --url="ftp://192.168.56.10/pub/"
13a11
> reboot
15d12
< 
17c14
< network  --bootproto=dhcp --device=enp0s3 --onboot=off --ipv6=auto --no-activate
---
> network  --bootproto=dhcp --device=enp0s3 --onboot=on --ipv6=auto --activate
19c16,17
< 
---
> repo --install --name="local" --baseurl="ftp://192.168.56.10/pub/localrepo"
> selinux --disabled
37d34
< 
47a45,52
> %end
> 
> %post
> echo "gpgcheck=0" >> /etc/yum.repos.d/local.repo
> rm -rf /etc/yum.repos.d/Cent*
> yum install -y puppet-agent stress-ng nc
> echo client`ip addr show enp0s3 | grep -oP inet.*/24 | sed -s 's/inet 192.168.56.//g' | sed -s 's/\/24//g'`.local > /etc/hostname
> cat /etc/hostname | nc 192.168.56.10 999

So you need to change cdrom to url with url of your ftp server, activate network interface if you want to and add another repository.

This creates a local repository in your /etc/yum.repos.d directory

repo --install --name="local" --baseurl="ftp://192.168.56.10/pub/localrepo"

Parameter reboot tell the installer to reboot the server after succesful installation. Otherwise the server will wait fo confirmation.

The „%post“ section in my case modifies a few things in a created local repository file, install packages, deletes all other repos and dynamically generates the name of a server from the last octet of an IP address. Finally it sends a notification to my server with nc, to see which server was succesfuly installed.

So that is kickstart file. Next step is to create a localrepo, because I use it to install other custom packages automatically.

mkdir /root/localrepo
yum install --downloadonly --downloaddir=/root/localrepo/ libpcap nc stress-ng
mkdir /var/ftp/pub/localrepo
cp -r /root/localrepo/* /var/ftp/pub/localrepo
chmod -r 644 /var/ftp/pub/localrepo
yum install createrepo
cd /var/ftp/pub/localrepo
createrepo .

Finally save everything, reload daemons, and run nc on a server:
while true; do nc -l -p 999; done

Than watch fully automated installation with configured repo, packages and generated hostname.
Booting:

PXE menu:

Sending message:

Booted machine without single keyhit.