19.1 Linux 的开机流程分析

19.1.1 开机流程一览

从按下电源键到出现登录界面,整个开机流程:

BIOS/UEFI → MBR/GPT (grub2) → Kernel (vmlinuz) → initramfs → systemd → 各服务就绪

详细步骤

步骤动作说明
1BIOS / UEFI载入 BIOS、自我测试 (POST)、依设置取得第一个可开机设备
2Boot Loader读取并执行 MBR 内的 grub2
3Kernel 载入grub2 载入 kernel + initramfs,kernel 侦测硬件、载入驱动
4systemd 启动kernel 调用 systemd (PID=1),以 default.target 开始开机流程
4asysinit.target初始化系统(硬件侦测、核心模块)
4bbasic.target准备基础操作系统(音效、防火墙、SELinux)
4cmulti-user.target启动本机与网络服务
4drc-local.service执行 /etc/rc.d/rc.local(若可执行)
4egetty.target提供 tty 终端机登录服务
4fgraphical.target(若默认图形界面)启动 gdm 等图形登录服务

19.1.2 BIOS, boot loader 与 kernel 载入

BIOS 与 POST

BIOS (Basic Input Output System) 读取 CMOS 信息,获取硬件设置、开机设备顺序、系统时间等,然后进行 POST (Power-on Self Test),侦测硬件并初始化 PnP 设备。最后通过 INT 13 中断读取第一个开机设备 MBR 内的 boot loader。

不论传统 BIOS 还是 UEFI BIOS 都简称 BIOS;不论 MBR 还是 GPT 分区表都简称 MBR(GPT 保留相容区块)。

Boot Loader 的三大功能

功能说明
提供菜单使用者可选择不同开机项目(多重开机的基础)
载入核心文件直接指向可开机程序区段,启动操作系统
转交其他 loader将开机管理权交给其他 boot sector 内的 loader

多重开机原理

菜单一:MBR(grub2) → kernel file → booting
菜单二:MBR(grub2) → boot sector(Windows loader) → Windows kernel → booting
菜单三:MBR(grub2) → boot sector(grub2) → kernel file → booting

⚠️ Windows 的 loader 默认不具有控制权转交功能,因此必须先装 Windows 再装 Linux,让 Linux 的 grub2 覆盖 MBR 来管理多重开机。

核心载入与 initramfs

核心文件位于 /boot/vmlinuz-xxx。核心模块放在 /lib/modules/$(uname -r)/kernel/

initramfs 解决的问题:核心不认识 SATA/SCSI 磁盘 → 无法挂载根目录 → 无法读取 /lib/modules/ 里的驱动模块。这是一个死循环。

解决方案:initramfs (Initial RAM Filesystem) 由 boot loader 与 kernel 一起载入内存,在内存中仿真成一个小型根目录,包含磁盘/文件系统/RAID/LVM 等开机必需模块。等核心载入正确的驱动程序后,释放虚拟文件系统,挂载实际的根目录。

lsinitrd /boot/initramfs-3.10.0-229.el7.x86_64.img   # 查看 initramfs 内容
# initramfs 内部也是由 systemd 管理,default.target → initrd.target

解包 initramfs

mkdir /tmp/initramfs && cd /tmp/initramfs
dd if=/boot/initramfs-xxx.img of=initramfs.gz bs=11264 skip=1   # 跳过前置数据
gzip -d initramfs.gz
cpio -i -d -H newc --no-absolute-filenames < initramfs
# 现在可以看到一个小型根目录

19.1.3 第一支程序 systemd 及使用 default.target 进入开机程序分析

核心载入完毕后,调用第一支程序 systemd (PID=1)。systemd 以 /etc/systemd/system/default.target 规划开机流程。

runlevel 与 target 对应

SystemVsystemd
init 0systemctl poweroff
init 1systemctl rescue
init [234]systemctl isolate multi-user.target
init 5systemctl isolate graphical.target
init 6systemctl reboot
ll /usr/lib/systemd/system/runlevel*.target
# runlevel0.target → poweroff.target
# runlevel1.target → rescue.target
# runlevel2/3/4.target → multi-user.target
# runlevel5.target → graphical.target
# runlevel6.target → reboot.target

