Grub2和Systemd环境下的Linux启动流程

1. BIOS初始化

BIOS的初始化就是BIOS上电自检POST(Power On Self Test)。这个过程主要由硬件完成。主要过程有:

  • 外设检查
  • 引导设备选择(一般是硬盘)
  • 硬盘第一扇区的读取和运行

当BIOS的POST成功后将触发INT 13H中断,CPU进入硬盘引导扇区(boot sector)将MBR加载到内存并执行。MBR存放着一段引导代码Boot Loader。对于使用GRUB作为引导程序的Linux来说,比如CentOS7,这段Boot Loader代码就是GRUB2

MBR(Master Boot Record)的结构:

这里分区表的使用有如下约定:
① 一块硬盘最多4个主分区(Primary Partition)
② 一块硬盘最多1个扩展分区(Extented Partition)
③ 逻辑分区(Logical Partion)的分区信息是写在扩展分区上
④ 磁盘编号1~4是留给主分区,5以后的编号留给逻辑分区

所以磁盘以/sda为例,/sda1,/sda2,/sda3,/sda4指主分区,可以引导操作系统。/sda5,/sda6,… 为逻辑分区,不能引导操作系统。

涉及到的命令:

# 查看分区信息
fdisk -l
fdisk /dev/sda
# 查看分区信息和挂载点
lsblk
df -h
mount
# 查看分区的UUID
blkid
# 查看磁盘使用情况
du -sh

注意:

ll /dev/sda1
brw-rw---- 1 root disk 8, 1 Feb 15 21:49 /dev/sda1
|-->Device type        |  |
                       |  |-->Minor number
                       |-->Major number

Device type,Major number和Minor number三个参数唯一确定一个设备。
如果:

mknod /dev/test b 8 1
此时/dev/test就变成了/dev/sda1
2. 通过GRUB引导系统

CentOS7开始使用GRUB2(GRand Unified BootLoader,Version 2)。运行MBR的Boot Loader实际就是启动GRUB程序。此时GRUB会显示一个菜单(boot splash screen),让用户选择:

  • Image镜像选择——确定加载的内核
  • 选择设置向内核Kernel传递的参数

grub程序可以通过类似如下的命令形式

grub2-install /dev/sda

被安装到引导扇区(boot sector)。如果有/boot分区也可以直接写到/boot分区上(/boot也在boot sector上)。

grub2-install --boot-directory=/boot /dev/sda

如此,grub程序文件将被写到/boot/grub目录下。

