深入理解 Linux 系统启动原理

从按下电源键到出现登录提示符,Linux 系统究竟经历了什么?本文以 CentOS 7 为样本,逐层拆解「POST 自检 → MBR 引导 → GRUB2 菜单 → 内核加载 → systemd 初始化」的完整启动链路,并系统梳理 target 依赖体系、运行级别演进、root 密码重置、/etc/fstab 故障排查与 GRUB2 配置等高频实战场景,助你真正读懂 Linux 的"开机哲学"。

文章目录

一、 启动链路总览

现代计算机系统是硬件与软件的复杂组合。从断电状态到拥有登录提示符的运行中系统,需要大量硬件与软件协同工作。以物理 X86_64 平台启动 CentOS 7 为例,较高层面的任务链路如下:

  1. 开机自检(POST)
  2. MBR 引导
  3. GRUB 菜单
  4. 加载内核
  5. 运行 systemd 进程(PID 1)

阶段一:开机自检

计算机接通电源后,系统固件(现代 UEFI 或更旧的 BIOS)运行开机自检(POST),并开始初始化硬件。

配置入口:在系统启动早期,通过按特定组合键(如 F2)进入并配置系统固件。

阶段二:MBR 引导

系统固件按配置顺序搜索启动磁盘上的主启动记录(MBR),从中读取 boot loader,并将系统控制权移交给它------在 CentOS 7 中,这个 boot loader 就是 GRand Unified Bootloader version 2(GRUB2)

配置入口 :使用 grub2-install 命令将 GRUB2 安装为磁盘上的启动加载器。

阶段三:GRUB2 菜单

GRUB2 从 /boot/grub2/grub.cfg 加载配置并显示操作系统菜单,供用户选择要启动的系统条目。

配置入口 :通过 /etc/grub.d/ 目录、/etc/default/grub 文件与 grub2-mkconfig 命令生成 /boot/grub2/grub.cfg

阶段四:加载内核与 initramfs

boot loader 根据选定条目的配置,从磁盘加载 kernel 与 initramfs 并放入内存。initramfs 是一个存档,包含启动所需硬件的内核模块、初始化脚本等。随后 boot loader 将控制权交给 kernel,同时传递内核参数与 initramfs 在内存中的位置;内核在 initramfs 中找到所有硬件驱动程序并完成硬件初始化。

配置入口 :使用 /etc/dracut.conf.d/ 目录、dracut 命令与 lsinitrd 命令检查和维护 initramfs 文件。

阶段五:systemd 接管(PID 1)

initramfs 执行 /sbin/init 作为 PID 1------在 CentOS 7 中,/sbin/init 是指向 systemd 的链接。此后 systemd 全面接管系统初始化:

  1. systemd 加载内核命令行传递的 target,或加载系统配置的 default.target,该目标通常启动文本登录或图形登录界面。

    配置入口 :使用 systemctl 设置默认 target。

  2. default.target 依赖 sysinit.target,后者负责初始化系统,例如读取 /etc/fstab 挂载文件系统、激活 systemd-journald 等。

    配置入口 :使用 /etc/fstab 配置文件系统开机自动挂载。

  3. default.target 激活所有开机自启单元。

    配置入口 :使用 systemctl enable 设置服务开机启用。

  4. default.target 激活 getty.target,打开 tty1 终端供用户登录。

二、 系统 target 依赖体系

systemd 使用类型为 target 的单元对其他单元进行分组。例如 multi-user.target 包含 chronyd.service、crond.service、firewalld.service 等服务;target 之间还可以层层嵌套------graphical.target 包含 multi-user.target,后者包含 basic.target,再往下包含 sysinit.target

使用以下命令查看 target 之间的依赖关系:

bash 复制代码
systemctl list-dependencies graphical.target

其输出呈现为一棵清晰的依赖树(节选结构如下):

