Tuesday, November 13, 2012

CentOS 6 Anaconda / Kickstart PXE Boot & Install Server HOWTO


This page describes how to configure CentOS 6.3 as an Anaconda & Kickstart PXE boot and install server.   The following guide outlines the details for setting up both CentOS 6.3 x86_64 and CentOS 6.3 i386 on the same server.  With a bit more effort, it is also possible to install other Enterprise Linux versions using the same install server (e.g. CentOS 5.8 or any version of Red Hat Enterprise Linux).

Step 1)  Download the CentOS DVD ISOs


o   Keep these available, you'll need them again later in this process.

# 64-bit
wget http://www.gtlib.gatech.edu/pub/centos/6.3/isos/x86_64/CentOS-6.3-x86_64-bin-DVD1.iso
# 32-bit
wget http://www.gtlib.gatech.edu/pub/centos/6.3/isos/i386/CentOS-6.3-i386-bin-DVD1.iso

Step 2) Install CentOS 6.3


o   This will be the anaconda / kickstart server.
o   Start with a 'minimal' install.
o   Make sure to have at least 40GB of free space on / or mounted as /export.
o   This guide uses yum to install the required additional packages.
o   Internet (or a Satellite Server) access isn't necessarily required, but it does make it easier.
o   In lieu of Internet/Satellite access, you could use rpm to install the required packages, but it's more difficult and you will have to install all dependent packages manually.

Step 3) Configure the network interface(s)


o   Don't use dhcp for the anaconda / kickstart server's network interface.
o   Configure /etc/resolv.conf and /etc/nsswitch.conf appropriately for your environment.
o   Remember to check that Internet (or Satellite Server) access works (e.g. yum makecache)

vi /etc/sysconfig/network-scripts/ifcfg-eth1:

-- begin example /etc/sysconfig/network-scripts/ifcfg-eth1--
DEVICE="eth1"
BOOTPROTO="none"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
IPADDR=192.168.111.1
MASK=255.255.255.0
-- end example /etc/sysconfig/network-scripts/ifcfg-eth0--

Step 4) Disable iptables


o   This isn’t absolutely necessary, it’s just easier.

chkconfig iptables off
service iptables stop

Step 5) Disable selinux


·         Again, not necessary but easier.

vi /etc/selinux/config

-- begin example /etc/selinux/config--
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted
-- end example /etc/selinux/config--

Step 6) Install required packages


yum -y install wget syslinux syslinux-tftpboot xinetd tftp-server tftp dhcp httpd openssh-clients

Step 7) Create the anaconda directory structure


mkdir -p /export/anaconda/iso/CentOS
mkdir -p /export/anaconda/media
mkdir -p /export/anaconda/media/CentOS-6.3-x86_64
mkdir -p /export/anaconda/media/CentOS-6.3-i386
mkdir -p /export/anaconda/tftpboot
mkdir -p /export/anaconda/tftpboot/pxelinux.cfg
mkdir -p /export/anaconda/tftpboot/CentOS-6.3-x86_64
mkdir -p /export/anaconda/tftpboot/CentOS-6.3-i386
mkdir -p /export/anaconda/postinstall/
mkdir -p /export/anaconda/cfg/
ln -s /export/anaconda /anaconda

Step 8) Enable anaconda tftp boot via xinetd


vi /etc/xinetd.d/tftp

-- begin example /etc/xinetd.d/tftp--
# default: on
# description: The tftp server serves files using the trivial file transfer \
#       protocol.  The tftp protocol is often used to boot diskless \
#       workstations, download configuration files to network-aware printers, \
#       and to start the installation process for some operating systems.
service tftp
{
        socket_type             = dgram
        protocol                = udp
        wait                    = yes
        user                    = root
        server                  = /usr/sbin/in.tftpd
        server_args             = -s /export/anaconda/tftpboot
        disable                 = no
        per_source              = 11
        cps                     = 100 2
        flags                   = IPv4
}
-- end example /etc/xinetd.d/tftp--
  

Step 9) Configure the DHCP server


o   Note that the example dhcpd.conf below is not authoritative. 
o   For PXE boot to work, you must enter the correct hardware ethernet (MAC) address for each of the clients you want to kickstart.
o   This could be changed to authoritative for a given subnet, but it's safer to prevent *any* client from obtaining an IP address from this dhcp server.
o   Once a client is installed via kickstart, be sure to remove (or change) the MAC address in dhcpd.conf so it doesn't accidentally get re-installed.
o   Preventing fully automatic installs is generally a good practice.

