2 ways to update and rebuild initrd image in CentOS/RHEL 7 and 8


GRUB2, How To, Linux, Tips and Tricks

How do I unpack or uncompress, and then repack or re-compress, an initrd or initramfs boot image file? How do I modify the contents of an initrd or initramfs? How do I view an initrd or initramfs? How to customize initrd in RHEL Linux. How to rebuild initrd image in RHEL 8 Linux. How to update initrd in RHEL 7 Linux. How to update initrd with XV compressed data. How to rebuild initrd image with LZMA compressed data. How to rebuild the initial ramdisk image in Red Hat Enterprise Linux. How to rebuild initial ram disk image in Red Hat Enterprise Linux. How to remake or recreate the initrd or initramfs.

How to update and rebuild initrd image (initramfs) in CentOS/RHEL 7 and 8

 

What is initrd?

  • The initial RAM disk (initrd) is an initial root file system that is mounted prior to when the real root file system is available. The initrd is bound to the kernel and loaded as part of the kernel boot procedure. The kernel then mounts this initrd as part of the two-stage boot process to load the modules to make the real file systems available and get at the real root file system.
  • The initrd file contains a minimal set of directories and executables to achieve this, such as the insmod tool to install kernel modules into the kernel. In other words, it contains the necessary executables and system files to support the second-stage boot of a Linux system.
  • The initrd image is present under /boot directory and is owned by kernel package.
  • The version of the running kernel on the system will be used to identify the current initrd image used during booting process.

 

Why should I update initrd?

Initrd contains many drivers for third party vendors along with many modules and executables which help OS detect the underlying hardware. It is possible that on a new hardware the initrd fails to detect the underlying hardware part such as Network Card, Storage Adapter etc. In such situations we can modify the initrd image.

Although instead of adding driver modules from third party vendor into initrd, I would recommend creating a custom DUD (Driver Update Disk) as it also performs the same task and is a better alternative rather than updating and rebuilding initrd.

NOTE:
Modifying initrd in production environment is not recommended, if you have a valid subscription then you should get in touch with your support team to handle any issue which requires initrd modification.

Rather than modifying the initrd image, you can also opt to create an updates.img file which is called at a later stage of the BOOT UP. But if your problem is related to detection failure of underlying hardware then updates.img will not help.

 

Which one to choose initrd.img vs updates.img?

anaconda has the capability to incorporate updates at runtime to fix any bugs or issues with the installer. These updates are generally distributed as a disk image file (referred to as updates.img in this article).

So we have two options with us to alter the boot up process with our customized changes, one with initrd and the other with updates.img

The answer to this question depends on your requirement. updates.img is called at a later stage of the boot up procedure so if you wish to include important modules to detect hardware then you should update and rebuild initrd while if you need to add some bug fixes for the RHEL OS then you can go ahead with updates.img

 

Check initrd content

Before we update initrd, it is a good idea to verify the existing content of our initrd image. Here I am checking the content of initrd from the RHEL 8 ISO image.

[root@rhel-8 ~]# lsinitrd /mnt/images/pxeboot/initrd.img  | less
Image: /mnt/images/pxeboot/initrd.img: 58M
========================================================================
Version: dracut-049-10.git20190115.el8

Arguments: --nomdadmconf --nolvmconf --xz --install '/.buildstamp' --no-early-microcode --add 'fips' --add 'anaconda pollcdrom qemu qemu-net prefixdevname-tools' --force

dracut modules:
bash
systemd
fips
systemd-initrd
modsign
nss-softokn
i18n
convertfs
network-legacy
network
ifcfg
url-lib
drm
plymouth

<Output trimmed>

drwxr-xr-x   2 root     root            0 Jan 15  2019 var/lib/nfs/rpc_pipefs
drwxrwxr-x   3 root     root            0 Jan 15  2019 var/lib/nfs/statd
drwxr-xr-x   2 root     root            0 Jan 15  2019 var/lib/nfs/statd/sm
drwxrwx---   2 root     root            0 Jan 15  2019 var/lib/rpcbind
lrwxrwxrwx   1 root     root           11 Jan 15  2019 var/lock -> ../run/lock
lrwxrwxrwx   1 root     root            6 Jan 15  2019 var/run -> ../run
drwxr-xr-x   2 root     root            0 Jan 15  2019 var/tmp
========================================================================

