运维必看:CentOS7开机全链路分析+root密码/引导故障急救方案
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 loader,boot 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的链接。
配置: 使用内核参数init=command配置系统初始化程序。
6.随后,systemd会加载从内核命令行传递的target或者加载系统配置的default.target,该目标通常启动一个基于文本的登录或图形登录屏幕。
配置:使用systemctl设置默认target。
7.default.target依赖sysinit.target,sysinit.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.target,multi-user.target包涵basic.target,basic.target包涵sysinit.target。
使用以下命令查看target之间依赖关系:
[root@client ~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......# 查看反向依赖[root@client ~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。 | |
| 1 | emergency.target rescue.target | 单用户模式(single user mode):仅 root 用户可登录,无网络服务,用于系统修复(如密码找回)。 |
| 2 | 多用户模式(无 NFS):支持多用户登录,但不启动网络文件系统(NFS),部分发行版(如 Debian)默认此级别功能与级别 3 相同。 | |
| 3 | multi-user.target | 完全多用户模式(文本界面):启动所有网络服务,用户通过命令行登录,无图形界面。 |
| 4 | 预留级别:默认未使用,可由用户自定义用途。 | |
| 5 | graphical.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[root@client ~13:59:33]# systemctl isolate multi-user.target# 等效与[root@client ~14:04:25]# init 3# 设置系统当前运行target为graphical.target[root@client ~14:04:34]# systemctl isolate graphical.target# 等效与[root@client ~14:05:53]# init 5(2)设置系统开机默认运行 target
# 查看系统开机默认运行target[root@client ~14:08:03]# systemctl get-defaultgraphical.target# 设置系统开机默认运行target[root@client ~14:08:08]# systemctl set-default multi-user.target# 重启验证(3)在系统启动时选择其它目标
要在启动时选择其他目标,将 systemd.unit=target.target 参数附加到内核命令行。该配置是临时生效的,经常用于系统启动过程中故障排除。
要使用这种选择其他目标的方法,请执行以下步骤:
1.启动或重新启动系统。
2.按任意键中断启动加载器菜单倒计时(Enter除外,它用于执行正常启动)。
3.将光标移至第一个内核条目,按e编辑当前条目。
4.将光标移至以linux16开头的行,末尾附加systemd.unit=target.target。例如,systemd.unit=multi-user.target。按 Ctrl+x 使用这些更改进行启动。
5.重置 ROOT 密码
以下几种方法可用于设置新的root密码。例如:
• 系统管理员可以使用Live CD启动系统,挂载根文件系统,然后编辑/etc/shadow:
• 删除root账户密码字段
• 使用已知密码字段替换root密码字段
• 在CentOS 7之后版本中,可以让initramfs运行的脚本在某些点暂停,以提供root身份的shell,然后在该shell中重置root密码。
方法1:rd.break
1.重新启动系统。
2.按任意键(Enter除外)中断启动加载器倒计时。
3.将光标移至第一个内核条目,按e编辑当前条目。
4.将光标移至以 linux16 开头的行,末尾附加 rd.break。利用该选项,在系统从initramfs向实际系统移交控制权前,系统将会中断。按Ctrl+x进行启动。
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.登录验证。
方法2:init=/bin/bash
1.重新启动系统。
2.按任意键(Enter除外)中断启动加载器倒计时。
3.将光标移至第一个内核条目,按e编辑当前条目。
4.将光标移至以 linux16 开头的行,末尾附加 init=/bin/bash。利用该选项,在系统从initramfs向实际系统移交控制权前,系统将会中断,请开启一个root shell。按Ctrl+x使用这些更改进行启动。
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 引起的系统启动问题
环境准备
# 设置磁盘分区管理方案[root@server ~ 09:47:52]# parted /dev/sdb mklabel msdos信息: You may need to update /etc/fstab.# 创建分区[root@server ~ 09:48:11]# parted /dev/sdb unit MiB mkpart primary 1 10241信息: You may need to update /etc/fstab.# 格式化为xfs文件系统[root@server ~ 09:48:45]# mkfs.xfs /dev/sdb1meta-data=/dev/sdb1isize=512agcount=4,agsize=655360blks=sectsz=512attr=2,projid32bit=1=crc=1finobt=0,sparse=0data=bsize=4096blocks=2621440,imaxpct=25=sunit=0swidth=0blks naming=version2bsize=4096ascii-ci=0ftype=1log=internal logbsize=4096blocks=2560,version=2=sectsz=512sunit=0blks, lazy-count=1realtime=noneextsz=4096blocks=0,rtextents=0# 创建挂载点[root@server ~ 09:48:59]# mkdir /data01# 设置持久化挂载[root@server ~ 09:49:08]# echo '/dev/sdb1 /data01 xfs defaults 0 0' >> /etc/fstab# 挂载并验证[root@server ~ 09:50:18]# mount -a[root@server ~ 09:50:25]# df -h /data01文件系统 容量 已用 可用 已用% 挂载点 /dev/sdb1 10G 33M 10G1% /data01故障1:挂载点不存在
环境准备
[root@server ~ 09:50:31]# umount /data01[root@server ~ 09:50:45]# rmdir /data01重启系统验证
# 可以正常进入系统,挂载点会被自动创建[root@server ~ 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 'Ctrl+Alt+]'. WARNING!The remote SSH server rejected X11 forwarding request. Last login: Mon May2509:47:472026from10.1.8.1[root@server ~ 09:51:37]# df -h /data01文件系统 容量 已用 可用 已用% 挂载点 /dev/sdb1 10G 33M 10G1% /data01故障2:设备名称写错或者找不到设备
环境准备
[root@server ~ 09:51:40]# vim /etc/fstab# 将原先的sdb1修改为sdd2/dev/sdd2 /data01 xfs defaults00重启系统验证
- 启动过程中找不到该设备。
- 1分30秒超时后,进入emergency模式,进行修复。
修改为正确的值或者注释该条目,确保系统正常启动。 - 然后输入exit,继续启动。
故障3:破坏文件系统
环境准备
[root@server ~10:07:50]# dd if=/dev/zero of=/dev/sdb1 bs=1M count=1记录了1+0 的读入 记录了1+0 的写出1048576字节(1.0MB)已复制,0.0043394 秒,242 MB/秒重启系统验证
1.系统启动过程中尝试修复文件系统,修复失败后提示进入 emergency 模式修复。
2.输入root 密码进入emergency 模式。
bash# 执行以下命令修复 [root@server ~]# xfs_repair /dev/sdb1#修复完成后,输入 exit 正常启动系统。7.grub2 配置
(1)grub2 配置文件
grub2 的主要配置文件如下:
• /boot/grub2,grub2的主要配置文件所在目录,例如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 菜单超时时间
[root@server ~11:47:10]# vim /etc/default/grub# 修改GRUB_TIMEOUT为10GRUB_TIMEOUT=10# 生效grub2.cfg配置文件[root@server ~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# 重启[root@server ~11:48:12]# reboot(3)kernel 启动参数
[root@server ~12:26:03]# vim /etc/default/grub# 修改GRUB_CMDLINE_LINUX,例如在最后添加参数console=ttyS0,导致不显示启动过程GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet console=ttyS0"# console=ttyS0: 启动过程信息显示到 ttyS0 终端,导致启动过程是tty1上不显示启动消息。# rhgb:启用图形化启动界面(Red Hat Graphical Boot)。# quiet:减少启动过程中的日志输出(只显示重要信息), debug 开启调试模式(显示详细启动日志)# 生成grub2.cfg配置文件,重启验证[root@server ~12:27:12]# grub2-mkconfig -o /etc/grub2.cfg[root@server ~12:27:12]# reboot效果如下:
(4)grub 菜单加密
# 查看/etc/grub.d/01_users脚本[root@server ~10:33:22]# cat /etc/grub.d/01_users#!/bin/sh -ecat<<EOF if [ -f \${prefix}/user.cfg ]; then source \${prefix}/user.cfg if [ -n "\${GRUB2_PASSWORD}" ]; then set superusers="root" export superusers password_pbkdf2 root \${GRUB2_PASSWORD}fi fi EOF# 生成grub2密码[root@server ~10:34:16]# grub2-mkpasswd-pbkdf2输入口令: Reenter password: PBKDF2hashof your password is grub.pbkdf2.sha512.10000.6FB2E329873B8C51EEB1C142B691D5A9B1B9847AFC55D3757F5EE53647ACE9C5C5321B7E595617083CA792C5557BBFC41FCE8B941BE0071A837853432780C18A.C1B29531450EBD8000D0525B96D0EF1E69BC1194C672CECCE8525C77107DE9F47A5D031B05E53C09FE64657ADAC9D3862AB06E419C99332E65AF27FBBD6FA230# 创建文件[root@server ~10:36:07]# vim /boot/grub2/user.cfgGRUB2_PASSWORD=grub.pbkdf2.sha512.10000.6FB2E329873B8C51EEB1C142B691D5A9B1B9847AFC55D3757F5EE53647ACE9C5C5321B7E595617083CA792C5557BBFC41FCE8B941BE0071A837853432780C18A.C1B29531450EBD8000D0525B96D0EF1E69BC1194C672CECCE8525C77107DE9F47A5D031B05E53C09FE64657ADAC9D3862AB06E419C99332E65AF27FBBD6FA230# 生成grub2.cfg配置文件,重启验证[root@server ~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[root@server ~10:38:23]# reboot效果如下:
1.启动菜单界面,按e编辑。
2.输入用户名root,密码自己设置的。
3.弹出如下菜单,可以编辑了。
思考:如何解除 grub 菜单加密?
8.grub2 故障处理
MBR 组成回顾
主引导扇区由三个部分组成:
• 引导程序(占446个字节),硬盘启动时将系统控制权转给分区表中的某个操作系统。
• 磁盘分区表项(DPT,Disk Partition Table),由四个分区表项构成(每个16个字节)。
• 结束标志(占2个字节),其值为AA55(十六进制)。
故障1:grub 引导程序故障
环境准备
[root@centos7 ~]# dd if=/dev/zero of=/dev/sda bs=1 count=446效果如下:系统无法从硬盘启动,则会尝试使用其他设备启动。
解决思路:使用光盘启动,并重新安装引导程序。
解决过程:
1.开机从光盘启动,并选择Troubleshooting。
2.选择Rescue a CentOS system
3.稍等片刻,进入选择界面,选择 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:引导文件丢失
环境准备
[root@centos7 ~]# mv /boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64{,.ori}[root@centos7 ~]# reboot效果如下:系统无法启动,提示/vmlinuz-4.18.0-553.el8_10.x86_64文件找不到。
解决思路:使用光盘启动,并从起位置恢复相应文件。
解决过程:
1.参考 << grub 引导程序故障 >>处理流程,获取root权限shell。
2.恢复文件。(从其他系统复制过来,从rpm包提取等)
3.输入 exit 两次继续启动系统。
9.故障处理总结
通过光盘启动的目的是将硬盘上的系统挂载到内存中,并进行修复。
我们也可以通过U盘启动盘启动或者将故障磁盘拔下来挂载到其他系统。
10.思考
1.如何避免别人获得磁盘后,读取磁盘中数据?
在 CentOS 7 中,通常使用 LUKS(Linux Unified Unified Key Setup,Linux 统一密钥设置) 对磁盘或分区进行加密(你提到的 “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 可在临时环境中完成解密流程,避免解密逻辑直接暴露在核心内核中,也提升了系统启动的安全性。
