searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

dracut简介

2025-09-11 06:46:03
3
0

概述

  • dracut是制作initramfs的工具。 initramfs(​Initial RAM File System,初始内存文件系统​​)是 Linux 内核启动过程中使用的一个​临时根文件系统​,它在内存中加载并提供必要的工具、驱动和脚本,用于在挂载真正的根文件系统之前完成关键初始化任务。使用initramfs是为了解决一个先有鸡还是先有蛋的问题:内核不包含所有外存储设备的驱动,这些驱动并没有全都编译到内核(可能编译到模块,也可能没有开启配置)。缺少对应的驱动,内核无法挂载外存储设备,也就无法启动外存储设备中的用户进程(例如systemd)。
  • dracut 的 initramfs 生成功能主要由一系列​​模块化生成器(generator modules)​​ 实现。这些模块由主 dracut 脚本调用,用于将特定功能注入 initramfs。它们位于 /usr/lib/dracut/modules.d 目录中,并利用 dracut-functions 提供的功能完成工作。
  • 制作initramfs:dracut --kver <内核版本> -f
    • 内核版本对应/lib/modules/目录下的文件夹名,-f表示覆盖原文件,也可直接指定文件名

安装dracut模块

  • /usr/lib/dracut/modules.d 中包含多个以 [优先级][模块名] 为命名格式的文件夹,模块安装由模块中的module-setup.sh脚本决定
  • 制作initramfs过程中,dracut会解析模块的module-setup.sh中的函数:
    • check()
      • 评估是否将某个 dracut 模块包含在 initramfs 中
      • 返回值:0包含、1不包含、255仅当其他模块需要该模块,或在配置文件或参数列表中明确指定时,才包含
    • depend()
      • 该函数应输出(echo)该模块依赖的所有其他 dracut 模块名称
    • cmdline()
      • 该函数应打印启动当前机器设置所需的内核命令行选项。应以空格开头且不应打印换行符
    • install()
      • 用来安装所有非内核相关的内容。要安装二进制文件、脚本和其他文件
      • 变量$moddir代表当前模块的目录
      • 不同的待安装文件可以用不同的预定义函数:
        • inst_multiple [-o] <文件> [<文件>...]
          安装多个二进制文件和普通文件。若可执行文件未指定路径,dracut将在PATH=/usr/sbin:/sbin:/usr/bin:/bin路径中搜索。若第一个参数为"-o"选项,则缺失文件不会报错。
        • inst <源文件> [<目标路径>]
          安装单个文件<源文件>到initramfs中相同位置或可选的<目标路径>。若inst接收超过两个参数,则按inst_multiple方式处理,所有参数均视为待安装文件而非安装目标。
        • inst_hook <钩子目录> <优先级> <源文件>
          在dracut的<钩子目录>中以<优先级>安装可执行文件/脚本<源文件>。优先级是数字,数值越小余额优先,钩子目录对应dracut启动过程的每个阶段,例如cmdline、pre-pivot
        • inst_rules <udev规则> [<udev规则>...]
          安装一个或多个udev规则。不存在的udev规则会被报告但不会导致dracut失败。
          udev规则位于/usr/lib/udev/rules.d
        • instmods <内核模块> [<内核模块>...]
          instmods应仅用于installkernel()函数。安装一个或多个内核模块到initramfs中。<内核模块>也可用"="前缀表示整个子系统,如"=drivers/net/team"。模块位于/usr/lib/modules/$(uname -r)/
    • installkernel()
      安装所有与内核相关的文件。同样可以使用上述函数
  • dracut模块的安装顺序由两方面决定:
    • 模块文件夹前面的优先级序号,越小越优先
    • 模块之间的依赖关系,依赖会优先安装。例如30module_a模块依赖40module_b,那么当安装modual_a时,会根据依赖关系先将module_b安装上

