Linux 系统启动原理摘要本文详细解析了 CentOS 7 系统的完整启动流程从硬件加电到用户登录的各个阶段。内容涵盖系统固件UEFI/BIOS、GRUB2 引导加载器、内核与 initramfs 加载、systemd 初始化过程以及系统 target 和运行级别的概念。同时文章深入探讨了常见系统故障的排查与修复方法包括 root 密码重置、/etc/fstab 配置错误、GRUB2 引导故障等并提供了详细的命令行操作步骤和故障恢复方案。最后文章还解答了关于磁盘加密、内核与 initramfs 分离设计等高级技术原理的思考题。1.CentOS 7 启动过程现代计算机系统是硬件与软件的复杂组合。从加电状态开始到拥有登录提示符的运行中系统这需要大量的硬件和软件配合工作。以下列表从较高层面概述了 CentOS7 启动过程。1.计算机接通电源。系统固件现代UEFI或更旧的BIOS)运行开机自检(POST)并开始初始化硬件。配置 在系统启动早期通过按特定的组合键例如F2配置系统固件。2.系统固件搜索启动设备根据固件配置的顺序搜索启动磁盘上的主启动记录(MBR)。系统固件从磁盘读取boot loader然后将系统控制权交给boot loaderboot loader是GRand Unified Bootloader version 2(GRUB2)。配置 使用 grub2-install 命令进行配置它将安装 GRUB2 作为磁盘上的启动加载器。3.GRUB2从/boot/grub2/grub.cfg文件加载配置并显示一个操作系统菜单可以从中选择要启动的系统。配置 使用 /etc/grub.d/ 目录、/etc/default/grub 文件和 grub2-mkconfig 命令进行配置以生成 /boot/grub2/grub.cfg 文件。4.boot loader根据选定条目的配置从磁盘中加载kernel和initramfs并将它们放入内存中。initramfs是一个存档其中包含启动时所有必要硬件的内核模块、初始化脚本等等。boot loader将控制权交给kernel并同时将启动项的内核参数、initramfs在内存中的位置传递给kernel。内核在initramfs中找到所有硬件驱动程序并初始化这些硬件。配置 使用 /etc/dracut.conf.d/ 用录、dracut 命令和 lsinitrd 命令进行配置以检查 initramfs 文件。5.initramfs 执行/sbin/init作为PID 1。在CentOS中/sbin/init是一个指向systemd的链接。配置 使用内核参数initcommand配置系统初始化程序。6.随后systemd会加载从内核命令行传递的target或者加载系统配置的default.target该目标通常启动一个基于文本的登录或图形登录屏幕。配置使用systemctl设置默认target。7.default.target依赖sysinit.targetsysinit.target用于初始化系统例如读取/etc/fstab挂载文件系统激活systemd-journald等。配置使用/etc/fstab配置文件系统开机自动挂载。8.default.target还会激活开机启动的单元。配置使用systemctl设置开机启用服务。9.default.target还会激活getty.target该target将打开tty1终端用于用户登录。2.系统 target普通文件和目录之间关系• 普通文件用来存储数据例如MP3、mp4、fstab、passwd• 目录用来组织文件系统分层结构白话用来分组文件。systemd使用类型为target的单元来分组不同单元例如multi-user.target包涵chronyd.service、crond.service、firewalld.service等服务。target还可以包涵其他target例如graphical.target包涵multi-user.targetmulti-user.target包涵basic.targetbasic.target包涵sysinit.target。使用以下命令查看target之间依赖关系[rootclient ~13:58:04]# systemctl list-dependencies graphical.targetgraphical.target ● ├─accounts-daemon.service ● ├─gdm.service ● ├─initial-setup-reconfiguration.service ● ├─network.service ● ├─rtkit-daemon.service ● ├─systemd-update-utmp-runlevel.service ● ├─udisks2.service ● └─multi-user.target......# 查看反向依赖[rootclient ~13:59:29]# systemctl list-dependencies sshd.service --reversesshd.service ● └─multi-user.target ● └─graphical.target3.系统启动级别传统的 SysVinit 系统定义了 7 个运行级别0-6每个级别有特定的作用具体如下运行级别target作用描述0关机halt系统终止所有进程并关闭电源对应命令 shutdown -h now。1emergency.target rescue.target单用户模式single user mode仅 root 用户可登录无网络服务用于系统修复如密码找回。2多用户模式无 NFS支持多用户登录但不启动网络文件系统NFS部分发行版如 Debian默认此级别功能与级别 3 相同。3multi-user.target完全多用户模式文本界面启动所有网络服务用户通过命令行登录无图形界面。4预留级别默认未使用可由用户自定义用途。5graphical.target图形化多用户模式在级别 3 的基础上启动图形界面如 GNOME、KDE用户通过图形登录界面访问系统。6重启reboot系统终止所有进程并重启对应命令 shutdown -r now。4.设置系统运行目标/etc/inittab文件是CentOS 6之前版本初始化系统使用的配置文件。# 部分内容如下# 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:(1)设置系统当前运行 target# 设置系统当前运行target为multi-user.target[rootclient ~13:59:33]# systemctl isolate multi-user.target# 等效与[rootclient ~14:04:25]# init 3# 设置系统当前运行target为graphical.target[rootclient ~14:04:34]# systemctl isolate graphical.target# 等效与[rootclient ~14:05:53]# init 5(2)设置系统开机默认运行 target# 查看系统开机默认运行target[rootclient ~14:08:03]# systemctl get-defaultgraphical.target# 设置系统开机默认运行target[rootclient ~14:08:08]# systemctl set-default multi-user.target# 重启验证(3)在系统启动时选择其它目标要在启动时选择其他目标将 systemd.unittarget.target 参数附加到内核命令行。该配置是临时生效的经常用于系统启动过程中故障排除。要使用这种选择其他目标的方法请执行以下步骤1.启动或重新启动系统。2.按任意键中断启动加载器菜单倒计时Enter除外它用于执行正常启动。3.将光标移至第一个内核条目按e编辑当前条目。4.将光标移至以linux16开头的行末尾附加systemd.unittarget.target。例如systemd.unitmulti-user.target。按 Ctrlx 使用这些更改进行启动。5.重置 ROOT 密码以下几种方法可用于设置新的root密码。例如• 系统管理员可以使用Live CD启动系统挂载根文件系统然后编辑/etc/shadow• 删除root账户密码字段• 使用已知密码字段替换root密码字段• 在CentOS 7之后版本中可以让initramfs运行的脚本在某些点暂停以提供root身份的shell然后在该shell中重置root密码。方法1rd.break1.重新启动系统。2.按任意键Enter除外中断启动加载器倒计时。3.将光标移至第一个内核条目按e编辑当前条目。4.将光标移至以 linux16 开头的行末尾附加 rd.break。利用该选项在系统从initramfs向实际系统移交控制权前系统将会中断。按Ctrlx进行启动。5.此时系统会显示root shell且磁盘上的实际根文件系统以只读方式挂载在/sysroot。以读/写形式重新挂载/sysroot。switch_root:/# mount -o remount,rw /sysroot6.切换root位置把/sysroot做为文件系统树的根。switch_root:/# chroot /sysroot7.设置新root密码。sh-4.2# echo password | passwd --stdin root提示password 是用户自定义密码。8.如果系统开启了 SELinux 功能则需要确保所有未标记的文件包括此时的/etc/shadow)在启动过程中都会重新获得标记。sh-4.2# touch /.autorelabel9.执行以下命令系统将继续启动。如果系统开启了SELinux功能还需要执行完整的 SELinux 重新标记然后再次重新启动。sh-4.2# exitswitch_root:/# exit10.登录验证。方法2init/bin/bash1.重新启动系统。2.按任意键Enter除外中断启动加载器倒计时。3.将光标移至第一个内核条目按e编辑当前条目。4.将光标移至以 linux16 开头的行末尾附加 init/bin/bash。利用该选项在系统从initramfs向实际系统移交控制权前系统将会中断请开启一个root shell。按Ctrlx使用这些更改进行启动。5.此时系统会显示root shell且磁盘上的实际根文件系统以只读方式挂载在/。以读/写形式重新挂载/。bashbash-4.2# mount -o remount,rw /6.使用以下命令删除root密码等进入系统后再重新设置root密码。bashsh-4.2# passwd -d root此时还可以使用vi编辑器直接编辑/etc/shadow文件复制已知用户的密码记录替换root密码。7.如果系统开启了 SELinux 功能则需要确保所有未标记的文件包括此时的/etc/shadow)在启动过程中都会重新获得标记。bashsh-4.2# touch /.autorelabel8.执行以下命令系统将继续启动。如果系统开启了SELinux功能还需要执行完整的 SELinux 重新标记然后再次重新启动。bashsh-4.2# exec /usr/lib/systemd/systemd9.使用root登录此时不需要密码。6./etc/fstab 引起的系统启动问题环境准备# 设置磁盘分区管理方案[rootserver ~ 09:47:52]# parted /dev/sdb mklabel msdos信息: You may need to update /etc/fstab.# 创建分区[rootserver ~ 09:48:11]# parted /dev/sdb unit MiB mkpart primary 1 10241信息: You may need to update /etc/fstab.# 格式化为xfs文件系统[rootserver ~ 09:48:45]# mkfs.xfs /dev/sdb1meta-data/dev/sdb1isize512agcount4,agsize655360blkssectsz512attr2,projid32bit1crc1finobt0,sparse0databsize4096blocks2621440,imaxpct25sunit0swidth0blks namingversion2bsize4096ascii-ci0ftype1loginternal logbsize4096blocks2560,version2sectsz512sunit0blks, lazy-count1realtimenoneextsz4096blocks0,rtextents0# 创建挂载点[rootserver ~ 09:48:59]# mkdir /data01# 设置持久化挂载[rootserver ~ 09:49:08]# echo /dev/sdb1 /data01 xfs defaults 0 0 /etc/fstab# 挂载并验证[rootserver ~ 09:50:18]# mount -a[rootserver ~ 09:50:25]# df -h /data01文件系统 容量 已用 可用 已用% 挂载点 /dev/sdb1 10G 33M 10G1% /data01故障1挂载点不存在环境准备[rootserver ~ 09:50:31]# umount /data01[rootserver ~ 09:50:45]# rmdir /data01重启系统验证# 可以正常进入系统挂载点会被自动创建[rootserver ~ 09:50:51]# rebootConnection closing...Socket close. Connection closed by foreign host. Disconnected from remote host(server)at 09:51:06. Type help to learn how to use Xshell prompt. [D:\~]$ Connecting to 10.1.8.10:22... Connection established. To escape to local shell, press CtrlAlt]. WARNING!The remote SSH server rejected X11 forwarding request. Last login: Mon May2509:47:472026from10.1.8.1[rootserver ~ 09:51:37]# df -h /data01文件系统 容量 已用 可用 已用% 挂载点 /dev/sdb1 10G 33M 10G1% /data01故障2设备名称写错或者找不到设备环境准备[rootserver ~ 09:51:40]# vim /etc/fstab# 将原先的sdb1修改为sdd2/dev/sdd2 /data01 xfs defaults00重启系统验证启动过程中找不到该设备。1分30秒超时后进入emergency模式进行修复。修改为正确的值或者注释该条目确保系统正常启动。然后输入exit继续启动。故障3破坏文件系统环境准备[rootserver ~10:07:50]# dd if/dev/zero of/dev/sdb1 bs1M count1记录了10 的读入 记录了10 的写出1048576字节(1.0MB)已复制0.0043394 秒242 MB/秒重启系统验证1.系统启动过程中尝试修复文件系统修复失败后提示进入 emergency 模式修复。2.输入root 密码进入emergency 模式。bash# 执行以下命令修复 [rootserver ~]# xfs_repair /dev/sdb1#修复完成后输入 exit 正常启动系统。7.grub2 配置(1)grub2 配置文件grub2 的主要配置文件如下• /boot/grub2grub2的主要配置文件所在目录例如grub.cfg、grubenv、user.cfg。• /etc/grub2.cfg• /etc/grub2.cfg 是指向 /boot/grub2/grub.cfg的软连接。• 不要直接修改/etc/grub2.cfg文件该文件由系统自动生成。如果需要自定义这个文件可以通过修改/etc/grub.d/中脚本和/etc/default/grub文件然后通过grub2-mkconfig命令生成。使用efi启动方式的grub2配置文件是/etc/grub2-efi.cfg。• /etc/grub.d/该目录下存放多个数字开头的脚本按照从小到大的顺序执行。例如00_header会调用/etc/default/grub配置文件来实现最基本的开机界面配置。• /etc/default/grub定义grub启动部分变量信息例如grub启动菜单选择条目的超时时间内核参数等。• /boot/grub2/grubenv设定默认启动条目。(2)grub 菜单超时时间[rootserver ~11:47:10]# vim /etc/default/grub# 修改GRUB_TIMEOUT为10GRUB_TIMEOUT10# 生效grub2.cfg配置文件[rootserver ~11:47:37]# grub2-mkconfig -o /etc/grub2.cfgGenerating grub configurationfile... Found linux image: /boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64 Found initrd image: /boot/initramfs-3.10.0-1160.71.1.el7.x86_64.img Found linux image: /boot/vmlinuz-0-rescue-144c971d1c794dc8b77de4acacfc8133 Found initrd image: /boot/initramfs-0-rescue-144c971d1c794dc8b77de4acacfc8133.imgdone# 重启[rootserver ~11:48:12]# reboot(3)kernel 启动参数[rootserver ~12:26:03]# vim /etc/default/grub# 修改GRUB_CMDLINE_LINUX例如在最后添加参数consolettyS0导致不显示启动过程GRUB_CMDLINE_LINUXrd.lvm.lvcentos/root rd.lvm.lvcentos/swap rhgb quiet consolettyS0# consolettyS0: 启动过程信息显示到 ttyS0 终端导致启动过程是tty1上不显示启动消息。# rhgb启用图形化启动界面Red Hat Graphical Boot。# quiet减少启动过程中的日志输出只显示重要信息 debug 开启调试模式显示详细启动日志# 生成grub2.cfg配置文件重启验证[rootserver ~12:27:12]# grub2-mkconfig -o /etc/grub2.cfg[rootserver ~12:27:12]# reboot效果如下(4)grub 菜单加密# 查看/etc/grub.d/01_users脚本[rootserver ~10:33:22]# cat /etc/grub.d/01_users#!/bin/sh -ecatEOF if [ -f \${prefix}/user.cfg ]; then source \${prefix}/user.cfg if [ -n \${GRUB2_PASSWORD} ]; then set superusersroot export superusers password_pbkdf2 root \${GRUB2_PASSWORD}fi fi EOF# 生成grub2密码[rootserver ~10:34:16]# grub2-mkpasswd-pbkdf2输入口令 Reenter password: PBKDF2hashof your password is grub.pbkdf2.sha512.10000.6FB2E329873B8C51EEB1C142B691D5A9B1B9847AFC55D3757F5EE53647ACE9C5C5321B7E595617083CA792C5557BBFC41FCE8B941BE0071A837853432780C18A.C1B29531450EBD8000D0525B96D0EF1E69BC1194C672CECCE8525C77107DE9F47A5D031B05E53C09FE64657ADAC9D3862AB06E419C99332E65AF27FBBD6FA230# 创建文件[rootserver ~10:36:07]# vim /boot/grub2/user.cfgGRUB2_PASSWORDgrub.pbkdf2.sha512.10000.6FB2E329873B8C51EEB1C142B691D5A9B1B9847AFC55D3757F5EE53647ACE9C5C5321B7E595617083CA792C5557BBFC41FCE8B941BE0071A837853432780C18A.C1B29531450EBD8000D0525B96D0EF1E69BC1194C672CECCE8525C77107DE9F47A5D031B05E53C09FE64657ADAC9D3862AB06E419C99332E65AF27FBBD6FA230# 生成grub2.cfg配置文件重启验证[rootserver ~10:37:44]# grub2-mkconfig -o /boot/grub2/grub.cfgGenerating grub configurationfile... Found linux image: /boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64 Found initrd image: /boot/initramfs-3.10.0-1160.71.1.el7.x86_64.img Found linux image: /boot/vmlinuz-0-rescue-144c971d1c794dc8b77de4acacfc8133 Found initrd image: /boot/initramfs-0-rescue-144c971d1c794dc8b77de4acacfc8133.imgdone[rootserver ~10:38:23]# reboot效果如下1.启动菜单界面按e编辑。2.输入用户名root密码自己设置的。3.弹出如下菜单可以编辑了。思考如何解除 grub 菜单加密8.grub2 故障处理MBR 组成回顾主引导扇区由三个部分组成• 引导程序占446个字节硬盘启动时将系统控制权转给分区表中的某个操作系统。• 磁盘分区表项DPTDisk Partition Table)由四个分区表项构成每个16个字节。• 结束标志占2个字节其值为AA55十六进制。故障1grub 引导程序故障环境准备[rootcentos7 ~]# dd if/dev/zero of/dev/sda bs1 count446效果如下系统无法从硬盘启动则会尝试使用其他设备启动。解决思路使用光盘启动并重新安装引导程序。解决过程1.开机从光盘启动并选择Troubleshooting。2.选择Rescue a CentOS system3.稍等片刻进入选择界面选择 1。搜索到系统后提示系统已经挂载在/mnt/sysimage按回车继续。4.切换root目录并确保root文件系统是读写挂载。bashsh-4.2# chroot /mnt/sysimage bash-4.2# mount | grep root /dev/mapper/centos-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota )5.确认系统启动分区所在磁盘。6.安装引导程序。bashbash-4.2# grub2-install /dev/sda Installing for i386-pc platform. Installation finished. No error reported.7.输入 exit 两次重启系统第一次exit退出chroot环境第二次exit退出系统。bashbash-4.2# exit sh-4.2# exit故障2引导文件丢失环境准备[rootcentos7 ~]# mv /boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64{,.ori}[rootcentos7 ~]# reboot效果如下系统无法启动提示/vmlinuz-4.18.0-553.el8_10.x86_64文件找不到。解决思路使用光盘启动并从起位置恢复相应文件。解决过程1.参考 grub 引导程序故障 处理流程获取root权限shell。2.恢复文件。从其他系统复制过来从rpm包提取等3.输入 exit 两次继续启动系统。9.故障处理总结通过光盘启动的目的是将硬盘上的系统挂载到内存中并进行修复。我们也可以通过U盘启动盘启动或者将故障磁盘拔下来挂载到其他系统。10.思考1.如何避免别人获得磁盘后读取磁盘中数据在 CentOS 7 中通常使用 LUKSLinux Unified Unified Key SetupLinux 统一密钥设置 对磁盘或分区进行加密你提到的 “lunks” 应为 “LUKS” 的拼写误差。LUKS 是 Linux 下主流的磁盘加密标准通过加密整个分区或逻辑卷保护数据安全。在操作系统安装配置安装位置的时候可以使用LUKS加密磁盘。效果系统启动的时候必须输入密码才能读取硬盘中数据。2.修复磁盘的时候同样需要输入密码。**提示**该加密操作不会加密grub2系统选择菜单也就是/boot目录中数据。2.为什么将vmlinuz(kernel)和initramfs(user)分开?(1)职责分离降低维护复杂度vmlinuz 是压缩后的 Linux 内核镜像核心作用是提供系统运行的基础内核功能比如进程管理、内存管理、基础调度等核心能力它是系统运行的核心骨架需保持通用性和稳定性不能频繁改动。而 initramfs 是临时内存文件系统核心职责是补充启动所需的 “辅助工具”比如特定磁盘驱动、LVM 逻辑卷模块、LUKS 加密解密工具等。二者分离后内核升级无需同步修改驱动等辅助组件驱动更新也不用重新编译内核大幅降低了系统维护难度。(2)精简内核体积提升启动效率若将所有硬件驱动、特殊存储所需模块都集成进 vmlinuz会让内核体积急剧增大。vmlinuz 作为需被引导加载器加载到内存的文件体积过大会延长加载时间和内核解压耗时。而 initramfs 仅包含当前硬件和存储环境必需的模块是按需定制的轻量化组件。这种拆分让 vmlinuz 保持小巧加载和解压更快同时 initramfs 的轻量化设计也能快速完成临时系统初始化。(3)适配多硬件与场景增强通用性不同设备的硬件配置差异极大比如有的用 SATA 硬盘、有的用 NVMe 硬盘还有的依赖 RAID 阵列或加密存储。若内核集成所有硬件的驱动既不现实也会造成冗余。initramfs 可针对不同硬件环境定制生成包含对应驱动和工具。同一版本的 vmlinuz 搭配不同的 initramfs就能适配台式机、服务器、嵌入式设备等多种硬件场景让 Linux 系统的硬件兼容性大幅提升。3.Linux为什么不直接使用真正的根启动(1)缺少驱动无法识别真正的根设备真正的根文件系统通常存储在硬盘、SSD 等存储设备上而这些设备需要对应的驱动程序才能被内核识别。但 vmlinuz 作为通用内核仅集成少量通用驱动无法覆盖所有特殊存储硬件如 NVMe 硬盘、RAID 控制器等。此时 initramfs 可先加载这些缺失的驱动模块让内核能识别到存储设备后续才能挂载真正的根文件系统。若直接启动真正的根内核会因无法识别存储设备而启动失败。(2)无法处理复杂的根目录配置现代 Linux 系统中根文件系统常涉及复杂配置比如采用 LVM 逻辑卷管理磁盘分区、通过 LUKS 实现全盘加密、根目录存储在网络设备上等。这些场景都需要在挂载根目录前执行额外操作如激活 LVM 卷、解密加密分区、连接网络等。而真正的根文件系统未挂载时这些操作无法执行。initramfs 作为临时系统可提前运行对应的工具和脚本完成这些操作为真正根目录的挂载铺路。(3)保障启动流程的稳定性与安全性真正的根文件系统可能存在损坏、挂载异常等问题。若直接启动真正的根一旦出现问题系统会直接卡死且难以排查。而 initramfs 作为过渡层可在挂载真正根之前做基础检查若发现问题还能提供应急修复环境。此外对于加密存储的根目录initramfs 可在临时环境中完成解密流程避免解密逻辑直接暴露在核心内核中也提升了系统启动的安全性。