Monday, July 01, 2019

Slimming Down RHEL 8 Image


I recently had a project that required the Red Hat Enterprise Linux 8 Binary DVD due to the package requirements.  This normally would not be an issue but there were further requirements that made this a bit more challenging.  Those requirements were that the image also needed to be under 4gb in size and could not be delivered via networking.   This sets up the challenge of trying to devise a way to take the DVD image which is over 6gb and par it down leaving only what is required behind.  The following will describe the process the I used to meets these requirements and while there might be other methods this was the procedure I used.

The first thing we need to do is download the RHEL 8 Binary DVD image to a running system.  Once on the system I created a directory called /rhel, mounted up the image and copied the contents to /rhel:

# mount ./rhel-8.0-x86_64-dvd.iso /mnt/ -o loop
# mkdir /rhel
# shopt -s dotglob
# cp -ai /mnt/* /rhel
# umount /mnt

The next step was to create a list of packages that I needed from an existing RHEL 8 system that was installed for the purpose of the project.   I just used a simple rpm command but formatted it just for the package name without the version.   The reason being is we just want the package name as versions might be different from image and current system due to applied errata on running system:

# rpm -qa --queryformat='%{NAME}\n' | sort -n > rhel8.lst

Now I need to get a list of packages from the RHEL 8 image and in this version there are two directories that hold packages: Appstream and BaseOS.  In my example I only needed to parse out the Appstream packages to gain enough image reduction.  So I will run the following command to grab the list:

# ls -1 /rhel/AppStream/Packages/*|xargs -n 1 basename > appstream.lst

Now that I have my two lists I needed to create some logic to be able to remove packages that I would not need and this required a comparison of the two lists.  The following script should be run from with in the /rhel directory and on successful comparison it will keep the matched packages in /rhel/AppStream/Packages.  If there is no match the package will be removed.

#!/bin/bash
while read package; do
    flag="0"
    while read rhel8; do
        if [[ "$package" =~ ^"$rhel8" ]]
        then
            flag="1"
            echo KEEP: $package $rhel8 $flag
            break
        fi
    done < rhel8.lst
    if [[ "$flag" = "0" ]]
    then
        echo REMOVE $package $rhel8 $flag
        find ./ -name $package -print -exec rm -r -f {} \;
    fi
done < appstream.lst

Now that we have removed the excessive packages from the /rhel directory structure, which if you recall is just the contents of the RHEL 8 image, we can now begin to make a new iso image.  But first since we changed the AppStream packaging we need to update the repository data.  We do this by using createrepo command:

# cd /rhel/AppStream
# createrepo  -g repodata/*comps*.xml . --update
Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete

At this point we can go ahead and create a new image using the following command inside /rhel:

# mkisofs -o /tmp/rhel8-slim.iso -b isolinux/isolinux.bin -c isolinux/boot.cat --no-emul-boot --boot-load-size 4 --boot-info-table -J -R -V RHEL-8-0-0-BaseOS-x86_64 .

Once the command runs the new image will be written out to /tmp/rhel8-slim.iso and if we are lucky the size is now greatly diminished:

# ls -lh /tmp/rhel8-slim.iso
-rw-r--r--. 1 root root 2.0G Jul  1 15:17 /tmp/rhel8-slim.iso

And there it is a slimmer 2gb RHEL 8 image that contains only the packages that are needed for this specific project.   Be aware this method could also be used to add custom packages to RHEL 8 as well or even script customization and/or configurations.  The flexibility is limited only to ones imagination.