bash 复制代码
graphical.target
├─display-manager.service
├─systemd-update-utmp-runlevel.service
├─udisks2.service
└─multi-user.target
  ├─auditd.service
  ├─crond.service
  ├─dbus.service
  ├─irqbalance.service
  ├─kdump.service
  ├─mdmonitor.service
  ├─NetworkManager.service
  ├─restorecond.service
  ├─rngd.service
  ├─rsyslog.service
  ├─sshd.service
  ├─systemd-ask-password-wall.path
  ├─systemd-logind.service
  ├─systemd-update-utmp-runlevel.service
  ├─systemd-user-sessions.service
  ├─systemtap.service
  ├─tuned.service
  ├─basic.target
  │ ├─-.mount
  │ ├─tmp.mount
  │ ├─paths.target
  │ ├─slices.target
  │ │ ├─-.slice
  │ │ └─system.slice
  │ ├─sockets.target
  │ │ ├─dbus.socket
  │ │ ├─dm-event.socket
  │ │ ├─pcscd.socket
  │ │ ├─systemd-coredump.socket
  │ │ ├─systemd-initctl.socket
  │ │ ├─systemd-journald-dev-log.socket
  │ │ ├─systemd-journald.socket
  │ │ ├─systemd-udevd-control.socket
  │ │ └─systemd-udevd-kernel.socket
  │ ├─sysinit.target
  │ │ ├─dev-hugepages.mount
  │ │ ├─dev-mqueue.mount
  │ │ ├─dracut-shutdown.service
  │ │ ├─hwclock-save.service
  │ │ ├─kmod-static-nodes.service
  │ │ ├─ldconfig.service
  │ │ ├─lvm2-lvmpolld.socket
  │ │ ├─lvm2-monitor.service
  │ │ ├─proc-sys-fs-binfmt_misc.automount
  │ │ ├─sys-fs-fuse-connections.mount
  │ │ ├─sys-kernel-config.mount
  │ │ ├─sys-kernel-debug.mount
  │ │ ├─sys-kernel-tracing.mount
  │ │ ├─systemd-ask-password-console.path
  │ │ ├─systemd-binfmt.service
  │ │ ├─systemd-hwdb-update.service
  │ │ ├─systemd-journal-catalog-update.service
  │ │ ├─systemd-journal-flush.service
  │ │ ├─systemd-journald.service
  │ │ ├─systemd-machine-id-commit.service
  │ │ ├─systemd-modules-load.service
  │ │ ├─systemd-network-generator.service
  │ │ ├─systemd-random-seed.service
  │ │ ├─systemd-sysctl.service
  │ │ ├─systemd-sysusers.service
  │ │ ├─systemd-tmpfiles-setup-dev-early.service
  │ │ ├─systemd-tmpfiles-setup-dev.service
  │ │ ├─systemd-tmpfiles-setup.service
  │ │ ├─systemd-udev-trigger.service
  │ │ ├─systemd-udevd.service
  │ │ ├─systemd-update-done.service
  │ │ ├─systemd-update-utmp.service
  │ │ ├─cryptsetup.target
  │ │ ├─integritysetup.target
  │ │ ├─local-fs.target
  │ │ │ ├─-.mount
  │ │ │ ├─boot-efi.mount
  │ │ │ ├─boot.mount
  │ │ │ ├─systemd-fsck-root.service
  │ │ │ ├─systemd-remount-fs.service
  │ │ │ └─tmp.mount
  │ │ ├─swap.target
  │ │ │ └─dev-mapper-openeuler\x2dswap.swap
  │ │ └─veritysetup.target
  │ └─timers.target
  │   ├─dnf-makecache.timer
  │   └─systemd-tmpfiles-clean.timer
  ├─getty.target
  │ └─getty@tty1.service
  └─remote-fs.target

反过来,也可以查看某个单元被哪些 target 依赖(反向依赖):

bash 复制代码
# 查看反向依赖
systemctl list-dependencies sshd.service --reverse
bash 复制代码
sshd.service
● └─multi-user.target
○   └─graphical.target

