Building a customised Red Hat install disc G.R.Keech 2006-04-24 Scope This document describes how to prepare a customised Red Hat Enterprise Linux (RHEL) CD. The resultant disc can be used to install a minimal RHEL version 4 system with: a. automated custom installation using kickstart; b. a single CD instead of four; c. custom packages on the disc. This document. The latest version of this document can be found from http://people.redhat.com/rkeech/custom-distro-simplified-el4.txt. An alternative, more elaborate procedure can be found at http://people.redhat.com/rkeech/custom-distro.txt-el4 This procedure applies equally to all flavours of Enterprise Linux 4 (ie AS, ES, WS, Desktop). This procedure might work for Fedora Core, but I cannot vouch for it. Limitations. This simplified build system is limited in that packages in the distro cannot directly be substituted with different versions, because this method relies on not modifying the installer's database of packages (the hdlist files). Summary Procedure Building a custom install disc involves: a. creating an install tree of the distro in the same way you would when configuring a network install server; b. remove redundant packages from the install tree; c. add extra packages, kickstart config file and discinfo file; d. update labels and version strings; e. run mkisofs; f. burn ISOs as required. Detailed Procedure The Install Tree. The install tree is prepared by copying the normal install discs into a single tree in the same manner as preparing a system to serve network installations Refer to: http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/x8664-multi-install-guide/s1-steps-network-installs.html However, the build tree in this case also requires the isolinux files. Definitions. For the purposes of this document, the directory in which the install tree is put is refered to as $RHROOT. $RPMDIR corresponds to ${RHROOT}/RedHat/RPMS. $EXTRASDIR corresponds to ${RHROOT}/extra-pkgs. Required packages. The mkisofs and cdrecord packages are required. If you want the resultant CD image to have an MD5 checksum, then the anaconda-runtime package will be required for the implantisomd5 utility. Trim down package set. RPM package files should be removed from $RPMDIR so that only those required in the install are left, being mindful of the need to keep the total size under that required to fit on one CD. The suggested way to do this is to: * perform an initial manual installation representing the system to be built; * erase and install other packages from the installed system as required, keeping record of this for the kickstart %packages section. * prepare a package listing using "rpm -qa" * split the package listing into those packages from the Red Hat distro discs (Set 1), and those sourced separately (Set 2). Any Red Hat-provided errata packages are in Set 2, not Set 1. * creating and comparing lists of packages is discussed at Appendix 3. * Remove packages not in Set 1 from $RPMDIR * Create $EXTRASDIR and copy all packages from Set 2. %packages. The Kickstart file's %packages section must agree with the set of files in $RPMDIR. Extra packages files in $RPMDIR will not break the installation, but may take up valuable disc space. Packages referenced in %packages but not in $RPMDIR will cause the installation to fail. Packages may be referenced implicitly in %packages. Add Kickstart file. The directory tree under ${RHROOT} will become the ISO filesystem so it is here that any final customisations should be made. This includes the addition of any optional kickstart files. An example kickstart file is included at Appendix 1. Multiple kickstart files. It may be useful to have multiple kickstart files representing related alternative configurations. It is straightforward to build these from a common baseline file. For example, there might be a kickstart file referencing SCSI disks, and another referencing IDE disks. Appendix 2 shows how to build these from a common source using m4 macros and a make file. Installing extras from Kickstart. Additional package files in $EXTRASDIR can be loaded at install time by creating a non-chrooted %post section in the Kickstart profile. The cdrom drive is available at install time as device "/tmp/cdrom". Packages can be copied from the cdrom to /mnt/sysimage/root/extras/. These can then be accessed in the normal (chrooted) %post section from /root/extras/ if required. Properly designed packages should be installable from the non-chroot'ed %post using the method below, however from experience, some third-party packages do not install properly in this way: rpm -ivh --nodeps --root /mnt/sysimage /mnt/source/extra-pkgs/*.rpm Remove any unwanted files from ${RHROOT}, eg: find ${RHROOT} -name "*~" -exec rm -f {} \; Isolinux.cfg. The kickstart profile can be referenced in the file ${RHROOT}/isolinux/isolinux.cfg as follows: label custom kernel vmlinuz append ks=cdrom:/ks.cfg initrd=initrd.img boot.msg. The boot.msg file in ${RHROOT}/isolinux is displayed when the install CD is first booted. This should be replaced or modified as required to identify your particular custom build. Version strings in this file should agree with any versioning in the mkisofs step below. Create discinfo file. In a multi-disc distro set, each disc is normally identified by the file .discinfo in the top-level directory. In this case, there is only one disc, but the installer's package database (hdlist*) is still configured to deal with multiple discs. To allow the installer to think that all discs are available, the line in .discinfo with the disc number can be replaced with "1,2,3,4". Here is an example .discinfo file that should work for all examples of this build system: 1128185472.900128 Red Hat Enterprise Linux 4 i386 1,2,3,4 RedHat/base RedHat/RPMS RedHat/pixmaps Mkisofs. The ISO file of the install tree can be created as follows: (Note the file customel4.iso will be created in the current directory, so cd as required) rm -f customel4.iso mkisofs -r -N -allow-leading-dots -d -J -T -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -V "RHEL4U3AS custom 1.0-9" \ -boot-load-size 4 -boot-info-table -o customel4.iso ${RHROOT} If required, add the checksum (this is usually not necessary): implantisomd5 customel4.iso Burn CD. The ISO can be burned to CD if required as follows: cdrecord -tao customel4.iso Speed and device options may apply here; modify command as required. Testing. The best way to test and refine this system is to use VMWare, which can directly mount the ISO image for installation. ================================================================================ Appendix 1 Example Kickstart configuration file This file would typically be named ks.cfg and placed in the root directory of the ISO filesystem ($RHROOT) ------------------------------------ ## Do not use this file directly as a kickstart file. It has M4 macros to be expanded ## before it can be used. Run make in the same directory as this file to ## create ks-ide.cfg and ks-scsi.cfg text keyboard us lang en_US langsupport --default en_US en_US #network --bootproto static --ip 10.10.10.32 --netmask 255.255.255.0 --nameserver 10.211.14.3 --gateway 10.10.10.254 --hostname sydapa2 #url --url http://10.211.14.3/rhel4u1es network --device eth0 --bootproto dhcp #nfs --server=192.168.0.254 --dir=/var/ftp/pub #nfs --server=192.168.0.254 --dir=/share/rhel4u3as-custom cdrom install zerombr yes clearpart --all #part swap --size 512 #part / --size 5000 #part /boot --size 100 # clearpart --all --drives=MYDISK part /boot --fstype ext3 --size=100 --ondisk=MYDISK part pv.5 --size=0 --grow --ondisk=MYDISK volgroup VolGroup00 --pesize=32768 pv.5 logvol swap --fstype swap --name=LogVol01 --vgname=VolGroup00 --size=288 --grow --maxsize=576 logvol / --fstype ext3 --name=LogVol00 --vgname=VolGroup00 --size=5024 # Mouse will usually just probe correctly #mouse genericps/2 --emulthree #mouse generic3ps/2 #mouse genericwheelusb --device input/mice timezone Australia/Melbourne --utc skipx #xconfig --resolution=1024x768 --depth=16 #xconfig --resolution=800x600 --depth=16 rootpw avaya authconfig --useshadow --enablemd5 #Packet filtering turned off initially. It should be turned on after installation. firewall --disabled bootloader #reboot #selinux --disabled %packages @ Administration Tools @ Server Configuration Tools @ System Tools @ Text-based Internet @ Web Server emacs postfix xorg-x11-font-utils ttmkfdir xorg-x11-xfs chkfontpath urw-fonts caching-nameserver screen rcs sharutils strace -dovecot -rp-pppoe -hpijs -gnome-pilot -gnome-meeting -openh323 -bluez-hcidump -bluez-bluefw -bluez-libs -bluez-utils -bluez-pin -irda-utils -rsh -rdate -isdn4k-utils -wvdial -ppp -tux -Omni -Omni-foomatic -system-config-printer -system-config-printer-gui -hal-cups-utils -desktop-printing -gimp-print -gimp-print-utils -linuxwacom -gnopernicus -ypbind -system-config-nfs -yp-tools -pcmcia-cs -pilot-link -fetchmail -ggv -gnome-audio -zlib-devel -libgcj-devel -kernel-devel -OpenIPMI -OpenIPMI-tools -wireless-tools -NetworkManager -NetworkManager-gnome -crash -autofs -specspo -nautilus-media -sendmail-cf -sendmail -xdelta -ckermit -gok -gnome-speech -gnome-kerberos -gnome-themes -gnome-mag -xorg-x11-tools -xterm -xorg-x11-twm -fonts-xorg-100dpi -fonts-xorg-75dpi -vim-enhanced -firstboot -system-config-soundcard -alsa-utils -foomatic -cadaver -tcsh -pdksh -zsh -xmlsec1 -xmlsec1-openssl -webalizer -httpd-manual -gnome-user-docs -fribidi -udapl -openmotif -OpenIPMI-libs -sane-backends -libieee1284 -libmusicbrainz #These packages required for Sun Java ES compat-libstdc++-296 %pre # This ensures that the partition table is empty. # It is done in case the partition table is initially corrupt # or missing. DEVICE=/dev/MYDISK mknod ${DEVICE} fdisk ${DEVICE} << EOF d 4 d 3 d 2 d 1 w EOF %post --nochroot ( echo in non-chrooted post section of kickstart [ -d /mnt/source ] || mkdir /mnt/source mount -o ro /tmp/cdrom /mnt/source cp -a /mnt/source/extra-pkgs /mnt/sysimage/root/ cp /mnt/source/localbin/* /mnt/sysimage/usr/local/bin rm -f /mnt/sysimage/usr/local/bin/TRANS.TBL # Note: Although it should be possible to install the extra packages here, # a packaging issue with the sun packages causes problems. So they are installed in the chroot-ed # post section. #rpm -ivh --nodeps --root /mnt/sysimage /mnt/source/extra-pkgs/sun/*.rpm umount /mnt/source ) >> /mnt/sysimage/root/postnochroot %post ( echo In chrooted post section of kickstart. HOSTNAME=s2-rhn-app01 IP=172.31.128.11 GW=172.31.1.1 NTP=172.26.30.30 DNS1=172.31.30.40 SMTP=172.21.3.1 DOMAIN=xyz netconfig -d eth0 --bootproto=none --ip=${IP} --netmask=255.255.0.0 --gateway=${GW} --hostname=${HOSTNAME}.${DOMAIN} --nameserver=127.0.0.1 # The following should not be necessary, but netconfig does not want to set the hostname cat << EOF > /etc/sysconfig/network NETWORKING=yes HOSTNAME=${HOSTNAME}.${DOMAIN} EOF cat << EOF > /etc/resolv.conf nameserver 127.0.0.1 search ${DOMAIN} EOF #netconfig -d eth1 --bootproto=dhcp #====================================================================== # extra RPM packages copied to /root/extra-pkgs in %pre --nochroot cd /root/extra-pkgs rpm -ivh misc/*.rpm #rpm -ivh --nodeps sun/*.rpm cd .. #rm -rf extra-pkgs #------------------------------------------------------------------------------- # Configure to run a caching-only nameserver to accelerate DNS requests. perl -pi -e 's#options {#options {\n forwarders { 172.26.30.40; };\n allow-query { 127.0.0.1; };\n allow-transfer { none; };#' /etc/named.conf #perl -pi -e 's#options {#options {\n forwarders { 203.1.108.1; };#' /etc/named.conf perl -pi -e 's#nameserver .*$#nameserver 127.0.0.1#' /etc/resolv.conf #perl -pi -e 's#nameserver .*$#nameserver 61.88.88.88#' /etc/resolv.conf echo "${IP} ${HOSTNAME} ${HOSTNAME}.${DOMAIN}" >> /etc/hosts #----------------------------------------------------------------------- #Add local user accounts for administrators. /usr/sbin/useradd -c "Fred Bloggs" fred echo blahblah | passwd --stdin fred #----------------------------------------------------------------------- #Setup NTP cat > /etc/ntp/step-tickers < /etc/ntp.conf <> /etc/motd echo "Authorized users only. All activity may be monitored and reported" >> /etc/issue.net #------------------------------------------------------------------------------- #Import GPG key for RHN. # This is required prior to first RHN registration. rpm --import /usr/share/rhn/RPM-GPG-KEY #------------------------------------------------------------------------------- chkconfig lm_sensors off chkconfig smartd off chkconfig gpm off chkconfig httpd off chkconfig kudzu off chkconfig nfs on chkconfig netfs on chkconfig portmap on chkconfig rpcidmapd on chkconfig snmpd on chkconfig named on chkconfig cups --del # These services need to be on, but for the sake of booting without # delay after installation, these have been turned off initially. # Turn them on later. chkconfig ntpd off chkconfig postfix off #----------------------------------------------------------------------- # Configure Postfix to relay any mail to the network's SMTP server postconf -e "myorigin = ${DOMAIN}" postconf -e "relayhost = ${SMTP}" #------------------------------------------------------------------------------- #Disable SELinux (once things are worked out, SELinux should be enabled) #perl -pi -e 's/^SELINUX=.*$/SELINUX=Disabled/' /etc/selinux/config #------------------------------------------------------------------------------- #Configure tcp wrappers host access to a mostly closed access policy. cat <> /etc/hosts.allow ALL:localhost sshd:ALL EOF cat <> /etc/hosts.deny ALL:ALL EOF #------------------------------------------------------------------------------- # Increase maximum number of open files per user. echo "* hard nofile 8000" >> /etc/security/limits.conf #------------------------------------------------------------------------------- # make mount point for shared volume mkdir /data groupadd -g 5000 support useradd -u 5000 -G support supop echo avaya | passwd --stdin supop mkdir /root/.ssh chmod 700 /root/.ssh #------------------------------------------------------------------------------- echo "This system was built with the ORGNAME standard build version VERSION" > /etc/soe-build-version echo Finished chrooted post section of kickstart. ) >> /tmp/post.log =============================================================================== Appendix 2 Derived kickstart files using m4 macros This describes how to derive kickstart configuration files from a common file using M4 macros. Multiple kickstart files. It may be useful to have multiple kickstart files representing related alternative configurations. It is straightforward to build these from a common baseline file. For example, there might be a kickstart file referencing SCSI disks, and another referencing IDE disks A file, say ks.cfg.m4, might be used with lines like the following: clearpart --all --drives=MYDISK This could then be used to derive ks.cfg with: m4 -D MYDISK=sda ks.cfg.m4 > ks-scsi.cfg m4 -D MYDISK=hda ks.cfg.m4 > ks-ide.cfg The selection of one or the other can be done in isolinux/isolinux.cfg with this sort of thing: label linuxide kernel vmlinuz append text ks=cdrom:/ks-ide.cfg initrd=initrd.img ramdisk_size=8192 label linuxscsi kernel vmlinuz append text ks=cdrom:/ks-scsi.cfg initrd=initrd.img ramdisk_size=8192 =============================================================================== Appendix 3 Managing package lists It is often useful to be able to manage lists of RPM packages to help with things like: * preparing the cut-down set of RPM package files; * determining which installed packages were sourced from outside the distro. 1. List of package names: rpm -qa --queryformat "%{name}\n" | sort | uniq > list1 The "sort|uniq" part will remove any duplicates, like kernel. 2. Determining which packages were installed after the OS was installed. rpm -qa --last | less This will show packages, sorted by the time of installation, with most recently installed packages first. 3. Determine package differences between two sets. If you have two sorted package lists that need to be compared, then the uniq command is helpful. eg, if list1 is an initial package list, and list2 is known to have only additional packages, then the extras can be determined with: cat list1 list2| sort | uniq -u 4. Package name from file name. If you have a list of package names, eg from the output of rpm -qa, and you need to strip the version information, then this can be done with: sed -n -s "s/^\(.*\)-.*-.*/\1/p" < /tmp/rpmqa This is useful for package lists which might, for example, go in the %packages section of the Kickstart file. =============================================================================== Appendix 4 Example makefile This makefile is put in the base of the install tree ($RHROOT). ------------------------------------------------------------------------------ VERSION = "20060421" RHEL = "4 AS Update 3" TMPISO = /tmp/tmpbuild.iso all: ../build.iso rm -f tmpfile.m4 tmpfile.m4: ks.cfg.m4 echo "#Do not edit this file directly. Edit the m4 file instead" > $@ grep -v "^##" $< >> $@ scsi: tmpfile.m4 m4 -D MYDISK=sda -D VERSION=$(VERSION) $< > ks-scsi.cfg ide: tmpfile.m4 echo #Do not edit this file directly. Edit the m4 file instead > ks.cfg m4 -D MYDISK=hda -D VERSION=$(VERSION) $< > ks-ide.cfg clean: rm -f tmpfile.m4 ks-scsi.cfg ks-ide.cfg boot.msg: isolinux/boot.msg: isolinux/boot.msg.m4 rm -f $@ m4 -D VERSION=$(VERSION) -D RHEL=$(RHEL) $< > $@ ../build.iso: scsi ide isolinux/boot.msg isolinux/boot.msg rm -f $(TMPISO) mkisofs -r -N -allow-leading-dots -d -J -T -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot \ -V $(VERSION) -boot-load-size 4 -boot-info-table -o $(TMPISO) . mv $(TMPISO) $@