dracut启动流程

  • initramfs中,systemd启动过程,以及dracut钩子的执行顺序如下。钩子被标注为斜体。
    • cmdline​:此阶段用于解析内核命令行参数并准备后续操作,如设置udev规则和配置文件。该阶段会定义两个关键环境变量:
      • root:指定根文件系统设备
      • rootok:标识是否有模块能处理指定的root参数(如iscsi模块会处理root=iscsi:...参数并设置rootok)
    • pre-udev​:此时root和rootok已设置但udev尚未运行。模块可以在此阶段对最终确定的root设备进行操作。
  • 启动udev:初始化udev服务并设置日志记录
    • pre-trigger​:通过udevadm trigger触发所有设备和子系统的add事件
  • 主循环:dracut会循环执行直到udev事件处理完成并且initqueue/finished中所有脚本返回true。主循环中包含5个可插入脚本的钩子点,通过在启动阶段执行的脚本中调用/sbin/initqueue可执行文件来注册主循环中的钩子(例如/sbin/initqueue --settled --unique --onetime /sbin/insmodpost.sh):
    • initqueue​:每次通过/sbin/initqueue注册initqueue钩子时,都会立即执行该脚本,无论udev状态如何initqueue/settled:每次udev稳定时执行该钩子脚本,udev稳定是指所有的udev事件都处理完毕,udevadm settle指令便是静默等待所有udev事件处理完毕,执行echo "$?"回显为0,则说明udev settled(稳定)
    • initqueue/timeout​:当主循环计数器达到rd.retry一半值时执行该钩子脚本
    • initqueue/online​:当网络接口就绪(启动并完成配置)时执行
    • initqueue/finished​:在udev稳定后执行,若所有脚本返回0则结束主循环。模块可在此插入等待特定条件的脚本。
  • 主循环结束
    • pre-mount​:在挂载根设备前执行所有脚本
    • mount​:主要用于挂载真正的根设备
    • pre-pivot​:在清理阶段之前执行,适合放置非清理类但需要在切换根目录前完成的操作
    • cleanup​:最终阶段,在切换到真实根设备前执行最后的清理工作,终止不必要的进程
  • 清理并切换根目录
    • init(或systemd)会终止所有udev进程、清理运行环境、为真正的init进程配置参数,最终调用switch_root。switch_root会执行以下操作:
      • ​​彻底移除initramfs的整个文件系统层级​​(需要满足​​所有源自initramfs的进程都不应保留任何打开的文件描述符)
      • ​​通过chroot()切换到真实的根设备​​
      • ​​使用指定参数调用/sbin/init​​
  • dracut钩子脚本中可以使用在dracut-utils dracut-lib 中的函数,如用warn替代echo,用echo需要重定向到/dev/console才会在开机界面打印,重定向到/dev/kmsg才会出现在dmesg、journalctl中
  • 内核参数rd.break的作用便是使系统停止在​​initramfs中pre-pivot钩子函数执行之前。该参数还可以指定停止的阶段,例如rd.break=pre-mount,将会使系统停止在挂载根文件系统的前一刻,当系统无法启动,并且提示根文件系统损坏时,可添加此参数,在根文件系统挂载之前尝试手动对其进行修复。

示例:

[root@localhost 95my-dracut-module]# cat /usr/lib/dracut/modules.d/95my-dracut-module/exec\_echo.sh
#!/bin/bash
// do what you need to do
for ((row=1; row<=5; row++)); do
    for ((col=1; col<=5; col++)); do
        echo -n "."   
        sleep 0.01    
    done
    echo ""        
done
[root@localhost 95my-dracut-module]# cat /usr/lib/dracut/modules.d/95my-dracut-module/module-setup.sh 
#!/bin/bash
# called by dracut
check() {
    return 0
}

# called by dracut
depends() {
    return 0
}

# called by dracut
install() {
    inst\_hook pre-mount 90 "\$moddir/exec\_echo.sh"
}

附录:initramfs中使用systemd的执行流程

image.png
image.png
image.png