Here in this list you can look for the content of initrd image file.

 

Method 1: Extract initrd image

Based on the initrd file compression type the command to extract and rebuild initrd will vary. For our case in both RHEL 7 and 8 we have XZ compressed data in initrd file as shown below:

[root@rhel-8 ~]# file /mnt/images/pxeboot/initrd.img
/mnt/images/pxeboot/initrd.img: XZ compressed data

[root@rhel-8 ~]# cat /etc/redhat-release
Red Hat Enterprise Linux release 8.0 (Ootpa)
[root@rhel-7 ~]# file /mnt/images/pxeboot/initrd.img
/mnt/images/pxeboot/initrd.img: XZ compressed data

[root@rhel-7 ~]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.6 (Maipo)

So we can use the same method to extract and rebuild initrd for both RHEL 7 and 8 Linux.

IMPORTANT NOTE:
Before you extract initrd make sure you take a backup of your initrd file or you can extract at a different location without touching the original file.

We will create a temporary directory where we will extract and update initrd

[root@rhel-8 custom_initrd]# mkdir /tmp/custom_initrd

To extract initrd use the below command:

[root@rhel-8 custom_initrd]# xz -dc < /mnt/images/pxeboot/initrd.img | cpio -idmv

This will extract all the content of initrd in the current directory

[root@rhel-8 custom_initrd]# ls -l
total 44
lrwxrwxrwx.  1 root root    7 Sep 13 19:44 bin -> usr/bin
drwxr-xr-x.  2 root root 4096 Sep 13 19:44 dev
drwxr-xr-x. 14 root root 4096 Sep 13 19:44 etc
lrwxrwxrwx.  1 root root   23 Sep 13 19:44 init -> usr/lib/systemd/systemd
lrwxrwxrwx.  1 root root    7 Sep 13 19:44 lib -> usr/lib
lrwxrwxrwx.  1 root root    9 Sep 13 19:44 lib64 -> usr/lib64
drwxr-xr-x.  2 root root 4096 Jan 15  2019 proc
drwxr-xr-x.  2 root root 4096 Jan 15  2019 root
drwxr-xr-x.  2 root root 4096 Jan 15  2019 run
lrwxrwxrwx.  1 root root    8 Sep 13 19:44 sbin -> usr/sbin
-rwxr-xr-x.  1 root root 3126 Oct  8  2018 shutdown
drwxr-xr-x.  2 root root 4096 Jan 15  2019 sys
drwxr-xr-x.  2 root root 4096 Jan 15  2019 sysroot
drwxrwxr-x.  2 root root 4096 Jan 15  2019 tmp
drwxrwxr-x.  9 root root 4096 Sep 13 19:44 usr
drwxr-xr-x.  4 root root 4096 Sep 13 19:44 var

 

Method 2: Extract initrd image

Alternatively you can also extract the initrd using the below list of steps. To start with copy the initrd file from the RHEL 7/8 ISO DVD to a temporary directory

[root@rhel-8 custom_initrd]# cp /mnt/isolinux/initrd.img /tmp/custom_initrd/

Verify the file

[root@rhel-8 custom_initrd]# ls -lh
total 58M
-r--r--r--. 1 root root 58M Sep 13 22:03 initrd.img

Now extract the file

[root@rhel-8 custom_initrd]# unxz -S .img initrd.img

With this the initrd.img will extract and create an initrd file

[root@rhel-8 custom_initrd]# ls -lh
total 171M
-r--r--r--. 1 root root 185M Sep 13 22:03 initrd

Extract the content of this initrd in the current directory

[root@rhel-8 custom_initrd]# cat initrd | cpio -idm
cpio: .buildstamp not created: newer or same age version exists
378442 blocks

Verify the content of the initrd