systemd 的服务启动流程

如果 default.target = graphical.target

  1. systemd 查找 /etc/systemd/system/graphical.target.wants/(用户设置)+ /usr/lib/systemd/system/graphical.target.wants/(系统默认)
  2. graphical.target 的 Requires=multi-user.target → 必须先完成 multi-user.target
  3. multi-user.target 的 Requires=basic.target → 必须先完成 basic.target
  4. 层层递进:local-fs.target + swap.target → sysinit.target → basic.target → multi-user.target → graphical.target
systemctl list-dependencies graphical.target   # 查看完整的启动依赖树

19.1.4 systemd 执行 sysinit.target 初始化系统、basic.target 准备系统

sysinit.target 主要工作

工作说明
特殊文件系统挂载dev-hugepages.mount, dev-mqueue.mount
特殊文件系统启用磁盘阵列、iSCSI、LVM、multipath
开机讯息传递plymouthd 服务(动画与讯息)
日志服务启用systemd-journald.service
载入额外核心模块/etc/modules-load.d/*.conf
载入核心参数/etc/sysctl.conf + /etc/sysctl.d/*.conf
乱数产生器加密演算使用
终端机字形console 字形设置
动态设备管理udevd — 动态对应设备存取与设备文件名

basic.target 主要工作

工作说明
载入 ALSA 音效驱动系统音效支持
载入 firewalld 防火墙CentOS 7 以 firewalld 取代 iptables
载入 CPU 微指令microcode
启动 SELinux设置安全本文(若由 disabled→enabled 会重新标注)
写入开机信息将开机过程写入 /var/log/dmesg
载入管理员指定模块/etc/sysconfig/modules/*.modules/etc/rc.modules
载入 timer 功能systemd timer 支持

sysinit.target = 初始化系统(让核心能存取硬件);basic.target = 最阳春的完整操作系统。

19.1.5 systemd 启动 multi-user.target 下的服务

服务启动脚本放在:

  • /usr/lib/systemd/system — 系统默认
  • /etc/systemd/system — 管理员自订

systemctl enable = 在 /etc/systemd/system/multi-user.target.wants/ 下创建符号链接:

systemctl enable vsftpd.service
# 实际执行:ln -s '/usr/lib/systemd/system/vsftpd.service' \
#   '/etc/systemd/system/multi-user.target.wants/vsftpd.service'

rc-local.service:兼容旧版 /etc/rc.d/rc.local。该文件必须可执行才会生效:

chmod a+x /etc/rc.d/rc.local
systemctl daemon-reload
systemctl list-dependencies multi-user.target | grep rc-local

getty.target:提供 tty 终端机登录界面。注意:getty 可能先于 systemd-logind.service 启动完毕,导致看到 tty1 但暂时无法登录——稍等几秒即可。

19.1.6 systemd 启动 graphical.target 下面的服务

如果是 graphical.target,会在 multi-user.target 基础上额外启动:

服务说明
accounts-daemon.service图形界面帐号管理
gdm.serviceGNOME Display Manager — 图形登录界面(核心)
network.service网络服务
rtkit-daemon.service实时调度
systemd-update-utmp-runlevel.service更新 runlevel 记录
systemctl isolate multi-user.target   # 从图形界面切换到文字界面

19.1.7 开机过程会用到的主要配置文件

模块加载配置

路径用途
/etc/modules-load.d/*.conf指定要载入的模块名(一行一个)
/etc/modprobe.d/*.conf模块加载时附带参数(options 模块名 参数
# 示例:加载 nf_conntrack_ftp 模块并指定 FTP 端口为 555
echo "nf_conntrack_ftp" > /etc/modules-load.d/vbird.conf
echo "options nf_conntrack_ftp ports=555" > /etc/modprobe.d/vbird.conf
 
systemctl restart systemd-modules-load.service   # 立即生效(无需重启)
lsmod | grep nf_conntrack_ftp                     # 验证

/etc/sysconfig/*

文件用途
authconfig身份认证机制(加密算法、外部验证等),用 authconfig-tui 修改
cpupowerCPU 频率调节策略(cpupower.service 读取)
firewalld防火墙配置
network-scripts/网卡设置
modules/*.modules管理员指定的额外模块

19.2 核心与核心模块

文件位置

内容路径
核心/boot/vmlinuz/boot/vmlinuz-version
虚拟文件系统/boot/initramfs/boot/initramfs-version
核心模块/lib/modules/$(uname -r)/kernel/
核心源代码/usr/src/kernels/(需安装,默认没有)

19.2.1 核心模块与相依性

模块目录结构 /lib/modules/$(uname -r)/kernel/

子目录内容
arch/硬件平台相关(CPU 等级等)
crypto/加密技术(md5, des 等)
drivers/硬件驱动(显卡、网卡、PCI 等)
fs/文件系统(vfat, reiserfs, nfs 等)
lib/函数库
net/网络协定 + 防火墙模块(net/ipv4/netfilter/*)
sound/音效模块

模块相依性记录在 /lib/modules/$(uname -r)/modules.dep,使用 depmod 创建/更新:

depmod          # 分析全部模块,写入 modules.dep
depmod -A       # 仅更新比 modules.dep 新的模块
depmod -n       # 不写入,只输出到屏幕
depmod -e       # 显示已载入的不可执行模块

模块扩展名一定是 .ko (kernel object)。

19.2.2 核心模块的观察

lsmod — 列出目前核心已载入的模块:

lsmod
# Module          Size  Used by
# nf_conntrack_ftp  18638  0
# nf_conntrack    105702  1 nf_conntrack_ftp    ← 依赖关系:conntrack 被 ftp 使用
# drm             311588  4 qxl,ttm,drm_kms_helper
字段说明
Module模块名称
Size模块大小(字节)
Used by被哪些模块依赖(数字=被几个模块使用,后面列出依赖者名称)

modinfo — 查看模块详细信息:

modinfo drm                   # 查看已载入模块的信息
modinfo /path/to/a.ko         # 查看未载入的 .ko 文件信息
# 输出:filename, license, description, author, depends, vermagic, parm...

19.2.3 核心模块的载入与移除

命令特点用法
insmod需完整路径,不处理相依性insmod /lib/modules/.../fat.ko
rmmod移除指定模块rmmod fat-f 强制
modprobe自动处理相依性(推荐)modprobe vfatmodprobe -r vfat 移除
# 错误示例——insmod 不会解析依赖
insmod vfat.ko   # ERROR: 可能找不到或依赖不满足
 
# 正确方式
modprobe vfat     # 自动从 modules.dep 查找并载入依赖
lsmod | grep cifs # cifs 依赖 dns_resolver,modprobe 会自动一并载入
modprobe -r cifs  # 移除

💡 modprobe 参考 modules.dep 克服相依性,且不需要完整路径——推荐始终使用 modprobe。

19.2.4 核心模块的额外参数设置:/etc/modprobe.d/*.conf

参见 19.1.7 节。创建 .conf 文件,通过 options 模块名 参数 传入。

19.3 Boot Loader: Grub2

CentOS 5/6 使用 grub (0.97),CentOS 7 开始换为 grub2,配置方式有所不同。

19.3.1 boot loader 的两个 stage

MBR 只有 446 Bytes,不可能容纳完整的 boot loader。因此 Linux 将 boot loader 分为两阶段:

阶段位置内容
Stage 1MBR 或 boot sectorboot loader 最小主程序(不含配置文件)
Stage 2/boot/grub2/载入所有配置文件与模块(grub.cfg + 文件系统模块)
ls -l /boot/grub2
# grub.cfg               ← 主配置文件(最重要!)
# grubenv                ← 环境区块符号
# device.map             ← 设备对应档
# fonts/                 ← 开机画面字体
# i386-pc/               ← x86 PC 所需的模块(acpi.mod, ext2.mod, xfs.mod, lvm.mod...)
# locale/                ← 语系数据
# themes/                ← 开机主题画面

grub2 通过模块机制支持大量文件系统和磁盘格式,这是它取代 grub1/LILO 的主要原因。

19.3.2 grub2 的配置文件 /boot/grub2/grub.cfg 初探

grub2 三大优点:认识更多文件系统、支持开机时编辑菜单(类 bash)、修改配置后不需重新安装

磁盘与分区代号

grub2 使用与 Linux 完全不同的硬盘命名:

(hd0,1)         # 第一颗硬盘的第一个分区(自动判断格式)
(hd0,msdos1)    # 明确指定为 MBR 格式
(hd0,gpt1)      # 明确指定为 GPT 格式
规则说明
硬盘编号从 0 开始(hd0) = 第一个被搜寻到的硬盘
分区编号从 1 开始(hd0,1) = 第一个分区(与 grub1 不同!grub1 分区从 0 开始)
按 BIOS 搜寻顺序编号若调整 BIOS 开机顺序,N 可能变动
Linux 设备grub2 代号
/dev/sda 整体磁盘(hd0)
/dev/sda1(hd0,msdos1) 或 (hd0,1)
/dev/sda5(第一个逻辑分区)(hd0,msdos5)
/dev/sdb (第二颗, GPT)(hd1,gpt1)

grub.cfg 的 menuentry 结构

menuentry 'CentOS Linux 7 (Core), with Linux 3.10.0-229.el7.x86_64' ... {
    load_video                        # 载入显卡模块
    set gfxpayload=keep
    insmod gzio                       # 载入解压缩模块
    insmod part_gpt                   # 载入 GPT 分区模块
    insmod xfs                        # 载入 XFS 文件系统模块
    set root='hd0,gpt2'               # grub2 配置文件所在设备(/boot 分区)
    search --no-floppy --fs-uuid ...   # 按 UUID 搜寻
    linux16 /vmlinuz-xxx root=/dev/mapper/centos-root ro ...   # 核心文件 + 参数
    initrd16 /initramfs-xxx.img       # initramfs 文件
}

三个关键参数的理解

参数含义注意
set root='hd0,gpt2'grub2 配置文件 (/boot/grub2) 所在的设备grub2 的 root,不是 Linux 根目录
linux16 /vmlinuz-xxx核心文件路径路径相对于 set root 指定的设备
linux16 ... root=/dev/mapper/...Linux 的根目录所在设备这是传给 kernel 的启动参数

如果 /boot 是独立分区:(hd0,gpt2)/vmlinuz-xxx → 路径是 /vmlinuz-xxx(相对于 /boot)
如果 /boot/ 同分区:(hd0,msdos1)/boot/vmlinuz-xxx → 路径是 /boot/vmlinuz-xxx

⚠️ 不要手动修改 grub.cfg!而是修改 /etc/default/grub/etc/grub.d/*,再用 grub2-mkconfig 生成。

19.3.3 grub2 配置文件维护 /etc/default/grub 与 /etc/grub.d

/etc/default/grub 主要环境变量

GRUB_TIMEOUT=5                   # 倒数秒数(0=不等,-1=必须手动选)
GRUB_TIMEOUT_STYLE=menu          # menu/countdown/hidden(是否显示菜单)
GRUB_DEFAULT=saved               # 默认开机菜单(0=第一个,saved=用grub2-set-default设置,或填--id名称)
GRUB_DISABLE_SUBMENU=true        # 隐藏次菜单
GRUB_TERMINAL_OUTPUT="console"   # 终端机模式:console/serial/gfxterm/vga_text
GRUB_CMDLINE_LINUX="rd.lvm.lv=... rhgb quiet"  # 传给核心的额外参数
GRUB_DISABLE_RECOVERY="true"     # 取消救援菜单

GRUB_DEFAULT 设置示例

GRUB_DEFAULT=0                      # 第一个 menuentry
GRUB_DEFAULT=3rd-win-system         # 使用 --id 名称
GRUB_DEFAULT=saved                  # 由 grub2-set-default 决定

修改后必须重新生成:

grub2-mkconfig -o /boot/grub2/grub.cfg

/etc/grub.d/* 菜单创建脚本

脚本功能
00_header初始显示设置(timeout, terminal, 模块等,读取 /etc/default/grub)
10_linux搜寻 /boot 下的核心文件,每个核心生成一个 menuentry
30_os-prober搜寻其他分区的操作系统(Windows 等),生成菜单项
40_custom管理员自订菜单——在这里添加自定义 menuentry

40_custom 示例——强制图形界面开机

vim /etc/grub.d/40_custom
menuentry 'My graphical CentOS7' --id 'mygraphical' {
    load_video
    insmod gzio
    insmod part_gpt
    insmod xfs
    set root='hd0,gpt2'
    search --no-floppy --fs-uuid --set=root 94ac5f77-...
    linux16 /vmlinuz-xxx root=/dev/mapper/centos-root ro ... systemd.unit=graphical.target
    initrd16 /initramfs-xxx.img
}
grub2-mkconfig -o /boot/grub2/grub.cfg

chainloader 移交控制权

menuentry "Windows" {
    insmod chain          # 载入 chainloader 模块
    insmod ntfs           # Windows 文件系统模块
    set root=(hd0,1)      # Windows 所在分区
    chainloader +1        # 读取该分区 boot sector 的 loader
}
menuentry "Go to MBR" {
    insmod chain
    set root=(hd0)        # 无分区号 = 指整个硬盘 MBR
    chainloader +1
}

19.3.4 initramfs 的重要性与创建新 initramfs 文件

需要 initramfs 的场景:

  • 根目录磁盘为 SATA/USB/SCSI 连接接口
  • 根目录文件系统为 LVM、RAID 等特殊格式
  • 根目录文件系统为非传统 Linux 文件系统
  • 其他必须在核心载入时提供的模块
dracut [-fv] [--add-drivers 列表] initramfs文件名 核心版本
参数说明
-f强制覆盖已有文件
-v显示详细过程
--add-drivers额外加入驱动模块
--filesystems加入额外文件系统支持
--gzip/--bzip2/--xz指定压缩方式(默认 gzip)
dracut -v initramfs-test.img $(uname -r)              # 默认创建
dracut -v --add-drivers "e1000e" --filesystems "ext4 nfs" initramfs-new.img $(uname -r)
lsinitrd initramfs-new.img | grep -E '(e1000|ext4|nfs)'   # 验证

19.3.5 测试与安装 grub2

grub2-install [--boot-directory=DIR] INSTALL_DEVICE
安装目标示例说明
安装到 MBRgrub2-install /dev/vdagrub2 文件 → /boot/grub2,主程序 → MBR
安装到分区grub2-install --force --recheck --skip-fs-probe /dev/vda4XFS 不支持 boot sector 嵌入,需加额外参数

完整的 grub2 配置步骤

  1. 安装 grub2(若从其他 loader 迁移):grub2-install /dev/vda
  2. 编辑 /etc/default/grub/etc/grub.d/*
  3. 生成配置文件:grub2-mkconfig -o /boot/grub2/grub.cfg

19.3.6 开机前的额外功能修改

开机菜单显示时,按下 e 进入编辑模式,可临时修改核心参数(类比 bash 编辑),改完后按 Ctrl+X 用修改后的参数开机。

在开机时进入救援模式

  1. 选中 menuentry,按 e
  2. linux16 那行末尾加上 systemd.unit=rescue.target
  3. Ctrl+X 开机

⚠️ systemd 的 rescue 模式需要 root 密码才能登录!(不同于旧版 SystemV runlevel 1 无需密码)。忘记 root 密码请见 19.4.1 的 rd.break 方法。

19.3.7 关于开机画面与终端机画面的图形显示方式

# /etc/default/grub
GRUB_TERMINAL=gfxterm          # 启用图形终端机
GRUB_GFXMODE=1024x768x24       # 分辨率与彩度
GRUB_GFXPAYLOAD_LINUX=keep     # 保留图形界面,不切换 text
grub2-mkconfig -o /boot/grub2/grub.cfg

重启后可显示中文菜单。还可以在 themes/ 中自定义企业/学校的开机画面。

19.3.8 为个别菜单加上密码

grub2 密码机制有两种身份:

身份设置权限
superusers系统管理员可修改所有菜单参数
users一般用户仅能选择有权限的菜单开机,不可修改

加密密码

grub2-mkpasswd-pbkdf2
# 输入密码 → 输出 PBKDF2 hash

创建 /etc/grub.d/01_users (数字开头,两个数字):

cat << eof
set superusers="vbird"
password_pbkdf2 vbird grub.pbkdf2.sha512.10000.9A2E...
password_pbkdf2 dmtsai grub.pbkdf2.sha512.10000.B595...
eof
 
chmod a+x /etc/grub.d/01_users

菜单的三种权限设置

设置效果
--unrestricted任何人都能开机(无密码限制),但设置了 superusers 后不可修改参数
--users dmtsai输入 dmtsai 或 superusers 的密码才能开机
无 —users 无 —unrestricted只有 superusers 可以进入和修改
vim /etc/grub.d/40_custom
menuentry 'Rescue CentOS7' --users dmtsai {
    ...
    linux16 /vmlinuz-xxx ... systemd.unit=rescue.target
    ...
}
 
grub2-mkconfig -o /boot/grub2/grub.cfg

⚠️ 10_linux 的默认 menuentry 带有 --unrestricted,所以默认的系统开机菜单无需密码。

19.4 开机过程的问题解决

19.4.1 忘记 root 密码的解决之道

使用 rd.break 核心参数进入 RAM Disk 环境的 root shell(无需密码):

步骤

1. 重新开机,在 grub 菜单选中项目后按 e
2. 在 linux16 行末尾加上 rd.break
3. 按 Ctrl+X 开机 → 进入 switch_root (RAM Disk) 的 root shell
switch_root:/# mount -o remount,rw /sysroot      # 重新挂载根目录为可读写
switch_root:/# chroot /sysroot                    # 切换根目录到原系统
sh-4.2# echo "new_password" | passwd --stdin root # 修改 root 密码
sh-4.2# touch /.autorelabel                       # ⚠️ 必须创建!让 SELinux 重新标注
sh-4.2# exit
switch_root:/# reboot

⚠️ 为什么不创建 /.autorelabel 会导致无法登录?
在 rd.break 的 RAM Disk 环境中没有 SELinux,修改 /etc/shadow 会使该文件的 SELinux 安全本文丢失。如果 SELinux 是 Enforcing 模式,系统开机时会阻止登录。touch /.autorelabel 会让系统在开机时自动以默认 type 重新写入所有文件的 SELinux 安全本文(花费时间较长)。

替代方案(不想等重新标注太久):

  1. rd.break 中修改密码后,改 /etc/selinux/configSELINUX=permissive
  2. 正常开机后以 root 执行 restorecon -Rv /etc
  3. 将 SELinux 改回 enforcing,执行 setenforce 1

19.4.2 直接开机就以 root 执行 bash 的方法

在 linux16 行末尾加 init=/bin/bash(而非 rd.break),系统会用 /bin/bash 取代 systemd 作为 PID=1。

mount -o remount,rw /     # 先重新挂载根目录
# 修改需要修复的文件...
特点说明
优点直接进入 bash,操作简单
缺点PATH 仅有 /bin;没有 systemd,无法 reboot/poweroff(只能强制关机);同样需要处理 SELinux
结论rd.break 更保险

19.4.3 因文件系统错误而无法开机

最常见的原因:/etc/fstab 写错(Quota/LVM/RAID 配置时)。屏幕提示输入 root 密码进入救援 shell 后:

mount -o remount,rw /       # 重新挂载根为可读写
vim /etc/fstab              # 修正错误

如果是不正常关机导致文件系统不一致(Inconsistent),需用 fsckxfs_repair 修复:

fsck.ext3 /dev/md0          # EXT 文件系统
xfs_repair /dev/vda2        # XFS 文件系统

命令速查表

命令用途
lsinitrd /boot/initramfs-xxx.img查看 initramfs 内容
lsmod列出所有已载入的核心模块
modinfo 模块名查看模块详细信息
insmod /path/to/module.ko载入模块(不处理相依性)
rmmod 模块名移除模块
modprobe 模块名载入模块(自动处理相依性,推荐)
modprobe -r 模块名移除模块(自动处理相依性)
depmod重建 modules.dep 相依性文件
dracut -v initramfs文件名 核心版本创建 initramfs
grub2-mkconfig -o /boot/grub2/grub.cfg重建 grub2 配置文件
grub2-install /dev/vda安装 grub2 到 MBR
grub2-mkpasswd-pbkdf2生成 grub2 PBKDF2 加密密码
systemctl list-dependencies graphical.target查看开机服务依赖树
systemctl isolate multi-user.target切换到文字界面
chroot /sysroot切换根目录(救援时使用)