0条评论
0 / 1000
张****建
2文章数
0粉丝数
张****建
2 文章 | 0 粉丝
张****建
2文章数
0粉丝数
张****建
2 文章 | 0 粉丝
原创

dracut简介

2025-09-11 06:46:03
3
0

概述

  • dracut是制作initramfs的工具。 initramfs(​Initial RAM File System,初始内存文件系统​​)是 Linux 内核启动过程中使用的一个​临时根文件系统​,它在内存中加载并提供必要的工具、驱动和脚本,用于在挂载真正的根文件系统之前完成关键初始化任务。使用initramfs是为了解决一个先有鸡还是先有蛋的问题:内核不包含所有外存储设备的驱动,这些驱动并没有全都编译到内核(可能编译到模块,也可能没有开启配置)。缺少对应的驱动,内核无法挂载外存储设备,也就无法启动外存储设备中的用户进程(例如systemd)。
  • dracut 的 initramfs 生成功能主要由一系列​​模块化生成器(generator modules)​​ 实现。这些模块由主 dracut 脚本调用,用于将特定功能注入 initramfs。它们位于 /usr/lib/dracut/modules.d 目录中,并利用 dracut-functions 提供的功能完成工作。
  • 制作initramfs:dracut --kver <内核版本> -f
    • 内核版本对应/lib/modules/目录下的文件夹名,-f表示覆盖原文件,也可直接指定文件名

安装dracut模块

  • /usr/lib/dracut/modules.d 中包含多个以 [优先级][模块名] 为命名格式的文件夹,模块安装由模块中的module-setup.sh脚本决定
  • 制作initramfs过程中,dracut会解析模块的module-setup.sh中的函数:
    • check()
      • 评估是否将某个 dracut 模块包含在 initramfs 中
      • 返回值:0包含、1不包含、255仅当其他模块需要该模块,或在配置文件或参数列表中明确指定时,才包含
    • depend()
      • 该函数应输出(echo)该模块依赖的所有其他 dracut 模块名称
    • cmdline()
      • 该函数应打印启动当前机器设置所需的内核命令行选项。应以空格开头且不应打印换行符
    • install()
      • 用来安装所有非内核相关的内容。要安装二进制文件、脚本和其他文件
      • 变量$moddir代表当前模块的目录
      • 不同的待安装文件可以用不同的预定义函数:
        • inst_multiple [-o] <文件> [<文件>...]
          安装多个二进制文件和普通文件。若可执行文件未指定路径,dracut将在PATH=/usr/sbin:/sbin:/usr/bin:/bin路径中搜索。若第一个参数为"-o"选项,则缺失文件不会报错。
        • inst <源文件> [<目标路径>]
          安装单个文件<源文件>到initramfs中相同位置或可选的<目标路径>。若inst接收超过两个参数,则按inst_multiple方式处理,所有参数均视为待安装文件而非安装目标。
        • inst_hook <钩子目录> <优先级> <源文件>
          在dracut的<钩子目录>中以<优先级>安装可执行文件/脚本<源文件>。优先级是数字,数值越小余额优先,钩子目录对应dracut启动过程的每个阶段,例如cmdline、pre-pivot
        • inst_rules <udev规则> [<udev规则>...]
          安装一个或多个udev规则。不存在的udev规则会被报告但不会导致dracut失败。
          udev规则位于/usr/lib/udev/rules.d
        • instmods <内核模块> [<内核模块>...]
          instmods应仅用于installkernel()函数。安装一个或多个内核模块到initramfs中。<内核模块>也可用"="前缀表示整个子系统,如"=drivers/net/team"。模块位于/usr/lib/modules/$(uname -r)/
    • installkernel()
      安装所有与内核相关的文件。同样可以使用上述函数
  • dracut模块的安装顺序由两方面决定:
    • 模块文件夹前面的优先级序号,越小越优先
    • 模块之间的依赖关系,依赖会优先安装。例如30module_a模块依赖40module_b,那么当安装modual_a时,会根据依赖关系先将module_b安装上