[root@rhel-8 custom_initrd]# ls -lh
total 171M
lrwxrwxrwx.  1 root root    7 Sep 13 22:07 bin -> usr/bin
drwxr-xr-x.  2 root root 4.0K Sep 13 22:07 dev
drwxr-xr-x. 14 root root 4.0K Sep 13 22:07 etc
lrwxrwxrwx.  1 root root   23 Sep 13 22:07 init -> usr/lib/systemd/systemd
-r--r--r--.  1 root root 185M Sep 13 22:03 initrd
lrwxrwxrwx.  1 root root    7 Sep 13 22:07 lib -> usr/lib
lrwxrwxrwx.  1 root root    9 Sep 13 22:07 lib64 -> usr/lib64
drwxr-xr-x.  2 root root 4.0K Jan 15  2019 proc
drwxr-xr-x.  2 root root 4.0K Jan 15  2019 root
drwxr-xr-x.  2 root root 4.0K Jan 15  2019 run
lrwxrwxrwx.  1 root root    8 Sep 13 22:07 sbin -> usr/sbin
-rwxr-xr-x.  1 root root 3.1K Oct  8  2018 shutdown
drwxr-xr-x.  2 root root 4.0K Jan 15  2019 sys
drwxr-xr-x.  2 root root 4.0K Jan 15  2019 sysroot
drwxrwxr-x.  2 root root 4.0K Jan 15  2019 tmp
drwxrwxr-x.  9 root root 4.0K Sep 13 22:07 usr
drwxr-xr-x.  4 root root 4.0K Sep 13 22:07 var

 

Update initrd image

Now since we have successfully extracted initrd, you can go ahead and do your modification. For example you can add new driver modules from the vendor to support some new hardware or any other custom change.

IMPORTANT NOTE:
Do not change the directory structure of the initrd image

For the sake of this article I wish to add a udev rule file to my initrd to detect and map the NIC cards with pre-defined PCI ID

# cat 20-persistent-net.rules
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", BUS=="pci", ID=="0000:01:00.0", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", BUS=="pci", ID=="0000:01:00.1", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", BUS=="pci", ID=="0000:03:00.0", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", BUS=="pci", ID=="0000:03:00.1", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth3"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", BUS=="pci", ID=="0000:04:00.0", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth4"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", BUS=="pci", ID=="0000:04:00.1", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth5"

We will add this in our initrd under /usr/lib/udev/rules.d

[root@rhel-8 rules.d]# ls -l
total 124
-r--r--r--. 1 root root 7266 Jan 15  2019 10-dm.rules
-r--r--r--. 1 root root 2454 Jan 15  2019 11-dm-lvm.rules
-rw-r--r--. 1 root root 4538 Jan 15  2019 11-dm-mpath.rules
-r--r--r--. 1 root root 1794 Jan 15  2019 13-dm-disk.rules
-rw-r--r--. 1 root root  876 Sep 13 20:13 20-persistent-net.rules
-rw-r--r--. 1 root root 1622 Jan 15  2019 40-redhat.rules
-rw-r--r--. 1 root root 3679 Jan 15  2019 50-udev-default.rules

 

Method 1: Rebuild initrd image

If you extract initrd using Method 1 then follow this procedure to rebuild initrd image, navigate to your temporary directory where you did extract initrd image.

[root@rhel-8 rules.d]# cd /tmp/custom_initrd/

[root@rhel-8 custom_initrd]#

Execute the below command to rebuild initrd image with xz as compression format

[root@rhel-8 custom_initrd]# find . 2>/dev/null | cpio -c -o | xz -9 --format=xz > /tmp/new.img
378439 blocks

Check the compression type of your new initrd file

[root@rhel-8 custom_initrd]# ls -l /tmp/new.img
-rw-r--r--. 1 root root 53615972 Sep 13 20:24 /tmp/new.img

[root@rhel-8 custom_initrd]# file /tmp/new.img
/tmp/new.img: XZ compressed data

 

Method 2: Rebuild initrd image

If you perform extract initrd using Method 2 then follow this procedure to rebuild initrd image, navigate to your temporary directory where you did extract initrd image.

Remove the initrd file which was already extracted is in the same directory.

[root@rhel-8 custom_initrd]# rm -f initrd

Next rebuild initrd image using the below command:

[root@rhel-8 custom_initrd]# find . | cpio -oc > ../initrd; cd ..; xz -S .img initrd
378442 blocks

Verify the new initrd image

[root@rhel-8 tmp]# ls -lh initrd.img
-rw-r--r--. 1 root root 53M Sep 13 22:15 initrd.img

 

Verify initrd image

Now since we successfully rebuild initrd image, let us verify the content of our new initrd and make sure our new rule file is present in this initrd image

[root@rhel-8 custom_initrd]# lsinitrd  /tmp/new.img | grep 20-persistent-net.rules
-rw-r--r--   1 root     root          876 Sep 13 20:13 usr/lib/udev/rules.d/20-persistent-net.rules

