Linux mkinitrd 命令

注意:mkinitrd是创建初始RAM磁盘(initrd)映像的工具,主要用于早期的Linux发行版(如Red Hat 7/8、CentOS 3/4)。现代发行版多使用dracutmkinitcpio,但了解mkinitrd对于维护旧系统仍有价值。

命令简介

mkinitrd用于创建初始RAM磁盘(initrd)映像文件。initrd是一个临时的根文件系统,在Linux内核启动过程中被加载到内存中,用于加载必要的硬件驱动和模块,然后挂载真正的根文件系统。它是系统启动过程中的关键组件。

命令语法

mkinitrd [选项] 映像文件 内核版本

常用选项

选项 说明
-f 强制覆盖现有映像文件
--preload 模块 预加载指定的内核模块
--omit-scsi-modules 省略SCSI模块
--omit-raid-modules 省略RAID模块
--omit-lvm-modules 省略LVM模块
--with 模块 包含指定的附加模块
--nocompress 不压缩initrd映像
--builtin 模块 指定内置到内核中的模块
--fstab 文件 使用指定的fstab文件
--image-version 在映像中添加版本信息
--verbose 详细输出模式
-v 显示版本信息
-h 显示帮助信息

initrd的作用和工作流程

阶段 说明
1. BIOS/UEFI启动 系统固件加载引导加载程序(GRUB/LILO)
2. 引导加载程序 GRUB加载Linux内核和initrd映像到内存
3. 内核初始化 内核解压并挂载initrd作为临时根文件系统
4. initrd执行 运行initrd中的/linuxrc或/init脚本,加载必要驱动
5. 根文件系统切换 挂载真正的根文件系统,切换到真实根目录
6. 系统初始化 执行/sbin/init,启动系统服务

使用示例

1. 创建基本的initrd映像

# 创建当前内核的initrd映像
mkinitrd /boot/initrd-$(uname -r).img $(uname -r)

# 或明确指定内核版本
mkinitrd /boot/initrd-2.6.32-754.el6.x86_64.img 2.6.32-754.el6.x86_64

2. 强制覆盖现有映像

# 强制创建,覆盖已存在的映像文件
mkinitrd -f /boot/initrd-$(uname -r).img $(uname -r)

3. 预加载特定模块

# 预加载SCSI和RAID模块
mkinitrd --preload=sd_mod --preload=ahci /boot/initrd-$(uname -r).img $(uname -r)

# 预加载网络驱动模块
mkinitrd --preload=e1000 --preload=8139too /boot/initrd-$(uname -r).img $(uname -r)

4. 省略不需要的模块

# 省略SCSI和RAID模块(如果没有SCSI/RAID设备)
mkinitrd --omit-scsi-modules --omit-raid-modules /boot/initrd-$(uname -r).img $(uname -r)

# 省略LVM模块(如果不使用LVM)
mkinitrd --omit-lvm-modules /boot/initrd-$(uname -r).img $(uname -r)

5. 包含附加模块

# 包含NFS和CIFS模块
mkinitrd --with=nfs --with=cifs /boot/initrd-$(uname -r).img $(uname -r)

# 包含加密模块(dm-crypt, cryptsetup)
mkinitrd --with=dm-crypt --with=cryptsetup /boot/initrd-$(uname -r).img $(uname -r)

6. 不压缩的initrd映像

# 创建不压缩的initrd(用于调试)
mkinitrd --nocompress /boot/initrd-$(uname -r).img $(uname -r)

7. 详细模式创建

# 显示详细的创建过程
mkinitrd --verbose /boot/initrd-$(uname -r).img $(uname -r)

8. 完整initrd创建和更新脚本

#!/bin/bash
# initrd创建和更新脚本
KERNEL_VERSION=$(uname -r)
INITRD_FILE="/boot/initrd-$KERNEL_VERSION.img"
BACKUP_DIR="/boot/initrd_backup"
DATE=$(date +%Y%m%d_%H%M%S)

echo "当前内核版本: $KERNEL_VERSION"
echo "目标文件: $INITRD_FILE"

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份现有的initrd(如果存在)
if [ -f $INITRD_FILE ]; then
    BACKUP_FILE="$BACKUP_DIR/initrd-$KERNEL_VERSION-$DATE.img"
    cp $INITRD_FILE $BACKUP_FILE
    echo "已备份现有initrd到: $BACKUP_FILE"
fi

# 创建新的initrd
echo "正在创建新的initrd映像..."
mkinitrd --preload=ahci --preload=ext4 --with=usb-storage --verbose \
    $INITRD_FILE $KERNEL_VERSION

if [ $? -eq 0 ]; then
    echo "initrd创建成功!"
    echo "文件大小: $(du -h $INITRD_FILE | cut -f1)"

    # 更新GRUB配置(如果需要)
    if [ -f /sbin/grubby ]; then
        echo "更新GRUB配置..."
        grubby --update-kernel=/boot/vmlinuz-$KERNEL_VERSION \
               --initrd=$INITRD_FILE
    fi
else
    echo "initrd创建失败!"
    exit 1
fi

initrd文件结构

典型的initrd映像包含以下目录结构:

initrd.img (解压后)
├── bin/           # 基本命令(busybox)
├── dev/           # 设备文件
├── etc/           # 配置文件
├── lib/           # 库文件和内核模块
├── proc/          # proc文件系统
├── sys/           # sys文件系统
├── sbin/          # 系统命令
├── init           # 初始化脚本(或linuxrc)
└── modules/       # 内核模块

查看initrd内容:

# 创建临时目录
mkdir /tmp/initrd

# 解压initrd(如果是gzip压缩)
cd /tmp/initrd
gzip -dc /boot/initrd-$(uname -r).img | cpio -id

# 如果是xz压缩
xz -dc /boot/initrd-$(uname -r).img | cpio -id

# 查看内容
ls -la /tmp/initrd/

常见使用场景

1. 添加新的硬件驱动支持

# 安装新硬件驱动后,重新创建initrd
# 1. 安装驱动模块到/lib/modules/$(uname -r)/
# 2. 重新创建initrd包含新模块
mkinitrd --with=新驱动模块 /boot/initrd-$(uname -r).img $(uname -r)

2. 创建救援模式的initrd

# 创建包含更多工具和驱动的救援initrd
mkinitrd --preload=ahci --preload=sd_mod \
         --with=e1000 --with=8139too \
         --with=nfs --with=cifs \
         /boot/initrd-rescue.img $(uname -r)

3. 优化initrd大小

# 创建最小化的initrd(仅包含必要模块)
mkinitrd --omit-scsi-modules \
         --omit-raid-modules \
         --omit-lvm-modules \
         --preload=ext4 \
         /boot/initrd-minimal.img $(uname -r)

与现代工具对比

工具 首次出现 特点 主要发行版 现代替代
mkinitrd Red Hat 5/6 简单、传统 RHEL 5/6, CentOS 5/6 dracut
dracut Fedora 12+ 模块化、灵活 RHEL 7+, CentOS 7+, Fedora 当前标准
mkinitcpio Arch Linux 0.7 可定制、hook系统 Arch Linux, Manjaro Arch默认
update-initramfs Debian 4.0 自动化、集成 Debian, Ubuntu Debian默认

从mkinitrd迁移到dracut

如果系统使用mkinitrd但需要迁移到dracut:

# 1. 安装dracut
yum install dracut  # RHEL/CentOS
apt-get install dracut  # Debian/Ubuntu

# 2. 备份现有initrd
cp /boot/initrd-$(uname -r).img /boot/initrd-$(uname -r).img.backup

# 3. 使用dracut创建initrd
dracut /boot/initrd-$(uname -r).img $(uname -r)

# 4. 验证新initrd
ls -lh /boot/initrd*.img

# 5. 测试启动
# 重启系统并选择新内核

常见问题解决

1. "找不到内核模块"错误

# 错误:No module ahci found for kernel 2.6.32-754.el6.x86_64
# 解决方案:
# 检查模块是否安装
find /lib/modules/$(uname -r) -name "ahci.ko"

# 如果模块不存在,安装相应内核模块包
yum install kernel-modules-extra

# 或手动编译安装模块

2. initrd过大导致启动失败

# 检查initrd大小
ls -lh /boot/initrd-$(uname -r).img

# 如果过大,创建精简版
mkinitrd --omit-scsi-modules --omit-raid-modules \
         --omit-lvm-modules \
         /boot/initrd-$(uname -r).img $(uname -r)

# 或者清理旧的内核和initrd
package-cleanup --oldkernels --count=2

3. 启动时卡在"Loading initial ramdisk"

# 可能原因:initrd损坏或不兼容
# 解决方案:
# 1. 从救援模式或Live CD启动
# 2. 挂载原系统
mkdir /mnt/sysroot
mount /dev/sda1 /mnt/sysroot

# 3. 重新创建initrd
chroot /mnt/sysroot /bin/bash
mkinitrd /boot/initrd-$(uname -r).img $(uname -r)
exit
reboot

重要注意事项

  • 备份现有initrd:创建新initrd前务必备份现有文件
  • 内核版本匹配:确保initrd与内核版本匹配
  • 测试新initrd:创建后应在测试环境中验证启动
  • 模块依赖:确保所有必要的模块都包含在initrd中
  • 现代替代:考虑迁移到dracut等现代工具
  • 保留旧版本:保留至少一个可工作的旧版本initrd

安装mkinitrd

# mkinitrd通常随发行版提供
# RHEL/CentOS 5/6
# 通常已安装,如未安装:
yum install mkinitrd

# 对于更新的系统,可能需要安装传统工具
yum install mkinitrd-legacy

# 从源码编译(不推荐)
# mkinitrd是早期发行版的工具,现代系统建议使用dracut

相关命令

  • dracut - 现代initrd创建工具
  • mkinitcpio - Arch Linux的initrd创建工具
  • update-initramfs - Debian/Ubuntu的initrd管理工具
  • depmod - 生成内核模块依赖关系
  • lsinitrd - 查看initrd内容(dracut工具)
  • grubby - 更新GRUB配置
  • uname - 显示系统信息(内核版本)
  • modprobe - 加载内核模块
  • cpio - initrd打包/解包工具