dracut启动流程

  • initramfs中,systemd启动过程,以及dracut钩子的执行顺序如下。钩子被标注为斜体。
    • cmdline​:此阶段用于解析内核命令行参数并准备后续操作,如设置udev规则和配置文件。该阶段会定义两个关键环境变量:
      • root:指定根文件系统设备
      • rootok:标识是否有模块能处理指定的root参数(如iscsi模块会处理root=iscsi:...参数并设置rootok)
    • pre-udev​:此时root和rootok已设置但udev尚未运行。模块可以在此阶段对最终确定的root设备进行操作。
  • 启动udev:初始化udev服务并设置日志记录
    • pre-trigger​:通过udevadm trigger触发所有设备和子系统的add事件
  • 主循环:dracut会循环执行直到udev事件处理完成并且initqueue/finished中所有脚本返回true。主循环中包含5个可插入脚本的钩子点,通过在启动阶段执行的脚本中调用/sbin/initqueue可执行文件来注册主循环中的钩子(例如/sbin/initqueue --settled --unique --onetime /sbin/insmodpost.sh):
    • initqueue​:每次通过/sbin/initqueue注册initqueue钩子时,都会立即执行该脚本,无论udev状态如何initqueue/settled:每次udev稳定时执行该钩子脚本,udev稳定是指所有的udev事件都处理完毕,udevadm settle指令便是静默等待所有udev事件处理完毕,执行echo "$?"回显为0,则说明udev settled(稳定)
    • initqueue/timeout​:当主循环计数器达到rd.retry一半值时执行该钩子脚本
    • initqueue/online​:当网络接口就绪(启动并完成配置)时执行
    • initqueue/finished​:在udev稳定后执行,若所有脚本返回0则结束主循环。模块可在此插入等待特定条件的脚本。
  • 主循环结束
    • pre-mount​:在挂载根设备前执行所有脚本
    • mount​:主要用于挂载真正的根设备
    • pre-pivot​:在清理阶段之前执行,适合放置非清理类但需要在切换根目录前完成的操作
    • cleanup​:最终阶段,在切换到真实根设备前执行最后的清理工作,终止不必要的进程
  • 清理并切换根目录
    • init(或systemd)会终止所有udev进程、清理运行环境、为真正的init进程配置参数,最终调用switch_root。switch_root会执行以下操作:
      • ​​彻底移除initramfs的整个文件系统层级​​(需要满足​​所有源自initramfs的进程都不应保留任何打开的文件描述符)
      • ​​通过chroot()切换到真实的根设备​​
      • ​​使用指定参数调用/sbin/init​​
  • dracut钩子脚本中可以使用在dracut-utils dracut-lib 中的函数,如用warn替代echo,用echo需要重定向到/dev/console才会在开机界面打印,重定向到/dev/kmsg才会出现在dmesg、journalctl中
  • 内核参数rd.break的作用便是使系统停止在​​initramfs中pre-pivot钩子函数执行之前。该参数还可以指定停止的阶段,例如rd.break=pre-mount,将会使系统停止在挂载根文件系统的前一刻,当系统无法启动,并且提示根文件系统损坏时,可添加此参数,在根文件系统挂载之前尝试手动对其进行修复。

示例:

[root@localhost 95my-dracut-module]# cat /usr/lib/dracut/modules.d/95my-dracut-module/exec\_echo.sh
#!/bin/bash
// do what you need to do
for ((row=1; row<=5; row++)); do
    for ((col=1; col<=5; col++)); do
        echo -n "."   
        sleep 0.01    
    done
    echo ""        
done
[root@localhost 95my-dracut-module]# cat /usr/lib/dracut/modules.d/95my-dracut-module/module-setup.sh 
#!/bin/bash
# called by dracut
check() {
    return 0
}

# called by dracut
depends() {
    return 0
}

# called by dracut
install() {
    inst\_hook pre-mount 90 "\$moddir/exec\_echo.sh"
}

附录:initramfs中使用systemd的执行流程

image.png
image.png
image.png

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0