So as you see our file is now part of the initrd file. So now you can use this initrd file to boot up your system.

Similarly you can verify the content of initrd which you create using the Method 2.

 

Lastly I hope the steps from the article to update and rebuild initrd image in CentOS/RHEL 7 and 8 Linux was helpful. So, let me know your suggestions and feedback using the comment section.

 

References:
How to extract and repackage the anaconda installation initrd.img from Red Hat Enterprise Linux 7 DVD iso media?

 

Deepak Prasad

Deepak Prasad

Deepak Prasad is the founder of GoLinuxCloud, bringing over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, Networking, and Security. His extensive experience spans development, DevOps, networking, and security, ensuring robust and efficient solutions for diverse projects.

Certifications and Credentials:

  • Certified Kubernetes Application Developer (CKAD)
  • Go Developer Certification
  • Linux Foundation Certified System Administrator (LFCS)
  • Certified Ethical Hacker (CEH)
  • Python Institute PCAP (Certified Associate in Python Programming)
You can connect with him on his LinkedIn profile and join his Facebook and LinkedIn page.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

18 thoughts on “2 ways to update and rebuild initrd image in CentOS/RHEL 7 and 8”

  1. Hello.
    I am trying to add the samba-client component(cifs-utils) to pxe initrd.img Unpacking is successful. Need advice on how to add a samba-client(cifs-utils)

    Reply
  2. Just a quick note – tried on RHEL 8.6, there was a small difference. You have to use xz with --check=crc32 (xz -9 --format=xz --check=crc32) when re-creating initrd image, because embedded xz doesn’t handle new defaults (sha256/crc64).

    Reply
  3. i also met the kernel panic issue, may i know at the first begining, how you mount the original initrd to /mnt ? is there any requirement on the mnt steps , i mean need to create a block device ?

    Reply
    • /mnt just acts as a mount point so there is nothing wrong there. The kernel panic happens many times because of the files or content modified/added. Or the initrd was not properly archived based on their file type. You can also try to create an updates.img and place it in the GRUB file.

      initrd is the first module to get called used to identify your disk, network and other HW devices. So if you have a different requirement then better to go for updates.img as with that the chances of getting such error are less.

      Reply
  4. Hi, I had the same issue with the kernel panic trying to reload initrd.img with the e1000e intel ethernet driver. My situation is a bit different as I’m using cobbler to deploy different distros and profiles. Our grub.cfg is under /var/lib/tftpboot and contains 5 different profiles and their initrd.img is at /var/lib/tftpboot/images/centos78-x86_64/ (for example).

    submenu ‘Install Centos 7.8 Workstation’ {
    menuentry ‘Install Centos 7.8 Workstation’ {
    linuxefi images/centos78-x86_64/vmlinuz ksdevice=bootif lang= text kssendmac net.ifnames=0 ks=http://redactedip/cblr/svc/op/ks/profile/centos78-x86_64-prod-workstation
    initrdefi images/centos78-x86_64/initrd.img

    So I built a patch.img but the etc/modules-load.d doesn’t seem relevant. Nor does the append. I thought maybe inst.updates= inserted into the linuxefi might be the place to put it so I renamed patch.img to updates.img. I also tried to append it to the last line in the block for initrdefi where the initrd.img is specified. So far nothing is working. This is all new to me. I feel like I’m close to solving this problem, but don’t know how to instruct the tftpboot in cobbler to load the driver from that spare image.

    Any feedback would be appreciated. Honestly I would have thought there’d be something more straight forward on Cobbler’s front end to just inject the extra drivers. I used to manage an SCCM server and it was very easy to add extra drivers.

    Thank you.

    Reply
    • The updates.ing is called at a later stage of installation and based on what you have mentioned, it looks like the driver is required to be loaded at very initial stage if boot up.

      So in such case initrd.img must be modified rather than using inst.updates

      Reply
      • Thanks for your quick reply!

        I thought that might be the case.

        So in your earlier reply to another commenter you said that the kernel panic was caused by symbolic links introduced for lib -> usr/lib ?

        In the last year, have you become aware of a workaround for that problem?

        I tried both of your guides for extracting and repacking the image after dropping a e1000e.ko.xz file into place and both cause a kernel panic. Interestingly the first way resulted in my initrd.img becoming almost double in size and the 2nd method ended up being the same size, so I think I’ll stick to that method.

        This is the full path inside the initrd:

        usr/lib/modules/3.10.0-1127.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko.xz

        I overwrote the original e1000e.ko.xz with one I got from centos.pkgs.org which a vendor said they knew to work with the Dell Precision 3650 Tower’s NIC.

        Thanks for any help 🙂

        Reply
        • The patch.img steps in the comments are tested as even I had similar situation and it worked perfectly.
          The e1000e module path should be the one which you intend to add. I believe this driver/module is coming as part of some rpm which you wish to add inside initrd?
          So you can use rpm -ql , get the path and create the same directory structure inside /tmp/temp. What you have shared above is the driver path from initrd.
          Updating /etc/modules.d is important step, without that the driver will not be loaded.
          Overwriting may or may not work based on the path limitation which I highlighted in one of the comments but I would suggest to invest some time to debug patch.img issue.

          Reply
  5. I’m trying to add an updated driver to my initrd.img file. I’m able to add everything and rebuild the initrd.img file but when I try to boot I get a kernel panic message about the kernel not syncing and being offset. I’m guessing this is because the driver was added. Is there a way to fix this or another way to add an updated driver?

    Reply
    • Lately even I faced challenge while trying to add a driver into the initrd.img becaise the drivers are mostly located in /lib directory which is marked as symlink in initrd

      lrwxrwxrwx.  1 root root    7 Sep 13 19:44 lib -> usr/lib

      Hence when we add a driver, this path is overwritten causing kernel panic. This is one possible root cause.

      If you can share following details then may be I can help you
      1. What is the driver module name? is this part of some rpm?
      2. What is the absolute path of this driver
      3. Is this module already present in initrd.img and you want to overwrite the same?
      4. Assuming answer to question 3 is YES, what is the path of this module in initrd.img

      Reply
      • 1. The driver module is e1000e so it’s already there but only the updated version works with the nic I’m using. It can be installed normally from elrepo. It’s the kmod-e1000e rpm.
        2. When installed the path is /usr/lib/modules/3.10.0-1160.el7.x86_64/extra/e1000e but the old one is also here, /usr/lib/modules/3.10.0-1160.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000e.
        3. So it is already present but I haven’t tried overwriting it yet.
        4. It would be the 2nd path in question 2.

        When I initially tried it I created the extra directory and dropped the driver module in. This time I’ll just try overwriting.

        Reply
        • Thanks for the info. So you can create a patch.img, the steps to create this is same like updates.img.

          You can first create a temp folder to create the patch.img

          # mkdir /tmp/temp; cd /tmp/temp

          Next create the same directory structure as the initrd has for e1000e driver i.e.

          # mkdir -p usr/lib/modules/3.10.0-1160.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000e/

          I assume the driver will be in compressed format (.ko.xz) while the one from ELREPO would be in .ko format so you should compress the module into same .ko.xz format

          # xz e1000e.ko

          Next place the e1000e.ko.xz module file from kmod-e1000e to this location. You may also need to manually probe the module so create this file with the module name

          # cat << EOF >./etc/modules-load.d/e1000e.conf
          e1000e
          EOF

          Make sure these files are world readable. Lastly create patch.img

          # find . | cpio -c -o | gzip -9cv > ../patch.img

          Now you must keep this patch.img along with your initrd.img so both are called together in which case the content from patch.img will overwrite the content from initrd.img and would be given preference, something like this:

          append initrd=rhel8/initrd.img,rhel8/patch.img

          here I have placed my PXE boot files under rhel8 directory

          Reply
        • sir I’m also facing same problem initially RHEL 6.6 not having the i219 Driver,That’s why PXE Boot doesn’t get support from i219 ethernet,But we need get full installation from i219 ethernet..
          Please kindly do help for above issue sir

          Reply
    • What do you mean by corrupted? If your initramfs was corrupted, your system most likely wouldn’t boot.
      But it it recommended you take a backup anyhow.

      Reply
  6. This was super useful, thanks! One question though – I add a module and it shows up during the boot process, meaning that the initrd was modified.

    However, after reboot, none of the initrd changes are in initramfs. This is with RHEL 7.6. Any ideas?

    Reply
    • Hi Swami, Thanks for your feedback
      Do you mean after reboot you extracted the initrd and verified if the changes are missing?
      Are you adding a module or a file? Can you please share some more details of what you are trying to do?

      Reply

Leave a Comment