How
to create a single CD for fast and easy customized
installation.
Installing Linux is a
relatively easy task. However, I was faced with the task
of installing it on multiple machines repeatedly, which
is time consuming and prone to errors. This problem
affected our whole group and other groups that relied on
us. So I started using Red Hat Kickstart to automate the
installs. This helped, but there still was room for
improvement. What I ultimately wanted was an automated
installation that would fit on one CD, dynamically
partition the hard drives and contain all of the updated
packages. I wanted to be able to start an installation
then walk away from the machine, returning only when it
was done. To accomplish this, I supplemented Kickstart
with a customized version of the Red Hat installation
program, Anaconda.
Although not officially supported, Red Hat has made
available several tools and documentation to assist in
customizing an installation. I describe a few of the
possible ways to do this here, which should give the
reader enough information to get started.
The following topics are covered in this article:
replacing packages with updates, reducing the
installation size to fit on one CD, utilizing Kickstart
in the custom installation and creating a custom message
screen.
The reader should have a good understanding of Linux
installations in general. I also assume that no esoteric
hardware is being used, as other customizations may be
needed to accommodate such hardware.
Setting Up the Build Machine
The first step is to prepare the build computer.
Because the installer tools are specific to a particular
release, the build computer needs to have the same Red
Hat release as the one used on the target(s). For our
example, Red Hat 8.0 is being used. There are some
differences between Red Hat 8.0 and previous versions,
and you need to investigate them if you use a previous
version.
Once the build computer has the correct release
installed, the Anaconda packages need to be installed.
These usually are not installed by default, so they need
to be manually installed. They are located on the second
CD of the standard Red Hat distribution and are named
anaconda, anaconda-runtime and anaconda-help (optional).
The next step is to create a directory structure
where the installation files will be located. The
partition should have adequate space available,
approximately 3GB. The actual location is based on your
preference; for this article, the base directory is
located at /RH80. Under this directory, we create
directories for each of the CDs:
mkdir -p /RH80/CD{1,2,3}
We are not concerned with the source packages, so
CD4 and CD5 are not included.
We make an additional directory where we can create
the custom installation:
mkdir /RH80/ONE_CD
Now we can copy the contents of the CDs to the
respective directories. Mount the first CD, then issue
this command:
cp -a /mnt/cdrom/* /RH80/CD1/
Repeat this step for CD2 and CD3.
Copy the contents of the CD directories to the ONE_CD
directory, but hard link them instead of actually
copying the files. This saves space and is quicker:
cd /RH80
cp -al CD1/* ONE_CD/
cp -al CD{2,3}/RedHat/RPMS/* ONE_CD/RedHat/RPMS/
You'll get an overwrite TRANS.TBL message; you can
answer no.
Selecting the Packages
Next we trim down the contents of the ONE_CD
directory so it fits on one CD. I assume the CD size to
be 700MB. I will not go into detail on how to do this,
as the list of files to remove from the distribution is
different from one installation to another. However,
here are some tips for trimming down the distribution:
- Don't include the source RPMs.
- Remove the dosutils directory, as these will be
automated installs.
- Remove any unnecessary packages. This can be
complicated, because you need to make sure that the
dependencies are still intact.
You should keep a record of the files that were
removed. You can use this list in case you need to back
out, and you will need it later if you edit the
comps.xml file.
For the package selection, I logged to a file all of
the base and core group packages with their dependencies
(according to the comps.xml file). In order to find this
information, I used the script getGroupPkgs.py (see
Resources):
cd /RH80/ONE_CD/RedHat/base
getGroupPkgs.py comps.xml > /RH80/pkglist
Any additional package names can be appended to
the end of this file. After my list was complete, I
removed the packages not on the list by using the
syncRpms.py script (see Resources). The arguments are
the package directory and the list of packages is
generated from getGroupPkgs.py. This script removes the
packages not listed in the package list and prints out
the package names. We redirect that to a file so we have
a log:
cd /RH80
syncRpms.py ONE_CD/RedHat/RPMS/ pkglist > pkgs_rem
We can monitor the installation size by using the
du command. The -h option displays the result in human
readable format, and the -s option gives a summary of
the whole directory tree:
du -hs /RH80/ONE_CD
The hdlist files actually decrease in size after
they are regenerated (see below), because we removed
many of the packages. This in turn reduces the size of
the CD image.
The tricky part about removing packages is they may
break dependencies. Even though getGroupPkgs.py resolved
the dependencies base on the comps.xml file, they are
not guaranteed to be accurate. Adding additional
packages may break dependencies as well. One way to
verify their accuracy is to create a temporary RPM
database, and then do a test install on that database
with the packages you have selected:
cd /RH80/ONE_CD/RedHat/RPMS
mkdir /tmp/testdb
rpm --initdb --dbpath /tmp/testdb
rpm --test --dbpath /tmp/testdb -Uvh *.rpm
Look for any error messages regarding failed
dependencies. If any appear, resolve the dependencies by
either adding or removing files that caused the
discrepancy, and repeat the above test.
Once the package dependencies have been resolved, you
can download the package updates pertinent for your
installation. Put these files under a separate
directory:
mkdir -p /RH80/updates/RPMS/
Remove the old files from the build directory and
then link the updated files to the build directory. Do
this for each updated package (where old_rpmfile
is the previous version of the package):
cd /RH80/ONE_CD/RedHat/RPMS/
rm
# ... remove each old rpm
cd /RH80/updates/RPMS/
cp -l
# ... do this for each rpm
You should keep a record of the updated packages,
in case you need to back them out. It's also a good idea
to check the dependencies and size one more time, in
case they changed after the packages were updated.
Next, we check the internal checksum of each package
with the -K option to rpm. First we need to import the
key:
cd /RH80/ONE_CD/RedHat/RPMS
rpm --import /usr/share/rhn/RPM-GPG-KEY
rpm -K *.rpm | grep "NOT *OK"
This isn't strictly necessary, but because we
downloaded package updates, this verifies they are
valid.
Preparing the Installation Files
Once all of the packages have been updated, we need
to regenerate the hdlist files. They contain only the
headers of the packages, which allows Anaconda to
retrieve the header information more quickly. Because we
updated packages, we need to regenerate these files with
the genhdlist tool, which is part of the
anaconda-runtime package:
/usr/lib/anaconda-runtime/genhdlist /RH80/ONE_CD/
Next we need to handle the comps.xml file. This
file defines package groups and package dependencies
(although they are not guaranteed). The file structure
was changed in Red Hat 8.0 to be XML-based; in previous
releases it was only a simple text file with some
obscure tags. We need to ensure that packages defined
within groups are included in our installation. We need
to be concerned only with groups we are installing. If
packages are missing (or if packages were added), we
need to edit the comps.xml file (see Resources). Because
we chose all of the packages in the Core and Base
groups, however, we don't need to edit this file. We
simply need to specify those groups under the %packages
directive in the Kickstart file. See Listing 1 for an
excerpt from the Kickstart file.
Listing 1. Excerpt from the Kickstart File
Technically, we can leave out the @Core and @Base
groups, as they are installed by default. They are
included here for illustrative purposes.
Creating a Custom Message Screen
We also want to create a custom message screen to
give the user special instructions. The message screens
are kept in the boot.img file (for CD-ROM installs)
under the images directory. This is a DOS filesystem, so
we can mount it to get to the contents:
cd /RH80/ONE_CD/images
mount -o loop -t msdos boot.img /mnt/boot
Looking in /mnt/boot, you see six message files:
boot.msg, options.msg, general.msg, param.msg,
rescue.msg and snake.msg. We create our own message file
and call it custom.msg, an arbitrary name. Because
snake.msg isn't really used, we replace that entry
within syslinux.cfg with custom.msg. Edit syslinux.cfg
in /mnt/boot and replace F7 snake.msg with F7
custom.msg.
A few other modifications were made to the
syslinux.cfg file; refer to Listing 2. The default entry
was changed from linux to ks. If the timeout occurs or
if the user presses Enter at the boot prompt, then the
ks label is used. Additionally, the timeout value was
decreased from 600 to 60, so the installation can start
sooner if there is no input from the user. The display
entry was changed as well. Instead of boot.msg being the
initial message screen, we wanted our custom message to
be displayed. For the append line under the ks label, we
added two things. The first is the keyword text, to
enable text-based installs. Then we changed the keyword
ks to ks=cdrom:/ks.cfg. This hard codes the Kickstart
location so the user doesn't have to specify it at the
boot prompt.
Listing 2. Modified syslinux.cfd File
Next we create our custom.msg file. Listing 3 shows
our custom.msg. The contents of the file can be marked
up, such as adding color around words. For example,
^O09Custom^O02 changes the color of Custom to blue, and
^O02 changes it back. See the syslinux reference in the
Resources section for more information.
Listing 3. Custom Message
Once we have composed the custom message, we need to
umount the boot image:
umount /mnt/boot
Building the CD
Before actually creating the CD, you may want to test
it by doing a network install. See the Red Hat Kickstart
documentation on how to do this.
We want this custom installation to be automated, so
we put the Kickstart file on the CD itself. You can
create the Kickstart file with any text editor, or you
can use the GUI tool called Kickstart Configurator.
In the %pre section, add a shell script to probe the
hard drives and dynamically create the partition
information based on the number of drives. We take
advantage of the fact that Kickstart executes the %pre
section and then re-reads the Kickstart file. When it
reads it for the second time, it includes the
/tmp/partinfo file where the %include directive is
located (see Listing 1). The /tmp/partinfo file is the
output from the script. We use the list-harddrives
command, which lists the available hard drives and their
sizes. Having the partition created dynamically frees us
from having to create multiple Kickstart files that hard
code the partition information.
Once the Kickstart file is created, name it ks.cfg
and place it in the root directory of our installation
tree (/RH80/ONE_CD/). It is possible to create more than
one Kickstart file and place all of them on the CD.
Different Kickstart files might address different
hardware configurations.
We can now create the ISO image. From our previous
steps, the distribution should be small enough to fit on
one CD and contain all of the updated packages. The
mkisofs program creates the image, and then we can copy
the image to the CD. The command to create the ISO image
is:
cd /RH80/ONE_CD
mkisofs -r -T -J
-V "My Custom Installation CD"
-b images/boot.img
-c images/boot.cat
-o /RH80/mydist.iso
/RH80/ONE_CD
Refer to Table 1 for a description of the options.
Table 1. Options Used for mkisofs
The last parameter to mkisofs is the source directory
of the contents that need to be included in the image
file (e.g., our custom installation directory). Several
other parameters are available that you may want to use.
For example, the -A, -P and -p options add additional
labeling information to the image. The -m and -x options
also allow you to exclude certain directories and file
patterns from the image. See the mkisofs man page for
additional information.
Next, add a checksum to the ISO image. This is not
strictly necessary, but it provides a way for end users
to check the integrity of the CD. The tool to add a
checksum to the ISO image is called implantisomd5. To
add a checksum to the ISO image, use the following
command:
implantisomd5 /RH80/mydist.iso
A companion tool, checkisomd5, can be used to
verify the checksum for you:
checkisomd5 /RH80/mydist.iso
The CD also can be verified during the
installation. After booting from the CD, the user can
issue this command:
linux mediacheck
Now we can burn the image to the CD. I assume the
CD writer is already set up on your system. We use
cdrecord below, but you can use other programs as well.
The command is invoked as:
cdrecord -v speed=4 dev=0,0,0 /RH80/mydist.iso
The speed and dev options depend on your system.
The device for the dev argument can be determined by
using the -scanbus option to cdrecord:
cdrecord -scanbus
Using the CD
Once the image is burned onto the CD, insert the CD
into the target machine and boot the machine. You should
get the custom message that you created earlier. At this
point, you can either press Enter at the boot prompt or
let it timeout. When it times out it uses the default
label, which we specified as ks (Kickstart).
If we did everything right, the installation should
proceed without user interaction. In my experience, the
installation takes approximately ten minutes. This may
differ depending on your exact configuration.
Conclusion
With a combination of Kickstart and a customized
Anaconda, a powerful and flexible installation can be
created. This installation greatly improved cycle time
and reduced errors for my project. I was able to install
multiple machines, multiple times almost effortlessly.
In this article, I touched on only a few ways to take
advantage of Kickstart and Anaconda, but there are many
other possibilities. I encourage those interested to
read the documentation in the Resources section and to
join the Kickstart and Anaconda mailing lists for
further information.
Resources
Brett Schwarz lives near
Seattle, Washington, with his wife, son and dog.
Although he is familiar with multiple platforms, his
platform of choice is Linux. He is a computer and
wireless systems consultant. He can be contacted via
his home page at http://www.bschwarz.com/.