Kickstart Tutorial – Practical Examples for RHEL 7 / CentOS 7

Yum – find out which RPM package provides particular file or command
Linux installation can be performed totally unattended using Kickstart file, which contains configuration, required setup and post installation tasks to fully automate installation process without being prompted for any input details. Kickstart file can be placed in the remote repository or can be included in ISO image in order to be read by Anaconda installer during system installation.

In this tutorial we present some practical solutions that can be placed in kickstart file to automate CentOS 7 / Red Hat 7 installation tasks.

At the very beginning let’s take a look at this kickstart file: ks.cfg, which is a complete and working set of commands and functions that let us perform hardware detection, unattended disk partitioning, additional RPMs installation, kernel parameters configuration, etc…

This file can be used as it is, without any modifications and this will do the whole automated installation job, but let’s break it down into pieces to describe particular use cases:

  • Skip GUI X server installation in kickstart file
  • To skip X Window Server installation, place the following in kickstart’s header section:

    skipx
  • How to add new user in kickstart file?
  • To add new user to the installed system, use the following option in kickstart’s header section:

    user --name=tuxoper --password=$1$qrBNJr0C$8J4stpPzjQZywX33wnMn7. --iscrypted
  • Install / add custom RPM packages in kickstart file
  • Additional RPM packages to install can be placed in %packages section right below @base package:

    %packages
    @base
    policycoreutils-python
    libseccomp
    PyYAML-3.10-11.el7
    python-jinja2
    python-pyasn1
    nfs-utils
    lksctp-tools
    pexpect
    screen
    nmap-ncat
    telnet
    lftp
    lshw
    tmux
    cairo
    numactl
    perf
    ltrace
    dstat
    iotop
    iptraf-ng
    net-snmp-utils
    lldpad
    %end
  • How to detect existing partition table (existing systems) on the disk in kickstart file?
  • If you want to avoid accidental reinstallation of already installed operating system, you can check whether there is any existing partition table on the disk using kpartx or partx:

    %pre --erroronfail --log=/tmp/ks-pre.log
    part_table=$(kpartx -r /dev/sda)
    if [ -n "$part_table" ]; then
     whiptail --fb --title "WARNING" --yesno --defaultno "This system contains partition table. Installation will DELETE EXISTING DATA on this system. Continue?" 12 50 > /dev/console
     if [ $? -ne 0 ]; then
      reboot
     fi
    fi
  • Hardware detection and hard disk capacity check in kickstart
  • The below example shows, how to detect hardware type, verify hard disk capacity and apply different partitioning scheme based on detected hardware type.

    For hardware detection we are using here virt-what command, which checks the type of detected hardware (bare metal, Virtualbox, VMware). virt-what, unlike other similar commands (i.e. dmidecode), displays already parsed output, so it’s pretty convenient in such use cases.

    Partitioning for bare metal depends also on the detected tux_node_type parameter, which is being read from kernel command line parameters included in GRUB 2 menu entries. For virtual hardware detected (VirtualBox, VMware), auto partitioning is applied. Partitioning instructions for each case are redirected to /tmp/part-include file, which is included in header section of kickstart file:

    # === include partitioning scheme generated in pre ===
    %include /tmp/part-include
    # ====================================================

    Kickstart also detects if minimum hard disk capacity requirements are met by comparing hard disk capacity parameter with bm_storage_min_size for bare metal and vm_storage_min_size for virtual hardware detected. capacity parameter is parsed from fdisk command.

    For VMware hardware detected, open-vm-tools information is redirected to /tmp/virtual file, which can be included in %packages section to install open-vm-tools RPM package for VMware only:

    # === open-vm-tools installation for vmware only ===
    echo "open-vm-tools" > /tmp/virtual

    The above solution requires placing dummy replacement of /tmp/virtual files for bare metal and VirtualBox to avoid installation failure, since open-vm-tools are not supposed to be installed in these two cases:

    # === open-vm-tools dummy replacement for bare metal ===
    echo "" > /tmp/virtual
    # === open-vm-tools dummy replacement for virtualbox ===
    echo "" > /tmp/virtual

    The whole hardware detection and hard disk capacity verification code is placed in %pre section of kickstart file:

    # === storage minimum capacity settings ===
    bm_storage_min_size=400
    vm_storage_min_size=16
    # =========================================
    
    sleep 20
    hw=$(virt-what | head -1)
    sleep 10
    
    # === read tux_node type from grub menuentry parameter ===
    tux_node_type=$(cat /proc/cmdline | cut -f 3 -d '=' | cut -f 1 -d ' ')
    
    if [ -z "$hw" ]; then 
     whiptail --infobox --title "HARDWARE DETECTION" "Detected hardware: Bare Metal" 10 40 > /dev/console
     sleep 10
     capacity=$(fdisk -l | grep /dev/sda | cut -f 3 -d " " | cut -f 1 -d ".")
     sleep 1
     if [ "$capacity" -lt "$bm_storage_min_size" ]; then
      whiptail --infobox --title "HARD DISK REQUIREMENTS" "ERROR: Minimum hard disk capacity for Bare Metal installation is $bm_storage_min_size GB. Will reboot now." 10 50 > /dev/console
      sleep 15
      reboot --eject
     else
      # === open-vm-tools dummy replacement for bare metal ===
      echo "" > /tmp/virtual
      if [ "$tux_node_type" == "manager" ]; then
       # =================== generate partitioning scheme for bare metal ==========================
       # partitioning intentionally removed to simplify analysis
       # ===========================================================================================
       elif [ "$tux_node_type" == "collector" ]; then
       # =================== generate partitioning scheme for bare metal ==========================
       # partitioning intentionally removed to simplify analysis
       # ===========================================================================================
      fi
     fi
    elif [ "$hw" == "vmware" ]; then
     whiptail --infobox --title "HARDWARE DETECTION" "Detected hardware: VMWare" 10 40 > /dev/console
     sleep 10
     capacity=$(fdisk -l | grep /dev/sda | cut -f 3 -d " " | cut -f 1 -d ".")
     sleep 1
     if [ "$capacity" -lt "$vm_storage_min_size" ]; then
      whiptail --infobox --title "HARD DISK REQUIREMENTS" "ERROR: Minimum hard disk capacity for VMWare installation is $vm_storage_min_size GB. Will reboot now." 10 50 > /dev/console
      sleep 15
      reboot
     else
      # === open-vm-tools installation for vmware only ===
      echo "open-vm-tools" > /tmp/virtual
      # ============== generate partitioning scheme for vmware ====================================
      echo "autopart" > /tmp/part-include
      # ===========================================================================================
     fi
    elif [ "$hw" == "virtualbox" ]; then
     whiptail --infobox --title "HARDWARE DETECTION" "Detected hardware: VirtualBox" 10 40 > /dev/console
     sleep 10
     capacity=$(fdisk -l | grep /dev/sda | cut -f 3 -d " " | cut -f 1 -d ".")
     sleep 1
     if [ "$capacity" -lt "$vm_storage_min_size" ]; then
      whiptail --infobox --title "HARD DISK REQUIREMENTS" "ERROR: Minimum hard disk capacity for VirtualBox installation is $vm_storage_min_size GB. Will reboot now." 10 50 > /dev/console
      sleep 15
      reboot
     else
      # === open-vm-tools dummy replacement for virtualbox ===
      echo "" > /tmp/virtual
      # ============== generate partitioning scheme for virtualbox ================================
      echo "autopart" > /tmp/part-include
      # ===========================================================================================
     fi
    else
     whiptail --infobox --title "HARDWARE DETECTION" "WARNING: This Operating System is not released for recognized hardware: $hw. Will reboot now." 10 40 > /dev/console
     sleep 10
     reboot
    fi
  • Set UEFI based custom partitioning scheme in kickstart file
  • The below partitioning layout is designed for UEFI boot based servers, since it contains EFI / UEFI system partition. EFI / UEFI partition should be VFAT type partition with the minimum capacity of 200 MB.

    The next one is a primary /boot partition with the capacity of 512 MB, this partition can’t be included in LVM volume groups.

    Next the physical volumes pv.00 and pv.01 are created to provide physical extents for accordingly vg_root and vg_app volume groups. Capacity of pv.00 is set to fixed size: 150 GB, pv.01 from the other hand starts from 1 MB, but the grow parameter makes it fill up the whole remaining disk space.

    Volume groups: vg_root and vg_app are created accordingly on pv.00 and pv.01 physical volumes.

    Logical volumes (swap, /var, /home, etc…) are created on both volume groups with fixed sizes and file system options. Additionally /var mount point capacity is set to 1 MB and has parameter grow assigned, that means, /var directory will fill up the whole remaining volume group space.

    Each line of the below block is placed in /tmp/part-include file which is being read in kickstart file header:

    # === include partitioning scheme generated in pre ===
    %include /tmp/part-include
    # ====================================================

    If you have many partitions in your configuration (like the below), consider also putting everything in HERE or EOF block of code.

    Here is our example partitioning scheme:

    # =================== generate partitioning scheme for bare metal ==========================
    echo "part /boot/efi --size=200 --ondisk=sda --fstype=vfat --label=EFIBOOT" > /tmp/part-include
    echo "part /boot --size=512 --ondisk=sda --asprimary --fstype=ext4 --label=boot --fsoptions=acl,user_xattr,errors=remount-ro,nodev,noexec,nosuid" >> /tmp/part-include
    echo "part pv.00 --size=150000 --asprimary --ondisk=sda" >> /tmp/part-include
    echo "part pv.01 --size=1 --grow --asprimary --ondisk=sda" >> /tmp/part-include
    echo "volgroup vg_root pv.00" >> /tmp/part-include
    echo "volgroup vg_app pv.01" >> /tmp/part-include
    echo "logvol swap --name=swap --vgname=vg_root --size=32000" >> /tmp/part-include
    echo "logvol / --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=30000 --name=root --vgname=vg_root" >> /tmp/part-include
    echo "logvol /var --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=1 --grow --vgname=vg_root" >> /tmp/part-include
    echo "logvol /var/log --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=20000 --vgname=vg_root" >> /tmp/part-include
    echo "logvol /var/log/audit --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=20000 --vgname=vg_root" >> /tmp/part-include
    echo "logvol /var/crash --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=24000 --vgname=vg_root" >> /tmp/part-include
    echo "logvol /home --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=2000 --vgname=vg_root" >> /tmp/part-include
    echo "logvol /var/docker-volumes --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=100000 --vgname=vg_app" >> /tmp/part-include
    echo "logvol /var/esdata --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=50000 --vgname=vg_app" >> /tmp/part-include
    echo "logvol /var/lib/docker --fstype=ext4 --fsoptions=acl,user_xattr,errors=remount-ro --size=16000 --vgname=vg_app" >> /tmp/part-include
    # ===========================================================================================
  • Additional RPM packages installation in kickstart file
  • If you need to install extra packages not included in standard RHEL 7 / CentOS 7 ISO image, you can place them in the custom directory on ISO image, i.e.: mounted_iso_main_dir/soft/… and invoke their installation in %post nochroot section of kickstart file.

    Note: this part of package installation must be executed in nochroot environment, since we need to have access to installation media.

    cd /run/install/repo/soft/docker
    rpm -ivh --root /mnt/sysimage *.rpm
    cp docker-compose /mnt/sysimage/usr/local/bin/
    chmod 755 /mnt/sysimage/usr/local/bin/docker-compose
    cd /run/install/repo/soft/ansible
    rpm -ivh --root /mnt/sysimage *.rpm
    cd /run/install/repo/soft/utils
    rpm -ivh --root /mnt/sysimage python-GnuPGInterface*.rpm
    rpm -ivh --root /mnt/sysimage python-lockfile*.rpm
    rpm -ivh --root /mnt/sysimage ncftp*.rpm
    rpm -ivh --root /mnt/sysimage python2-pyasn1*.rpm
    rpm -ivh --root /mnt/sysimage python2-rsa*.rpm
    rpm -ivh --root /mnt/sysimage python2-boto*.rpm
    rpm -ivh --root /mnt/sysimage ngrep*.rpm
    rpm -ivh --root /mnt/sysimage librsync*.rpm
    rpm -ivh --root /mnt/sysimage duplicity*.rpm
    rpm -ivh --root /mnt/sysimage duply*.rpm
    cd /run/install/repo/soft/performance
    rpm -ivh --root /mnt/sysimage *.rpm
  • Enable / disable service after installation in kickstart file
  • Services can be easily managed in kickstart file to be executed right after installation by placing them in %post chroot section, since all the mentioned commands are executed in newly installed system (outside installation media):

    # === enable docker service ===
    systemctl enable docker.service
    # === disable RHN unit services
    systemctl disable rhnsd.service rhsmcertd.service
    # === disable postfix unit service ===
    systemctl disable postfix.service
  • Add user to sudoers during installation in kickstart file
  • Regular user can be added to the wheel group for elevated administrative privileges and become a sudoer by redirecting apropriate strings to /etc/sudoers file:

    # === add tuxoper to sudoers ===
    echo "# Allow tuxoper to run any commands anywhere" >> /etc/sudoers
    echo "tuxoper   ALL=(ALL)   NOPASSWD: ALL" >> /etc/sudoers
  • Generate SSH key (key pair) for particular user in kickstart file
  • To generate SSH keys via kickstart file for a user during system installation, execute SSH key creation command on behalf of the destination user. The below command presents SSH key creation without password for tuxoper user:

    # === set ssh keys for tuxoper ===
    su - tuxoper -c "ssh-keygen -t rsa -f /home/tuxoper/.ssh/id_rsa -N ''"
  • Configure kernel runtime parameters during installation in kickstart file
  • Kernel runtime parameters can be configured in kickstart file to be enabled right after installation by placing particular parameter lines in /etc/sysctl.conf file:

    echo "kernel.exec-shield = 1" >> /etc/sysctl.conf                       
    echo "kernel.randomize_va_space = 2" >> /etc/sysctl.conf                        
    echo "net.ipv4.ip_forward = 0" >> /etc/sysctl.conf                              
    echo "net.ipv4.conf.all.send_redirects = 0" >> /etc/sysctl.conf
    echo "net.ipv4.conf.default.send_redirects = 0" >> /etc/sysctl.conf

    2 thoughts on “Kickstart Tutorial – Practical Examples for RHEL 7 / CentOS 7

    1. imran raza khan April 9, 2019 at 15:20

      Nice article and it helped me lot, One observation “–erroronfail” not working for pre section
      %pre –erroronfail –log=/tmp/ks-pre.log
      it gives error
      ImportError: No module named updates_disk_hook

      As soon as i removed it it start working
      Below works fine
      %pre –log=/tmp/ks-pre.log

      • Grzegorz Juszczak April 9, 2019 at 22:03

        Hi Imran

        Thanx for remark, it has been a while since I wrote this article, so maybe something has changed in the distro since then, anyway I will take a look if I have a moment.

    Leave a Reply

    Name *
    Email *
    Website

    This site uses Akismet to reduce spam. Learn how your comment data is processed.