Removing Linux Kernels

Problem

I noticed that I could not connect to one of my virutal machines (VM). I have a script that checks to see if the machines were offline and if so it will start them. Thus I did some investigating. What I found was not what I was expecting.

The VM in question was in fact showing as running in the VirtualBox. What happened was that it had attempted to upgrade to the next version of the Linux kernel. Only problem was that it ran out of space when unpackaging the archive. Thus I had to remove the existing kernels on the disk before it would continue. Here's how I did it.

Find The Old Kernels

You need to find the existing kernels on the system. Since this was not my first time cleaning up the file system, I created a shell script that I can use that will display the kernels that are installed on the system.

The Script

#!/bin/bash

################################################################################
# author: Kenny Robinson, @almostengr
# Description: List the linux kernels that are installed on a system. Use in 
# conjunction with removing old and unused kernels. 
# https://thealmostengineer.com/technology/2021.05.10-removing-linux-kernels/
################################################################################

dpkg -l | tail -n +6 | grep -E 'linux-image-[0-9]+' | grep -Fv $(uname -r)

When you run the script, it will give you an output like the following:

iamadmin@thepost:~/ubuntu-automation/utils$ . list_linux_kernels.sh 
rc  linux-image-4.15.0-101-generic         4.15.0-101.102                                  amd64        Signed kernel image generic
rc  linux-image-4.15.0-106-generic         4.15.0-106.107                                  amd64        Signed kernel image generic
rc  linux-image-4.15.0-108-generic         4.15.0-108.109                                  amd64        Signed kernel image generic
ii  linux-image-4.15.0-111-generic         4.15.0-111.112                                  amd64        Signed kernel image generic
rc  linux-image-4.15.0-34-generic          4.15.0-34.37                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-38-generic          4.15.0-38.41                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-39-generic          4.15.0-39.42                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-42-generic          4.15.0-42.45                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-43-generic          4.15.0-43.46                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-46-generic          4.15.0-46.49                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-47-generic          4.15.0-47.50                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-50-generic          4.15.0-50.54                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-51-generic          4.15.0-51.55                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-54-generic          4.15.0-54.58                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-58-generic          4.15.0-58.64                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-88-generic          4.15.0-88.88                                    amd64        Signed kernel image generic
rc  linux-image-4.15.0-99-generic          4.15.0-99.100                                   amd64        Signed kernel image generic

The break down of the output is as follows.

  • Lines that begin with "rc" are the ones that can be removed without any problem.
  • Lines that begin with "ii" should not be removed as they are being used by the system.
  • The second column of the output, represents the name of the image. This is what you will use in the next section to remove the old kernels from the system.

Remove The Old Kernels

Automatically Remove Them

If you have enabled automatic updates to run on your Ubuntu system, then you can configure the old Linux images and headers to be removed.

On Ubuntu 20.04, this would mean enabling or adding the below text to the /etc/apt/apt.conf.d/50unattended-upgrades file.

NOTE: Before making updates to files in the /etc directory, I would recommend that you create a backup of the file or set up version control, like Etckeeper, for this directory.

// Remove unused automatically installed kernel-related packages
// (kernel images, kernel headers and kernel version locked tools).
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";

Manual Removal

Now that you have identified the kernels to be remove, then the next step is to remove them. You can use either apt or dpkg to remove them. My preference is to use apt. Thus the command below would look like the following:

iamadmin@thepost:~/ubuntu-automation/utils$ sudo apt-get autoremove --purge linux-image-4.15.0-34-generic \ 
linux-image-4.15.0-38-generic linux-image-4.15.0-39-generic linux-image-4.15.0-42-generic linux-image-4.15.0-43-generic \
linux-image-4.15.0-46-generic linux-image-4.15.0-47-generic linux-image-4.15.0-50-generic linux-image-4.15.0-51-generic \
linux-image-4.15.0-54-generic linux-image-4.15.0-58-generic linux-image-4.15.0-88-generic linux-image-4.15.0-99-generic

You will need to replace the names of each of the packages in provided in the previous section to be used in this section of the code.

After entering the command, you may receive a prompt similiar to the one below.

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages will be REMOVED:
  linux-headers-4.15.0-36* linux-headers-4.15.0-36-generic* linux-headers-4.15.0-44* linux-headers-4.15.0-44-generic* linux-headers-4.15.0-45*
  linux-headers-4.15.0-45-generic* linux-headers-4.15.0-52*
  linux-headers-4.15.0-52-generic* linux-headers-4.15.0-70* linux-headers-4.15.0-70-generic* linux-headers-4.15.0-72* linux-headers-4.15.0-72-generic*
  linux-headers-4.15.0-74* linux-headers-4.15.0-74-generic*
  linux-headers-4.15.0-76* linux-headers-4.15.0-76-generic* linux-headers-4.15.0-91* linux-headers-4.15.0-91-generic* linux-image-unsigned-4.15.0-70-generic*
0 upgraded, 0 newly installed, 19 to remove and 7 not upgraded.
After this operation, 814 MB disk space will be freed.
Do you want to continue? [Y/n] y

If you do receive such prompt, enter in "Y".

Additional Removal

I received a message that some directories were not able to be removed. The reason being is because they were not empty. Thus the package manager would not remove these.

rmdir: failed to remove '/lib/modules/4.15.0-70-generic': Directory not empty

It is safe to remove this and any other directories that are listed. To remove them, you will need to run the command:

sudo rm -r /lib/modules/4.15.0-70-generic

My experience has been that sometimes the old packages are not automatically removed when Unattended Upgrades runs. I have not quite figured out why this is the case.

Conclusion

Linux packages take up a lot of space on your system. By making sure you clean them off when they are no longer used, you can make sure that your system runs smoothly and does not become clogged with old junk.

Updated: 2023-01-17 | Posted: 2021-05-10
Author: Kenny Robinson