vi /etc/dhcp/dhcpd.conf

-- begin example /etc/dhcp/dhcpd.conf--
ddns-update-style ad-hoc;

not authoritative;

option domain-name              "defaultdomain";

deny unknown-clients;
allow booting;
allow bootp;

option ip-forwarding    false;
option mask-supplier    false;

subnet 192.168.111.0 netmask 255.255.255.0 {
      option routers                  192.168.111.1;
      option domain-name-servers      192.168.111.1;
      option subnet-mask              255.255.255.0;
}

group {
      next-server                     192.168.111.1;
      filename                        "pxelinux.0";
      max-lease-time                  86400;
      default-lease-time              43200;
      min-lease-time                  43200;

      host anaconda-dhcp-200 {
              hardware ethernet 00:0c:29:1b:f7:84; # red
              fixed-address 192.168.111.200;
      }

      host anaconda-dhcp-201 {
              hardware ethernet 00:0c:29:fa:74:e5; # orange
              fixed-address 192.168.111.201;
      }

}
-- end example /etc/dhcp/dhcpd.conf--

Step 10) Copy the CentOS DVD media


o   Use the ISOs downloaded earlier.  Or, download them again.
o   (somehow) Copy them to /export/anaconda/iso/CentOS, e.g.

scp CentOS-6.3-x86_64-bin-DVD1.iso root@192.168.111.1:/export/anaconda/iso/CentOS
scp CentOS-6.3-i386-bin-DVD1.iso root@192.168.111.1:/export/anaconda/iso/CentOS

Or ...

cd /export/anaconda/iso/CentOS
# 64-bit
wget http://www.gtlib.gatech.edu/pub/centos/6.3/isos/x86_64/CentOS-6.3-x86_64-bin-DVD1.iso
# 32-bit
wget http://www.gtlib.gatech.edu/pub/centos/6.3/isos/i386/CentOS-6.3-i386-bin-DVD1.iso

Once the ISOs exist in /export/anaconda/iso/CentOS on the server ...

