Linux启动流程详解:CentOS 7 initramfs与systemd排障实践

发布时间:2026/10/11 9:37:17
Linux启动流程详解:CentOS 7 initramfs与systemd排障实践 简介这是一份讲解Linux系统启动流程的PPT课件适合Linux初学者、运维人员和系统管理员学习使用。课件从Linux内核与Linux系统的概念区别、常见发行版引入逐步展开PC架构主机从BIOS/UEFI固件到GRUB引导加载器再到内核加载initramfs临时文件系统、挂载真实根文件系统的全过程。内容还专门剖析了initramfs的产生原因、dracut脚本自动生成方式以及手动制作方法并对比传统SysV init与现代systemd的设计差异附带systemctl、journalctl、hostnamectl等命令的实际用法。资源为单个PPT文件整体大小约365KB结构紧凑、图文并茂适合课堂演示或自主复盘。已有283人学习。通过这套课件读者能形成完整的启动流程知识框架理解内核与根文件系统之间的依赖关系并掌握使用systemd高效管理服务的方法为后续系统调试和性能优化打下基础。1. 为什么说 Linux 启动流程的 PPT 课件值得用启动故障来检验《Linux系统启动流程PPT课件》这份资料最直接的价值在于它把 CentOS 7 从按下电源键到进入登录界面的整条链路拆成了三段BIOS/UEFI 到 GRUB、GRUB 到内核与 initramfs、initramfs 到 systemd。拿到一台启动异常的主机时很多人第一反应是“系统崩了”但实际上只要按这条链路逐层排查大多数问题都能定位到某个具体环节。这份课件适合刚接触 Linux 运维的开发者也适合做嵌入式网关、需要手工制造临时文件系统的工程师。它讲得不算深但结构非常适合作为一张排错地图你可以把每条知识点对应到实际命令在虚拟机上重新复现一遍。只要有一台 CentOS 7 环境就能跟着验证整个启动过程。2. CentOS7 启动流程从固件到 initramfs 的完整链路课件第一部分就是 CentOS 7 的 PC 架构主机启动流程。这部分内容如果只看概念会觉得简单但真实排障时固件、引导器、内核三个层次必须分开对待每一层都有完全不同的检查方式。2.1 BIOS 与 UEFI 的引导差异第一个程序是谁按下电源键后CPU 执行的第一段代码不是 Linux而是主板固件。老式 BIOS 负责自检并读取磁盘 MBRUEFI 则从 ESP 分区读取引导文件。两者不仅加载路径不同还直接影响 GRUB 配置文件的位置。CentOS 7 的 GRUB2 在 BIOS 模式下读取/boot/grub2/grub.cfg在 UEFI 模式下则读取/boot/efi/EFI/centos/grub.cfg。这个区别很关键否则你辛苦修改配置后重启依然走旧参数。对比项BIOS 引导UEFI 引导固件入口扫描磁盘 MBR从 ESP 分区读取 .efi 文件GRUB 安装位置MBR 或 /bootESP 分区配置文件路径/boot/grub2/grub.cfg/boot/efi/EFI/centos/grub.cfg多盘场景容易读错启动盘相对稳定但 ESP 损坏风险更高检查当前系统是哪种引导方式通常看/sys/firmware/efi目录是否存在。存在就是 UEFI不存在就是 BIOS。这个判断决定了后续所有修改操作的对象。我在拿到一台故障机器时第一件事就是执行这条命令因为后面是要改/boot/grub2/grub.cfg还是/boot/efi/EFI/centos/grub.cfg完全是两条路径。如果搞错grub2-mkconfig 生成了文件但启动固件根本不读那个位置等于白改。2.2 GRUB 加载内核与 initramfs先有鸡还是先有蛋GRUB2 本身不启动 Linux它只负责把两个关键文件载入内存以vmlinuz-*命名的内核镜像和以initramfs-*.img命名的临时根文件系统。为什么不能只加载内核因为内核为了控制体积只内置最核心的代码比如进程调度、内存管理、基础设备接口。磁盘控制驱动、文件系统驱动都以模块形式放在/lib/modules/里。但模块放在根文件系统中如果根文件系统所在磁盘的驱动不在内核里内核连根文件系统都读不到更别提加载模块了。initramfs 就是用来打破这个死循环的。GRUB 把 initramfs 载入内存后内核将其解压为一块临时 rootfs里面预置了启动阶段需要的驱动和工具。内核先运行 initramfs 中的/init由它加载驱动、识别根设备再挂载真实根文件系统。课件里那句“先有鸡还是先有蛋”说的就是这个场景模块在文件系统里文件系统又需要模块才能读取。实际操作中最常用的检查命令是# 查看内核启动参数确认 root 设备和 init 路径 cat /proc/cmdline # 查看当前 grub.cfg 中包含的内核菜单项 grep menuentry /boot/grub2/grub.cfg # 修改 /etc/default/grub 后需要重新生成 grub.cfg grub2-mkconfig -o /boot/grub2/grub.cfgcat /proc/cmdline的输出通常类似BOOT_IMAGE/vmlinuz-3.10.0-327.el7.x86_64 root/dev/mapper/centos-root。如果 root 后面是 LVM 逻辑卷路径说明 initramfs 阶段必须包含 LVM 相关模块如果是UUID...则根设备识别依赖 UUID 匹配。grub2-mkconfig的-o参数指定输出路径UEFI 机器上必须输出到 EFI 分区对应的 grub.cfg否则不生效。2.3 从 initramfs 切换到真实根switch_root 的隐藏步骤initramfs 中/init脚本的工作流程本质上就是把“临时根”让位给“真实根”。具体步骤包括挂载/proc、/sys、/dev创建设备节点识别根设备加载磁盘和文件系统驱动如果是 LVM 或加密卷还要激活卷组或解锁设备最后用switch_root切换根目录。任何一步失败都会出现类似Failed to mount /sysroot或者Cannot open root device的报错。排查这种报错我一般会在 GRUB 菜单按e编辑启动项在内核命令行末尾加rd.break让内核进入 initramfs 的调试 shell。在这个 shell 里可以手动执行# 查看内核是否识别了根磁盘 lsblk # 激活 LVM 卷组 lvm vgchange -ay # 手动挂载真实根验证文件系统是否完整 mount /dev/mapper/centos-root /sysrootrd.break是 dracut 提供的调试开关它会在 initramfs 完成驱动加载、准备切换到真实根之前停下来。这个状态下能直接看到磁盘设备、LVM 卷组和文件系统状态。如果lvm vgchange -ay成功说明卷本身没问题问题多半是 initramfs 没把 LVM 模块打进去如果 mount 失败那就要考虑根文件系统损坏或驱动不匹配。退出这个 shell 用exit继续启动流程改过配置之后我会再执行一次reboot验证效果。2.4 模块依赖一个容易被忽略的 initramfs 细节在课件对 initramfs 的介绍里最容易忽略的是“驱动模块”不是单个文件而是有依赖关系的。一个磁盘驱动可能需要先加载多个公共模块比如 SCSI 通用层、PCI 总线驱动。dracut 生成 initramfs 时会解析modprobe的依赖关系把整棵依赖树都打进去。但手动用 cpio 打包时如果只拷贝了某一个.ko文件启动时modprobe会报unknown symbol或module not found。查看模块依赖关系用# 查询某个内核模块的依赖 modprobe --show-depends ext4 # 查看 initramfs 里是否包含了该依赖 lsinitrd -m /boot/initramfs-$(uname -r).img | grep drivers/md/dm-mod这一节延伸出来的结论是除非你非常清楚目标硬件需要的完整驱动链否则生产环境尽量用 dracut而不是手工 cpio。课件里提到手动制作 initramfs 的例子更多是用于说明 initramfs 本质是什么而不是推荐你在服务器上手工造镜像。3. initramfs 制作dracut 自动生成与 cpio 手动打包课件里明确说initramfs 安装完系统后由 dracut 脚本自动生成也可以使用 cpio 命令手动制作。这一章讲清楚两种方式的适用场景和实践参数。3.1 dracut 的自动生成逻辑与常用参数CentOS 7 默认使用 dracut 生成 initramfs。它扫描当前内核目录/lib/modules/$(uname -r)结合机器实际硬件信息生成一份包含必要驱动和工具的最小镜像。默认文件位置是/boot/initramfs-内核版本.img。这份镜像和当前机器绑定换到另一台机器不一定能启动因为驱动集合完全不同。重建 initramfs 的标准命令# 用当前内核版本重新生成-f 覆盖已有文件 dracut -f /boot/initramfs-$(uname -r).img $(uname -r) # 指定内核版本生成适合为其他内核构建镜像 dracut --kver 3.10.0-1160.el7.x86_64 -f /boot/initramfs-3.10.0-1160.el7.x86_64.img第一个命令中$(uname -r)返回当前运行的内核版本例如3.10.0-327.el7.x86_64。第二个参数指定从哪个内核版本的模块目录生成。如果不指定dracut 默认用当前内核。--kver参数适用于你刚安装了新内核、但还没有重启进新内核的场景。此时uname -r还是旧版本必须手动指定新内核的版本号否则生成出来的镜像和实际启动的内核不匹配。如果要在 initramfs 中强制追加某些驱动用--add-driversdracut -f --add-drivers virtio_net /boot/initramfs-$(uname -r).img $(uname -r)这条命令适合虚拟化平台中网卡没有被自动识别的情况。注意--add-drivers只是在 initramfs 启动阶段预先加载驱动并不改变内核模块本身。如果你希望某些模块永远不被打进去可以用--omit-drivers排除。3.2 验证 initramfs 内容用 lsinitrd 而不是猜生成或重建之后不要急着重启。先用lsinitrd检查 initramfs 里到底有什么。这个命令会解压 initramfs 镜像并列出文件结构比直接解包到临时目录快得多。# 列出所有文件 lsinitrd /boot/initramfs-$(uname -r).img # 只看内核模块部分并过滤磁盘相关驱动 lsinitrd -m /boot/initramfs-$(uname -r).img | grep -E drivers/scsi|drivers/block|lvm-m只显示模块相关路径。我每次重建完都会执行最后一条确认根文件系统驱动在。比如 xfs 文件系统就要看有没有xfs.koLVM 根分区就要看有没有dm-mod.ko。宁可多花一分钟做验证也不要重启后才发现 initramfs 里缺了关键驱动。3.3 用 cpio 手动制作最小 initramfs课件里提到可以用 cpio 命令手动制作这个场景在嵌入式设备或者特殊网关项目里很常见。手动制作的核心有两点一是目录结构二是 init 脚本。内核解压 initramfs 后如果没有指定rdinit默认会查找根目录下的init作为第一个用户态程序。下面是一个最小示例用静态编译的 busybox 提供基础命令# 1. 准备目录结构 mkdir -p /tmp/myinitramfs/{bin,dev,proc,sys} # 2. 复制静态编译的 busybox cp /bin/busybox /tmp/myinitramfs/bin/ # 3. 创建 init 脚本 cat /tmp/myinitramfs/init EOF #!/bin/busybox sh mount -t proc proc /proc mount -t sysfs sys /sys echo initramfs is up exec /bin/busybox sh EOF chmod x /tmp/myinitramfs/init # 4. 打包成 cpio 并压缩 cd /tmp/myinitramfs find . -print0 | cpio --null -H newc -o --owner root:root 2/dev/null | gzip -9 /tmp/myinitramfs.img逻辑说明find . -print0将当前目录下所有文件以 null 分隔输出避免文件名包含空格时出错。cpio -H newc指定 newc 格式这是内核唯一能识别的传统 cpio 格式。--owner root:root将所有文件所有者设置为 root否则内核在加载时可能因权限问题拒绝执行 init。最后通过管道交给 gzip 压缩生成/tmp/myinitramfs.img。这个示例只能验证 initramfs 能启动到 shell不能真正挂载真实根文件系统因为它没有设备驱动、没有分区逻辑、也没有 switch_root。但作为理解 initramfs 原理的实验已经完全够用。如果你想在真实机器上测试可以在 GRUB 命令行中临时指定 initrd 文件并加上rdinit/init参数确认它能进到 init 脚本。3.4 手动制作与 dracut 的边界手动 cpio 的优势是可控缺点是模块依赖很难手工维护。一个驱动背后往往跟着一串依赖项手工拷贝非常容易漏。课件里的例子更适合教学用来解释 initramfs “本质上就是一块内存中的小型文件系统”。在生产环境特别是 RHEL/CentOS 系列永远优先用 dracut。如果确实需要定制也应该在 dracut 的配置目录下做增量修改而不是推翻重建。dracut 的配置目录在/etc/dracut.conf.d/可以写配置文件来增加默认参数比如cat /etc/dracut.conf.d/custom-drivers.conf EOF add_drivers nvme vmxnet3 omit_drivers floppy EOFadd_drivers和omit_drivers会作为默认参数合并到每次 dracut 执行中。这种方式比每次手工敲--add-drivers更可靠也方便团队多台机器保持一致。4. systemd 功能介绍从 SysV init 到并发启动课件最后一部分是 systemd。它拿 SysV init 做对比解释了为什么要用 systemd 替代传统 init。理解这段内容对排查启动后服务不起来的场景特别有用。4.1 SysV init 的串行启动瓶颈老版本 CentOS 的 PID 1 是init进程依赖/etc/inittab和/etc/init.d/下的大量 shell 脚本。启动服务用service network start或/etc/init.d/network start。这种方式看起来简单但命令本质是按脚本顺序一条条执行前一个服务没启动完后一个只能等待。课件直言它的缺点是“服务顺序启动过程较慢不能根据需要来启动服务”。更麻烦的是SysV init 的依赖关系靠脚本名的数字前缀控制比如S55sshd、S80postfix。一旦有人调整了编号依赖关系就乱了。只要有一个脚本阻塞后面全卡住。这种调度方式在物理机时代还能接受到了云主机和容器时代启动速度的劣势就非常明显。4.2 systemd 的并发启动与按需启动systemd 的守护目标是整个系统d代表 daemon。它把所有可管理对象抽象成 Unit包括 service、socket、target、device 等。Unit 文件通过After、Requires、Wants声明依赖systemd 先构建依赖图再把没有相互依赖的服务并行拉起。这就是并发启动提速的根本原因。按需启动是另一个关键能力。传统 init 会一次性把所有服务都启动systemd 则支持 socket 激活。比如一个服务平时不运行只有收到外部请求时才被拉起或者某个单元被另一个单元引用时才开始加载。这能减少系统空转的资源消耗。分析启动瓶颈可以用# 查看启动最慢的 10 个服务 systemd-analyze blame | head -10 # 查看某个服务的启动依赖链 systemd-analyze critical-chain sshd.servicecritical-chain会输出该服务启动前必须等待的单元列表这些等待项往往是启动耗时的来源。比如网络未就绪、磁盘挂载延迟、或者某个 socket 服务超时。4.3 用 systemctl 管理服务一个最小 Unit 示例课件给出了systemctl start apache.service与/etc/init.d/apache start的对照。这里用一个虚构的 demo 服务来说明 Unit 文件的写法。在/etc/systemd/system/demo.service写入cat /etc/systemd/system/demo.service EOF [Unit] DescriptionDemo background service Afternetwork.target [Service] Typesimple ExecStart/usr/local/bin/demo --foreground Restarton-failure RestartSec3 [Install] WantedBymulti-user.target EOF参数说明Typesimple表示 systemd 认为该进程启动后就进入运行状态进程本身必须在前台运行不能自己 fork 到后台。ExecStart必须写绝对路径和完整参数。Restarton-failure在进程异常退出时自动拉起RestartSec3是重启前的等待秒数。WantedBymulti-user.target表示在进入多用户模式时启用该服务。写完文件后执行systemctl daemon-reload systemctl enable demo.service systemctl start demo.service systemctl status demo.servicedaemon-reload是必须的。systemd 在启动时读取了旧的 Unit 配置不重载就不会感知新文件。enable只是在 target 下创建软链接不会立刻启动。start才真正拉起进程。这里最常见的翻车点是服务程序是 daemon 类型父进程启动后会 fork 子进程然后退出而Typesimple要求 ExecStart 进程一直活着结果 systemd 认为启动失败反复重启。4.4 journalctl 与 hostnamectl排错和系统信息查看systemd 把日志集中到了 journald查看日志不再需要去翻/var/log/messages。常用命令# 查看本次启动的所有日志 journalctl -b # 只看某个服务单元的日志并带时间戳 journalctl -b -u demo.service -o short-precise # 实时跟踪日志 journalctl -f-b表示本次启动-u过滤指定 Unit-o short-precise输出微秒级时间戳。服务启动失败时优先执行第二条命令看日志比盲猜原因高效得多。主机名管理也归 systemd 管# 查看当前主机名和系统信息 hostnamectl # 设置主机名 hostnamectl set-hostname node01设置后立即生效不需要重启。操作SysV initsystemd启动服务service httpd startsystemctl start httpd.service停止服务service httpd stopsystemctl stop httpd.service查看日志tail -f /var/log/messagesjournalctl -f开机自启chkconfig httpd onsystemctl enable httpd.service这张对照表是课件没有写但实际迁移时一定会用到的。CentOS 7 上很多老脚本还在用service它会被兼容层转发到 systemctl但依赖旧版/var/log/messages的日志排查方法已经过时了。5. 避坑启动流程调试中的五个常见问题与排查记录以下五条都是实际排查中踩过的坑按“现象 → 原因 → 解决”记录可以收藏备用。5.1 改了 /etc/default/grub 的启动参数重启后不生效现象在/etc/default/grub的GRUB_CMDLINE_LINUX里加了consolettyS0执行reboot后/proc/cmdline看不到这个参数。原因GRUB2 启动时读取的是/boot/grub2/grub.cfg/etc/default/grub只是配置模板。没有执行grub2-mkconfig改动的参数永远不会进入实际启动项。UEFI 模式下还可能因为输出路径写错生成的文件没有被固件读取。解决先确认引导模式再执行grub2-mkconfig -o /boot/grub2/grub.cfgUEFI 环境输出到/boot/efi/EFI/centos/grub.cfg。执行后立即用grep console /boot/grub2/grub.cfg验证参数确实写入不要相信reboot后才发现。5.2 dracut 重建 initramfs 后启动时仍报找不到根设备现象内核启动后卡在Failed to mount /sysroot但用系统安装光盘进入救援模式可以正常挂载根分区。原因initramfs 里缺少根文件系统驱动或 LVM 模块没有被打进去。常见诱因是根分区从/dev/sda1变成了/dev/nvme0n1p1设备名变化而 GRUB 命令行的 root 参数还写死了旧设备名也可能是 dracut 生成时使用了--omit-drivers排除了必需驱动。解决先用lsinitrd -m /boot/initramfs-$(uname -r).img | grep lvm检查 LVM 模块缺少就用dracut -f --add-drivers lvm2重新生成。同时把 GRUB 的 root 参数和/etc/fstab都改成 UUID 或/dev/mapper/xxx避免设备名漂移。5.3 手动制作的 initramfs 无法进入 init shell现象用 cpio 打包的 initramfs 启动后内核报Kernel panic - not syncing: Attempted to kill init!或者直接黑屏。原因init 脚本没有可执行权限或者脚本第一行解释器路径写错。另一个常见问题是 cpio 打包时文件所有者不是 root内核拒绝执行。如果二进制依赖动态库而动态库没有一起打包也会出现类似现象。解决检查ls -l /tmp/myinitramfs/init确认有x权限。脚本第一行必须指向真实的解释器比如#!/bin/busybox sh。拷贝的二进制尽量用静态编译版本或者把动态库一起放进对应目录。打包命令必须带--owner root:root并用-H newc指定格式。5.4 systemd 服务启动 90 秒超时现象systemctl start demo.service执行后长时间不返回最终报Start request repeated too quickly或 Timed out但查看进程时服务实际在运行。原因Unit 里的Type写错。服务是 daemon 型启动后父进程退出、子进程驻留却写了Typesimplesystemd 认为 ExecStart 进程退出就是服务结束于是反复拉起并等待超时。解决如果服务进程会 fork 到后台用Typeforking并配置PIDFile/run/xxx.pid指向子进程 PID如果保持前台运行用Typesimple。服务需要等网络就绪时加Afternetwork-online.target和Wantsnetwork-online.target不要只写Afternetwork.target。5.5 启动后直接进入 emergency mode现象开机字符界面显示Welcome to emergency mode!提示某个文件系统无法挂载输入 CtrlD 后能继续启动但每次重启都会出现。原因/etc/fstab中存在一个挂载项对应的设备在启动阶段找不到systemd 为保护系统进入应急模式。常见于挂载了临时数据盘或 U 盘后来设备拔掉了但 fstab 没有更新也有可能 UUID 写错。解决查看 emergency 提示中的设备或 UUID用blkid对比修正。如果确实是临时设备直接注释掉对应 fstab 行执行systemctl daemon-reload后重启。遇到这种情况不要急着重装系统先怀疑 fstab。6. 让启动流程课件变成排查手册内核升级后的 initramfs 重建与验证最后分享一个我每次都会执行的固定流程内核升级后重建并验证 initramfs。很多人升级完内核就重启翻车后才想起来/boot目录下没有对应版本的 initramfs。虽然内核 RPM 安装时通常会触发 dracut 自动生成但默认生成的镜像不一定适配你的存储环境尤其是使用 LVM、软件 RAID 或特殊网卡的机器。我的习惯是在重启之前走完下面四步# 1. 列出所有已安装内核确认要启动的新版本号 rpm -q kernel # 2. 为指定内核版本重建 initramfs注意不要用 uname -r dracut -f /boot/initramfs-3.10.0-1160.el7.x86_64.img 3.10.0-1160.el7.x86_64 # 3. 验证关键驱动是否在镜像内 lsinitrd -m /boot/initramfs-3.10.0-1160.el7.x86_64.img | grep -E xfs|lvm|nvme # 4. 检查 GRUB 默认启动项是否正确 grub2-editenv listrpm -q kernel的输出会包含所有已安装内核版本。如果你刚安装新内核但还没有重启uname -r返回的仍然是旧版本号这时候用uname -r去重建生成的就是旧内核的 initramfs新内核启动时自然找不到。我曾踩过一次这个坑当时在新机器上装完内核直接用uname -r生成 initramfs重启后卡在 grub 提示符下后来才明白第二个参数一定要显式指定新内核版本。grub2-editenv list可以查看当前 GRUB 默认启动项。如果新内核版本没有排在第一重启后还是会进旧内核。这步容易被忽略但它决定你到底能不能验证刚才生成的 initramfs。从那以后我每次升级内核都强制走一遍先rpm -q kernel确认版本再dracut -f重建然后用lsinitrd -m检查磁盘驱动最后看一眼grub2-editenv list确认默认启动项是新的内核。这套流程同样适用于把这份启动流程课件里的知识点落地的过程课件负责讲链路命令负责验证链路。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询