三、 系统启动级别:从 runlevel 到 target

CentOS 6 及之前使用**启动级别(runlevel)**控制系统开机激活哪些服务;CentOS 7 之后改用 target 承担同一职责。二者对应关系如下:

runlevel target 作用
0 poweroff.target 关机。init 0poweroffsystemctl poweroff
1 emergency.target / rescue.target 单用户模式、救援模式和紧急模式,用于修复系统
2 --- 多用户文本界面,不具备 NFS 功能
3 multi-user.target 多用户文本界面
4 --- 未使用
5 graphical.target 多用户图形界面
6 reboot.target 重启。init 6rebootsystemctl reboot

历史回顾:/etc/inittab

/etc/inittab 是 RHEL 6 之前版本初始化系统使用的配置文件,部分内容如下:

bash 复制代码
# Default runlevel. The runlevels used by RHS are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
# 设置运行级别为 5,也就是图形化方式启动
id:5:initdefault:

设置系统当前运行 target

bash 复制代码
# 设置系统当前运行 target 为 multi-user.target
systemctl isolate multi-user.target

# 设置系统当前运行 target 为 graphical.target
systemctl isolate graphical.target

设置系统开机默认运行 target

bash 复制代码
# 查看系统开机默认运行 target
systemctl get-default
# 输出示例:multi-user.target

# 设置系统开机默认运行 target
systemctl set-default multi-user.target

# 重启验证
reboot

在系统启动时临时选择其它目标

要在启动时选择其他目标,将 systemd.unit=target.target 参数附加到内核命令行。该配置临时生效,常用于系统启动过程中的故障排除。操作步骤:

  1. 启动或重新启动系统;
  2. 按任意键(Enter 除外,它用于执行正常启动)中断启动加载器菜单倒计时;
  3. 将光标移至要启动的内核条目;
  4. e 编辑当前条目;
  5. 将光标移至以 linux 开头的行------此即内核命令行;
  6. 附加 systemd.unit=target.target,例如 systemd.unit=emergency.target
  7. Ctrl+x 使用这些更改进行启动。

四、 实战:重置 root 密码

如果管理员仍处于登录状态(无论是拥有完全 sudo 权限的非特权用户,还是 root 用户),直接执行 passwd 即可。但若管理员未登录,任务就复杂了:CentOS 6 及更早版本可将系统启动到 runlevel 1 获取 root 提示符,而 CentOS 7 之后与 runlevel 1 最接近的紧急目标与救援目标都需要 root 密码才能登录

常见的绕过思路有两种:其一,使用 Live CD 启动系统、挂载根文件系统后编辑 /etc/shadow(删除 root 密码字段,或替换为已知密码字段);其二,让 initramfs 在特定断点暂停,提供 root 身份的 shell 来重置密码。后者又分为两个经典方法。

方法一:rd.break(官方推荐,优先使用)

中断点 :initramfs 阶段,尚未切换真实根,提示符为 switch_root:/#

  1. 重新启动系统;
  2. 按任意键(Enter 除外)中断启动加载器倒计时;
  3. 将光标移至要启动的内核条目,按 e 编辑;
  4. 将光标移到内核命令行(以 linux 开头的行),附加 rd.break。利用该选项,系统在从 initramfs 向实际系统移交控制权前中断。kernel 行可能有多个 console 参数,以最后一个为准,有时需要设置 console=tty0
  5. Ctrl+x 使用更改启动;
  6. 此时系统显示 root shell,磁盘上的实际根文件系统以只读 方式挂载在 /sysroot。依次执行:
bash 复制代码
# 以读/写形式重新挂载 /sysroot
switch_root:/# mount -o remount,rw /sysroot

# 切换 root 位置,把 /sysroot 作为文件系统树的根
switch_root:/# chroot /sysroot

# 设置新 root 密码
sh-4.2# passwd root