# 64-bit
cd /export/anaconda/media/CentOS-6.3-x86_64/
mount -o loop /export/anaconda/iso/CentOS/CentOS-6.3-x86_64-bin-DVD1.iso /mnt
cp -rp /mnt/* .
umount /mnt
# 32-bit
cd /export/anaconda/media/CentOS-6.3-i386/
mount -o loop /export/anaconda/iso/CentOS/CentOS-6.3-i386-bin-DVD1.iso /mnt
cp -rp /mnt/* .
umount /mnt

Step 11) Configure default boot menu


o   Adding the default option to boot to rescue mode can avoid fully automatic (accidental) installs.
o   Manual selection of the correct installation / kickstart configuration profile is my best practice.

vi /export/anaconda/tftpboot/pxelinux.cfg/default

-- begin example /export/anaconda/tftpboot/pxelinux.cfg/default--
timeout 3600
default menu.c32

menu title Automatic Anaconda / Kickstart Boot Menu

label 1
    menu label ^ 1) CentOS-6.3-x86_64 (64-bit)
    kernel CentOS-6.3-x86_64/vmlinuz
    append initrd=CentOS-6.3-x86_64/initrd.img ramdisk_size=15491 ip=dhcp ksdevice=bootif ks=http://192.168.111.1/anaconda/cfg/CentOS-6.3-x86_64-ks.cfg
    IPAPPEND 2

label 2
    menu label ^ 2) CentOS-6.3-i386 (32-bit)
    kernel CentOS-6.3-i386/vmlinuz
    append initrd=CentOS-6.3-i386/initrd.img ramdisk_size=15491 ip=dhcp ksdevice=bootif ks=http://192.168.111.1/anaconda/cfg/CentOS-6.3-i386-ks.cfg
    IPAPPEND 2

label 3
    menu label ^ 3) Rescue CentOS-6.3-x86_64 (64-bit)
    kernel CentOS-6.3-x86_64/vmlinuz
    append initrd=CentOS-6.3-x86_64/initrd.img ramdisk_size=15491 ip=dhcp repo=http://192.168.111.1/anaconda/CentOS-6.3-x86_64 lang=en_US.UTF-8 keymap=us rescue

label 4
    menu label ^ 4) Rescue CentOS-6.3-i386 (32-bit)
    menu default
    kernel CentOS-6.3-i386/vmlinuz
    append initrd=CentOS-6.3-i386/initrd.img ramdisk_size=15491 ip=dhcp repo=http://192.168.111.1/anaconda/CentOS-6.3-i386 lang=en_US.UTF-8 keymap=us rescue
-- end example /export/anaconda/tftpboot/pxelinux.cfg/default--

Step 12) Configure /etc/httpd/conf.d/anaconda.conf


vi /etc/httpd/conf.d/anaconda.conf

-- begin example /etc/httpd/conf.d/anaconda.conf--
# anaconda/kickstart
#

Alias /anaconda/cfg /export/anaconda/cfg
<Directory /export/anaconda/cfg/>
    Options Indexes FollowSymLinks
    Allow from All
</Directory>

Alias /anaconda/postinstall /export/anaconda/postinstall
<Directory /export/anaconda/postinstall/>
    Options Indexes FollowSymLinks
    Allow from All
</Directory>

Alias /anaconda /export/anaconda/media
<Directory /export/anaconda/media/>
    Options Indexes FollowSymLinks
    Allow from All
</Directory>
-- end example /etc/httpd/conf.d/anaconda.conf--

Step 13) Customize kickstart configuration files


o   These are working examples, but you should tailor them to your individual needs.

# 64-bit
vi /export/anaconda/cfg/CentOS-6.3-x86_64-ks.cfg

-- begin example /export/anaconda/cfg/CentOS-6.3-x86_64-ks.cfg--
# Example kickstart configuration file for a RHEL 6.3 x86_64 (64-bit) standard install.
#

install

# Specifies the language
lang en_US.UTF-8

# Specifies the keyboard layout
keyboard us

# Skip Red Hat subscriber key input
key --skip

# Forces the text installer to be used (saves time)
text

# Forces the cmdline installer to be used (debugging)
#cmdline

# Skips the display of any GUI during install (saves time)
skipx

# Used with an HTTP install to specify where the install files are located
url --url http://192.168.111.1/anaconda/CentOS-6.3-x86_64

# Assign a static IP address upon first boot & set the hostname
network --onboot yes --bootproto dhcp --hostname rhel63

# Give the second interface a DHCP address (if you are not using a second interface comment this line out)
#network --device eth1 --bootproto=dhcp

# Set the root password
rootpw r00tp@55w0rd

# Enable the firewall and open port 22 for SSH remote administration
firewall --enabled --port=22:tcp

# Setup security and SELinux levels
#authconfig --enableshadow --enablemd5
authconfig --enableshadow --passalgo=sha512

selinux --disabled

# Set the timezone
timezone --utc Etc/UTC

# Create the bootloader in the MBR with drive sda being the drive to install it on
bootloader --location=mbr --driveorder=sda,sdb --append=audit=1

# Wipe all partitions and build them with the info below
clearpart --all --initlabel

#Disk partitioning information
zerombr

# Create primary partitions
part /boot --fstype ext4 --size=500 --asprimary --ondisk=sda
part swap --size=4096 --asprimary --ondisk=sda
part pv.01 --size=100 --grow --asprimary --ondisk=sda
# use the entire second disk for swap
#part swap --size=100 --grow --ondisk=sdb

# Create LVM logical volumes
volgroup system --pesize=32768 pv.01
logvol  /var  --vgname=system  --size=8196  --name=var_vol
logvol  /tmp  --vgname=system  --size=2048  --name=tmp_vol
logvol  /  --vgname=system  --size=100  --grow  --name=root_vol

# reboot when installation completes
reboot

# Install the Core software packages, aka "minimal", plus a couple extras
%packages
# minimal
@core
@server-policy
#@base
#@network-file-system-client
#@server-policy
%end

%pre
# redirect debugging output to tty3
#exec < /dev/tty3 > /dev/tty3
#chvt 3

%post --log=/var/tmp/install.log
# redirect debugging output to tty3
#exec < /dev/tty3 > /dev/tty3
#chvt 3

echo "Creating CentOS-6.3-x86_64 post installation directory ..."
mkdir -p /opt/postinstall

echo "Downloading CentOS-6.3-x86_64 post installation files ..."
cd /opt/postinstall
wget http://192.168.111.1/kickstart/postinstall/CentOS-6.3-x86_64-postinstall.tgz
tar zxf CentOS-6.3-x86_64-postinstall.tgz
rm CentOS-6.3-x86_64-postinstall.tgz > /dev/null 2>&1

echo "Executing CentOS-6.3-x86_64 post installation script ..."
./CentOS-6.3-x86_64-postinstall >> CentOS-6.3-x86_64-postinstall.out 2>&1
echo "Done."
-- end example /export/anaconda/cfg/CentOS-6.3-x86_64-ks.cfg--

# 32-bit
vi /export/anaconda/cfg/CentOS-6.3-i386-ks.cfg

-- begin example /export/anaconda/cfg/CentOS-6.3-i386-ks.cfg--
# Example kickstart configuration file for a RHEL 6.3 i386 (32-bit) standard install.
#

install

# Specifies the language
lang en_US.UTF-8

# Specifies the keyboard layout
keyboard us

# Skip Red Hat subscriber key input
key --skip

# Forces the text installer to be used (saves time)
text

# Forces the cmdline installer to be used (debugging)
#cmdline

# Skips the display of any GUI during install (saves time)
skipx

# Used with an HTTP install to specify where the install files are located
url --url http://192.168.111.1/anaconda/CentOS-6.3-i386

# Assign a static IP address upon first boot & set the hostname
network --onboot yes --bootproto dhcp --hostname rhel63

# Give the second interface a DHCP address (if you are not using a second interface comment this line out)
#network --device eth1 --bootproto=dhcp

# Set the root password
rootpw r00tp@55w0rd

# Enable the firewall and open port 22 for SSH remote administration
firewall --enabled --port=22:tcp

# Setup security and SELinux levels
#authconfig --enableshadow --enablemd5
authconfig --enableshadow --passalgo=sha512

selinux --disabled

# Set the timezone
timezone --utc Etc/UTC

# Create the bootloader in the MBR with drive sda being the drive to install it on
bootloader --location=mbr --driveorder=sda,sdb --append=audit=1

# Wipe all partitions and build them with the info below
clearpart --all --initlabel

#Disk partitioning information
zerombr

# Create primary partitions
part /boot --fstype ext4 --size=500 --asprimary --ondisk=sda
part swap --size=4096 --asprimary --ondisk=sda
part pv.01 --size=100 --grow --asprimary --ondisk=sda
# use the entire second disk for swap
#part swap --size=100 --grow --ondisk=sdb

# Create LVM logical volumes
volgroup system --pesize=32768 pv.01
logvol  /var  --vgname=system  --size=8196  --name=var_vol
logvol  /tmp  --vgname=system  --size=2048  --name=tmp_vol
logvol  /  --vgname=system  --size=100  --grow  --name=root_vol

# reboot when installation completes
reboot

# Install the Core software packages, aka "minimal", plus a couple extras
%packages
# minimal
@core
@server-policy
#@base
#@network-file-system-client
#@server-policy
%end

%pre
# redirect debugging output to tty3
#exec < /dev/tty3 > /dev/tty3
#chvt 3

%post --log=/var/tmp/install.log
# redirect debugging output to tty3
#exec < /dev/tty3 > /dev/tty3
#chvt 3

echo "Creating CentOS-6.3-i386 post installation directory ..."
mkdir -p /opt/postinstall


echo "Downloading CentOS-6.3-i386 post installation files ..."
cd /opt/postinstall
wget http://192.168.111.1/kickstart/postinstall/CentOS-6.3-i386-postinstall.tgz
tar zxf CentOS-6.3-i386-postinstall.tgz
rm CentOS-6.3-i386-postinstall.tgz > /dev/null 2>&1

echo "Executing CentOS-6.3-i386 post installation script ..."
./CentOS-6.3-i386-postinstall >> CentOS-6.3-i386-postinstall.out 2>&1
echo "Done."
-- end example /export/anaconda/cfg/CentOS-6.3-i386-ks.cfg--

Step 15) Finish configuring the PXE boot environment


cp /usr/share/syslinux/pxelinux.0 /export/anaconda/tftpboot/
cp /usr/share/syslinux/menu.c32 /export/anaconda/tftpboot/
# 64-bit
cd /export/anaconda/tftpboot/CentOS-6.3-x86_64/
cp /export/anaconda/media/CentOS-6.3-x86_64/images/pxeboot/* .
# 32-bit
cd /export/anaconda/tftpboot/CentOS-6.3-i386/
cp /export/anaconda/media/CentOS-6.3-i386/images/pxeboot/* .

Step 16) Enable services


chkconfig dhcpd on
chkconfig httpd on
chkconfig xinetd on
service dhcpd restart
service httpd restart
service xinetd restart
reboot

Step 17) PXE Boot the install clients


o   Different hardware manufacturers have different methods for invoking PXE network booting.
o   Make sure to verify the client’s MAC address is in /etc/dhcp/dhcpd.conf and that you’ve restarted dhcpd (e.g. service dhcpd restart).
o   If everything’s correct then you should see screens similar to the following screen shots.