在CentOS7中Grub2的配置文件是:/boot/grub2/grub.cfg
配置文件中的几点说明:(详细可参考 https://blog.csdn.net/changexhao/article/details/78467276 )
① timeout指引导菜单的等待时间(单位秒,0表示不允许选择菜单项,直接进入引导)
② 盘符命名规则

磁盘从"0"开始计数,分区从"1"开始计数
(fd0)          第一软盘
(hd0)          第一硬盘(大多数U盘与USB接口的移动硬盘以及SD卡也都被当作硬盘看待)
(hd1,1)        第二硬盘的第一分区(通用于MBR与GPT分区)
(hd0,msdos1)   第一硬盘的第一分区,也就是传统的DOS分区表
(hd1,msdos5)   第二硬盘的第五分区,也就是第一个逻辑分区
(hd0,gpt1)     第一硬盘的第一GPT分区
(cd)           启动光盘(仅在从光盘启动GRUB时可用)
(cd0)          第一光盘

/dev/sda1 对应 (hd0,msdos1), 其中0对应a,1对应1。

③ 常用命令

set 设置变量
insmod 插入模块
search 查找设备
linux16 以16位方式加载内核镜像
initrd16 以16位方式加载initrd

grub2在/boot/grub2/grub.cfg配置文件中用insmod加载的模块在/boot/grub2/i386-pc/下。

④ 内核参数

rhgb 即Redhat Graphic Booting,表示以图形化方式启动(显示彩色进度条)
quiet 不提示用户服务加载失败的信息。只显示OK或FAILED。
net.ifnames=0 biosdevname=0 自定义网卡名称

通过向内核传递参数net.ifnames=0 biosdevname=0可以修改网卡名称。具体可以:

vim /etc/sysconfig/grub
修改配置添加内核参数
GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos_com/root rd.lvm.lv=centos_com/swap rhgb quiet net.ifnames=0 biosdevname=0"

grub2-mkconfig -o /boot/grub2/grub.cfg
mv /etc/sysconfig/network-scripts/ifcfg-ens33 /etc/sysconfig/network-scripts/ifcfg-eth0
sed -i '/DEVICE=/c\DEVICE=eth0' /etc/sysconfig/network-scripts/ifcfg-eth0
reboot
3. 加载内核Kernel与initrd

Grub程序将通过菜单的选择结果,决定加载哪个内核Kernel和initrd(Initial RAM disk image)。这里要注意:
① CentOS7使用initramfs来替代initrd
② 内核文件名以vmlinuz开头,一般放在/boot/下,可以有多个,以供grub选择加载。
③ initrd镜像文件名以initramfs开头,.img结尾,也可以有多个。
④ vmlinuz和initramfs文件配对出现,不单独使用。

Grub加载vmlinuz文件来将Linux kernel加载到内存;Grub加载initramfs镜像文件来将一个微型Linux文件系统加载入内存。这个微型的Linux文件系统包含必要的命令和模块(设备驱动程序)。

# /boot/grub2/grub.cfg
linux16 /vmlinuz-3.10.0-1062.el7.x86_64 root=/dev/mapper/centos_com-root ro crashkernel=auto spectre_v2=retpoline rd.lvm.lv=c
initrd16 /initramfs-3.10.0-1062.el7.x86_64.img

/vmlinuz-xxx和/initramfs-xxx文件的/表示/boot。
root=/dev/mapper/centos_com-root指明根分区/ ,且挂载的根分区是ro只读的。即此时内核访问的/分区还是只读的。

initramfs内部是什么呢?

# 文件类型
file initrd.img 
initrd.img: XZ compressed data
或者
file /boot/initramfs-3.10.0-1062.el7.x86_64.img 
/boot/initramfs-3.10.0-1062.el7.x86_64.img: gzip compressed data, from Unix, last modified: Fri Feb  7 17:31:27 2020, max compression

# 在当前目录下生成解压结果
xz -dc initrd.img | cpio -id
或者
zcat initramfs-3.10.0-1062.el7.x86_64.img | cpio -imd

# 看看解压结果吧
lrwxrwxrwx  1 root root    7 Feb 15 17:00 bin -> usr/bin
drwxr-xr-x  2 root root   45 Feb 15 17:00 dev
drwxr-xr-x 12 root root 4096 Feb 15 17:00 etc
lrwxrwxrwx  1 root root   23 Feb 15 17:00 init -> usr/lib/systemd/systemd
lrwxrwxrwx  1 root root    7 Feb 15 17:00 lib -> usr/lib
lrwxrwxrwx  1 root root    9 Feb 15 17:00 lib64 -> usr/lib64
drwxr-xr-x  2 root root    6 Feb  7 17:31 proc
drwxr-xr-x  2 root root    6 Feb  7 17:31 root
drwxr-xr-x  2 root root    6 Feb  7 17:31 run
lrwxrwxrwx  1 root root    8 Feb 15 17:00 sbin -> usr/sbin
-rwxr-xr-x  1 root root 3117 Aug  9  2019 shutdown
drwxr-xr-x  2 root root    6 Feb  7 17:31 sys
drwxr-xr-x  2 root root    6 Feb  7 17:31 sysroot
drwxr-xr-x  2 root root    6 Feb  7 17:31 tmp
drwxr-xr-x  7 root root   66 Feb 15 17:00 usr
drwxr-xr-x  2 root root   29 Feb 15 17:00 var

其中常见的命令和.so文件都有了。最关键的是还有systemd。init已经符号链接到了systemd,相应的pid是1。

initramfs可以解决一个“先有鸡还是先有蛋的”问题,即内核需要挂载根分区(比如xfs文件系统),而xfs的驱动程序文件又在/分区。要想访问/分区,又需要xfs模块的驱动。此时initramfs可以在内存中直接提供一个上述的微型文件系统,在这个内存文件系统中存放了xfs的驱动程序模块,可以提供给内核来访问根分区。
initramfs提供的文件系统中存放的xfs驱动文件如下:

ll usr/lib/modules/3.10.0-1062.el7.x86_64/kernel/fs/xfs/
total 328
-rw-r--r-- 1 root root 332132 Aug  8  2019 xfs.ko.xz

initrd的制作方法:

# raid1的驱动已存在于系统,在initrd文件系统中添加raid1驱动模块。
mkinitrd --with=raid1 /boot/initrd-$(uname -r).img $(uname -r)
# 使用系统已有的驱动模块新建initrd镜像文件
mkinitrd /boot/initrd-$(uname -r).img $(uname -r)

initramfs的制作方法:
详见:https://blog.csdn.net/pengrui18/article/details/14389233

4. systemd启动

grub加载Kernel,Kernel启动init进程,而init在initramfs中符号链接到systemd(也意味着systemd替代了init),最终实际上启动的是systemd,管理权限也交给了它。

传统的init进程此时会读取/etc/inittab(这是init读取的第一个配置文件,最后一个文件是/etc/rc.d/rc.local)。
然后运行如下内容:

  1. initial run level
  2. system initialization scripts
  3. run level specific script directories
  4. trap certain key sequences
  5. define UPS power fail/restore scripts
  6. spawn gettys on virtual consoles
  7. initialize X in run level 5

run level:
0 halt
1 single
2 multiuser without network
3 full multiuser mode
4 unused
5 X11
6 reboot
使用 init n(1, 2, …, 5) 可以切换到相应的run level。
使用rc(running control)方式来管理上述0~6共7个run level。通过脚本完成管理,各脚本是串行的执行方式。
/etc/rc.d/rc.local执行完毕后系统出现登陆界面。

# pid为1,和传统的init进程一样。
[root@com ~]# pidof systemd
1

启动systemd使 Linux 系统进入可操作状态,并能够执行用户功能性任务。

systemd可以管理运行中的 Linux 主机的许多方面,包括挂载文件系统(grub之后的第二次挂载,此时挂载的根分区是可读写的),以及开启和管理 Linux 主机的系统服务等。

systemd 借助其配置文件 /etc/systemd/system/default.target 决定 Linux 系统应该启动达到哪个状态(或目标态target)。default.target 是一个真实的 target 文件的符号链接。对于桌面系统,其链接到 graphical.target,该文件相当于旧式 systemV init 方式的 run level 5。对于一个服务器操作系统来说,default.target 更多是默认链接到 multi-user.target, 相当于 systemV 系统的 run level 3。emergency.target 相当于单用户模式。所有的目标态target和服务service均是 systemd 的单元unit。

以下是systemd的完整启动过程:
可以通过命令 man bootup 查看

           local-fs-pre.target
                    |
                    v
           (various mounts and   (various swap   (various cryptsetup
            fsck services...)     devices...)        devices...)       (various low-level   (various low-level
                    |                  |                  |             services: udevd,     API VFS mounts:
                    v                  v                  v             tmpfiles, random     mqueue, configfs,
             local-fs.target      swap.target     cryptsetup.target    seed, sysctl, ...)      debugfs, ...)
                    |                  |                  |                    |                    |
                    \__________________|_________________ | ___________________|____________________/
                                                         \|/
                                                          v
                                                   sysinit.target
                                                          |
                     ____________________________________/|\________________________________________
                    /                  |                  |                    |                    \
                    |                  |                  |                    |                    |
                    v                  v                  |                    v                    v
                (various           (various               |                (various          rescue.service
               timers...)          paths...)              |               sockets...)               |
                    |                  |                  |                    |                    v
                    v                  v                  |                    v              rescue.target
              timers.target      paths.target             |             sockets.target
                    |                  |                  |                    |
                    v                  \_________________ | ___________________/
                                                         \|/
                                                          v
                                                    basic.target
                                                          |
                     ____________________________________/|                                 emergency.service
                    /                  |                  |                                         |
                    |                  |                  |                                         v
                    v                  v                  v                                 emergency.target
                display-        (various system    (various system
            manager.service         services           services)
                    |             required for            |
                    |            graphical UIs)           v
                    |                  |           multi-user.target
                    |                  |                  |
                    \_________________ | _________________/
                                      \|/
                                       v
                             graphical.target

至此,整个启动过程结束。系统出现登陆界面。

5. 分析systemd的启动过程便于优化
  • 为获取关于启动速度的简短信息,使用下面的命令:
systemd-analyze
  • 根据初始化所用的时间打印所有正在运行的单元的列表。
    不会显示服务类型为简单(Type=simple)的服务,因为 systemd 认为这些服务应是立即启动的。因此,无法测量初始化的延迟。
systemd-analyze blame
  • 打印关键的服务单元的树形结构
systemd-analyze critical-chain
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值