# 若系统开启 SELinux,确保未标记文件(含 /etc/shadow)在启动过程中重新获得标记
sh-4.2# touch /.autorelabel
  1. 键入 exit 两次:第一次退出 chroot 环境,第二次退出 initramfs 调试 shell。系统将继续启动、执行完整的 SELinux 重新标记,然后再次重启;
  2. 登录验证。

方法二:init=/bin/bash

作用 :内核启动完成后不启动 systemd(PID 1),而是直接把 /bin/bash 作为 PID 1,直接拿到系统 shell。此时根文件系统默认只读挂载。

  1. 重新启动系统;
  2. 按任意键(Enter 除外)中断启动加载器倒计时;
  3. 将光标移至要启动的内核条目,按 e 编辑;
  4. 将光标移到内核命令行,附加 init=/bin/bash,请开启一个 root shell。kernel 行可能有多个 console 参数,以最后一个为准,有时需要设置 console=tty0
  5. Ctrl+x 使用更改启动;
  6. 此时系统显示 root shell,磁盘上的实际根文件系统以只读方式挂载在 /。依次执行:
bash 复制代码
# 以读/写形式重新挂载根文件系统
bash-4.2# mount -o remount,rw /

# 设置新 root 密码
sh-4.2# passwd

# 若系统开启 SELinux,确保未标记文件(含 /etc/shadow)在启动过程中重新获得标记
sh-4.2# touch /.autorelabel

# 拉起 systemd,正常走完启动流程(切勿直接断电/重启)
sh-4.2# exec /sbin/init
  1. 登录验证。

两种方法对比

对比项 rd.break init=/bin/bash
中断阶段 initramfs,切换真实根之前 已切换到真实根,替代 systemd(PID 1)
根文件系统位置 真实根在 /sysroot,需要 chroot 直接就是真实系统 /
SELinux 依然生效,必须写 /.autorelabel 依然生效,也要 /.autorelabel
磁盘支持 LVM、RAID、iSCSI 都正常识别,initramfs 驱动完整 同样加载 initramfs,磁盘驱动正常
退出方式 两次 exit 正常继续启动 不能直接断电/重启,必须执行 exec /sbin/init
风险点 几乎无风险,官方标准方式 忘记 exec /sbin/init 直接重启,极易损坏文件系统
官方态度 RHEL/CentOS 官方文档标准方案 兼容旧方式,不推荐生产使用

五、 实战:/etc/fstab 引起的启动故障

环境准备

bash 复制代码
# 设置磁盘分区管理方案
parted /dev/sdb mklabel msdos

# 创建分区
parted /dev/sdb unit MiB mkpart primary 1 10241

# 格式化为 xfs 文件系统
mkfs.xfs /dev/sdb1

# 创建挂载点
mkdir /data01

# 设置持久化挂载
echo '/dev/sdb1 /data01 xfs defaults 0 0' >> /etc/fstab

# 挂载并验证
mount -a
df -h /data01
bash 复制代码
文件系统       容量  已用  可用 已用% 挂载点
/dev/sdb1       10G   33M   10G    1% /data01

故障一:挂载点不存在

bash 复制代码
umount /data01
rmdir /data01

重启系统验证:系统可以正常进入 ,挂载点会被自动创建,df -h /data01 输出与之前一致。这说明挂载点缺失并非致命错误,systemd 会自动补建目录。

故障二:设备名称写错或找不到设备

bash 复制代码
vim /etc/fstab
# 将原先的 sdb1 修改为 sdb2
# /dev/sdb2 /data01 xfs defaults 0 0

重启系统验证:

  1. 启动过程中找不到该设备;
  2. 等待 1 分 30 秒超时后,系统进入 emergency 模式 ,输入 root 密码进行修复;
  3. 修改为正确的值或注释该条目,确保系统正常启动;
  4. 输入 reboot 重新启动系统;若系统没有继续启动,可强制关机重启。

