If you’re a NetEye regular, you may have downloaded the NetEye ISO at least once in your life.
And if you did, you probably discovered that you had a bit of free time before the download was completed and the ISO was ready to be used. Why’s that? Because until a couple of weeks ago, the NetEye ISO was running about 15 GB – not the lightest ever!
Okay, to understand how we managed to improve this aspect and reduce the size of the ISO by just a bit, we first need to take a look at how the NetEye ISO is built.
To build a NetEye ISO we need two ingredients: a Red Hat Enterprise Linux 8 official ISO and… a NetEye container!
That’s because our pipelines have always built the NetEye ISO starting from a NetEye container, which is based on a UBI 8 container, on top of which the NetEye packages are installed from our repos, using the associated DNF groups.
We use containers internally to perform most of our development work, and the NetEye ISO is no exception. In particular, the ISO project would create the NetEye ISO as follows:
So, where does that 15 GB come from?
Well, making a summary of what the NetEye ISO contains, we can see the content divided among the following three repos:
Now, the Base OS is clearly something that’s needed, at least if we would like to have a NetEye that works 😅
The same holds for the NetEye one, since otherwise our packages will be missing… so guess which repo is the one holding unnecessary packages?
You’re right! App Stream!
Why is that? Because the App Stream repo contains all possible Application Streams that can be installed on a RHEL 8 system, together with their dependencies.
And, as you can imagine, not all those streams are needed when NetEye is first installed from the ISO, since we require just some specific streams and versions.
Great, so we managed to identify the repo that’s holding some extra packages that we don’t need during the first installation. But how can we identify, in an automatic way, the specific packages that we can remove?
Well, we need to remember that we are starting from a container, which already contains (it is a container, right? 🤣) the packages that we really need. So, once more, we can use it as a basis for our ISO!
Of course, there’s a little exception: there are some packages that are not in the container (and that we cannot really install there, to avoid some nasty conflicts) but that we would like to preserve in the ISO, together with their dependencies.
In that case, what we can do is to simulate the installation of those packages in the container and get the installed packages as a list of packages to preserve from the App Stream repo, to ensure we do not delete them by mistake.
The procedure to extract the list of packages that we want to preserve from the App Stream repo was performed like this, using Ansible:
- name: Prepare Environment | gather the packages list
ansible.builtin.package_facts:
# We start by creating the list of packages
# that are installed in the container
- name: Create list of packages installed in the container
ansible.builtin.set_fact:
packages_array: "{{ ansible_facts.packages | dict2items
| map(attribute='value') | list | flatten}}"
# We keep only the names and version,
# the other information are not required.
- name: Extract the packages names and versions
ansible.builtin.set_fact:
container_packages:"{{ packages_array | map(attribute='name')
| zip(packages_array | map(attribute='version'))
| map('join', '-') | zip(packages_array
| map(attribute='release'))
| map('join', '-') | list }}"
- name: Simulate package installation to catch missing packages
ansible.builtin.dnf:
name: "{{ extra_packages_needed_in_the_iso | join(',') }}"
state: latest
# Necessary since in the containers we may have some packages
# that conflicts with something we want to install through
# the ISO such as coreutils-single
allowerasing: true
# Hey, it is just a simulation!
check_mode: true
register: packages_with_dependencies
- name: Extract the packages names
ansible.builtin.set_fact:
extra_packages: "{{ packages_with_dependencies.results
| select('match','^Installed.*')
| map('regex_replace', '^Installed.*: ', '') | list }}"
when: packages_with_dependencies.changed
- name: Create list of packages to preserve in the AppStream Repo
ansible.builtin.set_fact:
packages_to_preserve: "{{ container_packages
+ (extra_packages | default([])) }}"
And with this we were able to remove all the packages present in the App Stream Repo that were not part of the packages_to_preserve list.
After that, to really make the ISO work, we need to update the metadata of the App Stream repo, as follows:
createrepo --update {{ rhel8_unpackaged_iso_path }}/AppStream
By applying the aforementioned procedure in our ISO building pipeline, we managed to reduce it from the initial 15 GB to just 5 GB!
This improvement allowed us to speed up some internal pipelines while also improving the installation process, providing a more compact and manageable ISO for NetEye 🚀
Did you find this article interesting? Does it match your skill set? Programming is at the heart of how we develop customized solutions. In fact, we’re currently hiring for roles just like this and others here at Würth Phoenix.