故障三:破坏文件系统

bash 复制代码
dd if=/dev/zero of=/dev/sdb1 bs=1M count=1

重启系统验证:

  1. 系统启动过程中尝试修复文件系统,修复失败后提示进入 emergency 模式修复;
  2. 进入 emergency 模式后执行修复命令:
bash 复制代码
xfs_repair /dev/sdb1
  1. 修复完成后,输入 exit 继续启动,系统即可正常进入。

六、 GRUB2 配置详解

主要配置文件

  • /boot/grub2/:GRUB2 主要配置文件所在目录,例如 grub.cfggrubenvuser.cfg
  • /etc/grub2.cfg:指向 /boot/grub2/grub.cfg 的软连接。不要直接修改该文件 ------它由系统自动生成;如需自定义,应修改 /etc/grub.d/ 中的脚本与 /etc/default/grub,再通过 grub2-mkconfig 生成。使用 EFI 启动方式时,配置文件为 /etc/grub2-efi.cfg
  • /etc/grub.d/:存放多个数字开头的脚本,按从小到大的顺序执行。例如 00_header 会调用 /etc/default/grub 实现最基本的开机界面配置;
  • /etc/default/grub:定义 GRUB 启动部分变量信息,例如菜单超时时间、内核参数等;
  • /boot/grub2/grubenv:设定默认启动条目。

修改菜单超时时间

bash 复制代码
vim /etc/default/grub
# 修改 GRUB_TIMEOUT 为 10
GRUB_TIMEOUT=10

# 重新生成 grub2.cfg 配置文件使其生效
grub2-mkconfig -o /etc/grub2.cfg
bash 复制代码
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-1160.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-c6e36d35c9a846d7b64d9fdf929b09f6
Found initrd image: /boot/initramfs-0-rescue-c6e36d35c9a846d7b64d9fdf929b09f6.img
done
bash 复制代码
# 重启验证
reboot

重启后即可看到 GRUB2 菜单按新的超时时间展示启动条目,配置生效。

七、总结

本文以 CentOS 7 为样本,完整拆解了 Linux 启动的五段式链路:固件 POST 自检、MBR 移交 GRUB2、GRUB2 加载内核与 initramfs、systemd 以 PID 1 接管初始化、target 依赖树逐级激活服务直至打开登录终端。在此基础上,文章进一步梳理了 runlevel 与 target 的演进对应、临时与永久运行目标设置、rd.break 与 init=/bin/bash 两种 root 密码重置方案的差异与风险,以及 /etc/fstab 三类典型故障的现象与修复路径,并给出 GRUB2 配置的正确修改姿势。理解启动原理,是排查开机故障、加固系统安全、优化启动性能的基石,也是每一位 Linux 运维工程师从"会操作"走向"懂原理"的必经之路。

相关推荐
zbyyd2 小时前
Linux 基础与 Shell 命令
linux·运维·arm开发
起名真的太难了2 小时前
Linux系统运维与远程管理核心命令速查指南
linux·运维·服务器
tg_xianheyun2 小时前
阿里云国际账号注册代充值怎么选服务商?
服务器·阿里云·云计算·全球访问优化
xiaoye-duck2 小时前
《Linux网络编程》吃透 Linux 网络传输全流程:完整梳理局域网通信、封装解包与跨网络传输原理
linux·网络
深念Y2 小时前
订阅管理及节点过滤实践(技术笔记)
linux·网络·arm·优化·日志·工具·soc
IT小盘2 小时前
17-AI应用防止越权访问知识库
服务器·网络·windows
酷可达拉斯2 小时前
自动化运维-Ansible Role详解
linux·运维·服务器·自动化·ansible
为思念酝酿的痛2 小时前
Socket编程--TCP
服务器·网络·tcp/ip
智能运维指南2 小时前
智能体自治运维选型指南:2026年企业如何从“AI辅助”走向“AI自治”
大数据·运维·人工智能