CentOS 启动流程

 

Linux 系统的启动是不需要人为参与和控制的,只要按下电源,系统就会按照设定好的方式进行启动。不过,了解系统的启动有助于我们在系统出现问题时能够快速地修复 Linux 系统。


 

目前,CentOS 6.x 的启动流程经历以下几步:

  1. 服务器加电,加载 BIOS 信息,BIOS 进行系统检测。依照 BIOS 设定,找到第一个可以启动的设备(一般是硬盘)。
  2. 读取第一个启动设备的 MBR (主引导记录),加载 MBR 中的 Boot Loader(启动引导程序,最为常见的是 GRUB)。
  3. 依据 Boot Loader 的设置加载内核,内核会再进行一遍系统检测。系统一般会采用内核检测硬件的信息,而不一定采用 BIOS 的自检信息。内核在检测硬件的同时,还会通过加载动态模块的形式加载硬件的驱动。
  4. 内核启动系统的第一个进程,也就是 /sbin/init。
  5. 由 /sbin/init 进程调用 /etc/init/rcS.conf 配置文件,通过这个配置文件调用 /etc/rc.d/rc.sysinit 和 /etc/inittab 配置文件。 前者是用来进行系统初始化的,主要用于配置计算机的初始环境。后者是用来确定系统的默认运行级别。
  6. 确定默认运行级别后,调用 /etc/init/rc.conf 配置文件,然后通过 /etc/init/rc.conf 配置文件调用并执行 /etc/rc.d/rc 脚本,并传入运行级别参数。
  7. /etc/rc.d/rc 确定传入的运行级别,然后运行相应的运行级别目录 /etc/rc[0-6].d/ 中的脚本。
  8. /etc/rc[0-6].d/ 目录中的脚本依据设定好的优先级依次启动和关闭。
  9. 最后执行 /etc/rc.d/rc.local 中的程序。
  10. 如果是字符界面启动,就可以看到登录界面了。如果是图形界面启动,就会调用相应的 X Window 接口。

总的来说,Linux 系统的启动,要经历BIOS自检 -> 启动 GRUB -> 加载内核 -> 执行第一个进程 -> 配置系统初始环境.

 

BIOS自检

前面提到,服务器通电后,会直接进入 BIOS,BIOS 全称 Basic Input/Output System,中文可译为基本输入/输出系统。

简单地理解 BIOS,它就是固化在主板上一个 ROM(只读存储器)芯片上的程序,主要保存计算机的基本输入/输出信息、系统设置信息、开机自检程和系统自启动程序,用来为计算机提供最底层和最直接的硬件设置与控制。

也就是说,BIOS 是硬件与软件之间的接口,而且是非常基本的接口,BIOS 提供了一组基本的操作系统使用的指令,系统启动的成功与否,依赖于 BIOS。

BIOS 的初始化主要完成以下 3 项工作:

  1. 第一次检查计算机硬件和外围设备,例如 CPU、内存、风扇灯。当 BIOS 一启动,就会做一个自我检测的工作,整个自检过程也被称为 POST(Power On Self Test)自检。
  2. 如果自检没有问题,BIOS 开始对硬件进行初始化,并规定当前可启动设备的先后顺序,选择由那个设备来开机。
  3. 选择好开启设备后,就会从该设备的 MBR(主引导目录)中读取 Boot Loader(启动引导程序)并执行。

当 MBR 被加载到 RAM 之后,BIOS 就会将控制权交给 MBR,进入系统引导的第二阶段。

 

启动GRUB

MBR 中最主要的功能就是存储 Boot Loader ( 启动引导程序 )。启动引导程序用于引导操作系统启动,Linux 系统中默认使用的启动引导程序是 GRUB。


关于 MBR 结构,作如下记录:

MBR 也就是主引导记录,位于硬盘的 0 磁道、0 柱面、1 扇区中,主要记录了启动引导程序和磁盘的分区表。我们通过图 1 来看看 MBR 的结构。


CentOS 启动流程_第1张图片
图  1 MBR的结构

MBR 共占用了一个扇区,也就是 512 Byte。其中 446 Byte 安装了启动引导程序,其后 64 Byte 描述分区表,最后的 2 Byte 是结束标记。我们已经知道,每块硬盘只能划分 4 个主分区,原因就是在 MBR 中描述分区表的空间只有 64 Byte。其中每个分区必须占用 16 Byte,那么 64 Byte 就只能划分 4 个主分区。每个分区的 16 字节的规划如表 1 所示。

表 1 分区表内容
存储字节 数据内容及含义
第 1 字节 引导标志
第 2 字节 本分区的起始磁道号
第 3 字节 本分区的起始扇区号
第 4 字节 本分区的起始柱面号
第 5 字节 分区类型,可以识别主分区和扩展分区
第 6 字节 本分区的结束磁道号
第 7 字节 本分区的结束扇区号
第 8 字节 本分区的结束柱面号
第 9~12 字节 本分区之前已经占用的扇区数
第 13~16 字节 本分区的总扇区数

BIOS 的作用就是自检,然后从 MBR 中读取出启动引导程序。那么,启动引导程序最主要的作用就是加载操作系统的内核。当然,每种操作系统的启动引导程序都是不同的。

每种操作系统的文件格式不同,因此,每种操作系统的启动引导程序也不一样。不同的操作系统只有使用自己的启动引导程序才能加载自己的内核。如果我的服务器上只安装了一个操作系统,那么这个操作系统的启动引导程序就会安装在 MBR 中。BIOS 调用 MBR 时读取出启动引导程序,就可以加载内核了。

但是在有些时候,我的服务器中安装了多个操作系统,而 MBR 只有一 个,那么在 MBR 中到底安装哪个操作系统的启动引导程序呢?

很明显,一个 MBR 是不够用的。每块硬盘只能有一个 MBR 是不能更改的,所以不可能増加 MBR 的数量。系统只能在每个文件系统(可以看成分区)中单独划分出一个扇区,称作引导扇区(Boot Sector)。每个分区的引导扇区中也能安装启动引导程序,也就是说,在 MBR 和每个单独分区的引导扇区中都可以安装启动引导程序。这样多个操作系统才能安装在同一台服务器中(每个操作系统要安装在不同的分区中),而且每个操作系统都是可以启动的。

还有一个问题,BIOS 只能找到 MBR 中的启动引导程序,而找不到在分区的引导扇区中的启动引导程序。那么,要想完成多系统启动,我们的方法是増加启动引导程序的功能,让安装到 MBR 中的启动引导程序(GRUB)可以调用在分区的引导扇区中的其他启动引导程序。

因此,启动引导程序拥有以下功能:

  1. 加载操作系统的内核。这是启动引导程序最主要的功能。
  2. 拥有一个可以让用户选择的菜单,来选择到底启动哪个系统。大家如果在服务器上安装过双 Windows 系统,就应该见过类似的选择菜单,不过这个选择菜单是由 Windows 的启动引导程序提供的,而不是 GRUB。
  3. 可以调用其他的启动引导程序,这是多系统启动的关键。不过需要注意的是,Windows 的启动引导程序不能调用 Linux 的启动引导程序,所以我们一般建议先安装 Windows,后安装 Linux,是为了将 Linux 的启动引导程序安装到 MBR 中,覆盖 Windows 的启动引导程序。

当然,这个安装顺序不是绝对的,就算最后安装了 Windows,我们也可以通过手工再安装 GRUB 的方法,来保证 MBR 中安装的还是 Linux 的启动引导程序。

图2 展示了启动引导程序的作用。


CentOS 启动流程_第2张图片
图 2 启动引导程序的作用

 

加载内核

GRUB 加载了内核之后,内核首先会再进行二次系统的自检,而不一定使用 BIOS 检测的硬件信息。这时内核终于开始替代 BIOS 接管 Linux 的启动过程了。

内核完成再次系统自检之后,开始采用动态的方式加载每个硬件的模块,这个动态模块大家可以想象成硬件的驱动(默认 Linux 硬件的驱动是不需要手工安装的,如果是重要的功能,则会直接编译到内核当中;如果是非重要的功能,比如硬件驱动会编译为模块,则在需要时由内核调用。不过,如果没有被内核硬件,要想驱动,就需要手工安装个硬件的硬块了)。

那么,Linux 的内核到底放在了哪里呢?当然是 /boot 的启动目录中了,我们来看看这个目录下的内容吧。

[root@localhost ~]#ls /boot/
config-2.6.32-279.el6.i686
#内核的配置文件,内核编译时选择的功能与模块
efi
#可扩展固件接口,为英特尔为全新PC固件的体系结构、接口和服务提出的建议标准
grub
#启动引导程GRUB的数据目录
initramfe-2.6.32-279.el6.i686.img
#虚拟文件系统(CentOS 6.x 中用initramfs替代了initrd,但功能是一样的)
lost+found
#boot分区的备份目录
symvers-2_6.32-279.el6.i686.gz
#模块符号信息
System.map-2.6.32-279.el6.i686
#内核功能和内存地址的对应列表
vmlinuz-2.6.32-279.el6.i686
#用于启动的Linux内核。这个文件是一个压缩的内核镜像

我们已经知道,Linux 会把不重要的功能编译成内核模块,在需要时再调用,从而保证了内核不会过大。在多数 Linux 中,都会把硬件的驱动程序编译为模块, 这些模块保存在 /lib/modules 目录中。常见的 USB、SATA 和 SCSI 等硬盘设备的驱动,还有一些特殊的文件系统(如 LVM、RAID 等)的驱动,都是以模块的方式来保存的。

如果 Linux 安装在 IDE 硬盘之上,并且采用的是默认的 ext3/4 文件系统,那么内核启动后加载根分区和模块的加载都没有什么问题,系统会顺利启动。但是,如果 Linux 安装在 SCSI 硬盘之上,或者采用的是 LVM 文件系统,那么内核(内核载入内存是启动引导程序 GRUB 调用的,并不存在硬盘驱动不识别的问题)在加载根目录之前是需要加载 SCSI 硬盘或 LVM 文件系统的驱动的。

SCSI 硬盘和 LVM 文件系统的驱动都放在硬盘的 /lib/modules 目录中,既然内核没有办法识别 SCSI 硬盘或 LVM 文件系统,那怎么可能读取 /lib/modules 目录中的驱动呢?Linux 给出的解决办法是使用 initramfs 这个虚拟文件系统来处理这个问题。

CentOS 6.x 中使用 initramfs 虚拟文件系统取代了 CentOS 5.x 中的 initrd RAM Disk。它们的作用类似,可以通过启动引导程序加载到内存中,然后会解压缩并在内存中仿真成一个根目录,并且这个仿真的文件系统能够提供一个可执行程序,通过该程序来加载启动过程中所需的内核模块,比如 USB、SATA. SCSI 硬盘的驱动和 LVM、RAID 文件系统的驱动。

也就是说,通过 initramfs 虚拟文件系统在内存中模拟出一个根目录,然后在这个模拟根目录中加载 SCSI 等硬件的驱动,就可以加载真正的根目录了,之后才能调用 Linux 的第一个进程 /sbin/init。

Initramfs 虚拟文件系统主要有以下优点:

  • initramfs 随着其中数据的増减自动増减容量。
  • 在 initramfs 和页面缓存之间没有重复数据。
  • initramfs 重复利用了 Linux caching 的代码,因此几乎没有増加内核尺寸,而 caching 的代码已经经过良好测试,所以 initramfs 的代码质量也有保证。
  • 不需要额外的文件系统驱动。

其实只需要知道 initramfs 是为了在内核中建立一个模拟根目录,这个模拟根目录是为了可以调用 USB、SATA、SCSI、LVM、RAID 等硬盘接口或文件系统的驱动模块,加载了驱动模块后才可以加载真正的系统根目录。我们可以通过示意图 3来表示这个过程。


CentOS 启动流程_第3张图片
图 3 内核启动流程


那么既然 initramfs 是一个仿真根目录,那么我们是否可以看看这个仿真根目录中到底是什么样子的呢?当然可以,命令如下:

[root@localhost ~]# mkdir /tmp/initramfs
#建立测试目录
[root@localhost ~]# cp/boot/initramfs-2.6.32-279.el6.i686.img /tmp/initramfs/
#复制initramfs文件
[root@localhost ~]# cd /tmp/initramfs/
[root@localhost initramfs]# file
initramfs-2.6.32-279.el6.i686.img
initramfe-2.6.32-279.el6.i686.img:gzip compressed
data,from Unix,last modified:
Wed Apr 10 21:49:34 2013, max compression
#查看文件类型,发现这个文件是一个使用gzip命令打包的压缩包
[root@localhost initramfs]# mv initramfs-2.6.32-279.el6.i686.imginitramfs-2.6.32-279.el6.i686.img.gz
#修改文件的扩展名为.gz
[root@localhost initramfs]# gunzip
initramfs-2.6.32-279.el6.i686.img.gz
#解压缩
[root@localhost initramfs]# ls
initramfs-2.6.32-279.el6.i686.img
[root@localhost initramfs]# file
initramfs-2.6.32-279.el6.i686.img
initramfe-2.6.32-279.el6.i686.img: ASCII cpio archive (SVR4withnoCRC)
#查看文件类型,使用cpio命令的压缩文件
[root@localhost initramfs]# cpio -ivcdu 

 

启动 init 进程

在内核加载完毕,并完成硬件检测与驱动程序加载后,此时主机硬件已经准备完毕,内核会主动呼叫第一个进程,也就是 /sbin/init,此配置文件最主要的功能就是准备软件执行的环境,包括系统的主机名、网络设定、语言、文件系统格式及其他服务的启动等。

这里和 CentOS 5.x 系统相比也有较大变化。在 CentOS 5.x 系统中,主要通过 init 进程的配置文件 /etc/inittab 来设定系统,并启动 Linux。但是在 CentOS 6.x 系统中,由于用 Upstart 启动服务来替换以前的 init,所以在 /etc/inittab 配置文件中只能定义系统的默认运行级别,而其他的功能是靠 /etc/init/ 目录中的其他配置文件实现的。

大家可以把 /etc/init/ 目录中的配置文件看成以前 /etc/inittab 这个文件功能的分拆。

前面提到,由 /sbin/init 进程可通过 /etc/init/rcS.conf 配置文件,分别找到 /etc/rc.d/rc.sysinit 配置文件和 /etc/inittab 配置文件,前者用于初始化系统,配置计算机的初始环境;后者用于确定系统的默认运行级别。

接下来,先介绍 /etc/rc.d/rc.sysinit 配置文件。如果我们使用 Vim 查看 /etc/rc.d/rc.sysinit 配置文件,就会发现这个这个配置文件主要进行了以下几项工作:

  • 获得网络环境和主机类型;
  • 测试设备:除了挂载内存设备 /proc 之外,还会主动侦测系统上是否具有 usb 设备,如果有,则会主动加载 usb 的驱动程序,并尝试挂载 usb 文件系统;
  • 开机启动画面 Plymouth(代替了以往的 RHGB);
  • 判断是否启用 SELinux;
  • 显示开机过程中的欢迎画面;
  • 初始化硬件;
  • 用户自定义模块的加载,用户可以在 /etc/sysconfig/modules/*.modules 加入自订的模块,则此时会被加载到系统当中;
  • 配置内核的参数,系统会主动去读取 /etc/sysctl.conf 这个文件的配置参数,使内核的功能成为我们想要的样子。
  • 设置主机名。
  • 同步存储器。
  • 设备映射器及相关的初始化。
  • 初始化软件磁盘阵列 (RAID)。
  • 初始化 LVM 的文件系统功能。
  • 检验磁盘文件系统 (fsck)。
  • 设置磁盘配额 (quota)。
  • 重新以可读写模式挂载系统磁盘。
  • 更新 quota (非必要)。
  • 启动系统虚拟随机数生成器。
  • 配置机器(非必要)。
  • 清除开机过程中的临时文件。
  • 创建 ICE 目录。
  • 启动交换分区(swap)。
  • 将开机信息写入 /var/log/dmesg 文件中。


在以上过程中,比较值得注意的是自定模块的加载。在 CentOS 中,如果我们想要加载核心模块的话,就可以将整个模块写入到 /etc/sysconfig/modules/*.modules 中。当然,此过程并不是必须的,通常我们的默认模块已经够用,除非对硬件太新,不得不自己加载模块,否则无需刻意添加任何模块。

在 /etc/rc[06].d/ 目录中的程序启动之后,系统的启动就已经完成。不过,我们总有一些程序是需要在系统启动之后随着系统一起启动的。这时我们并不需要自己把需要启动的服务链接到 /etc/rc3.d/ 目录中,因为系统给我们准备了 /etc/rc.d/rc.local 配置文件。

这个配置文件会在用户登陆之前读取,这个文件中写入了什么命令,在每次系统启动时都会执行一次。也就是说,如果有任何需要在系统启动时运行的工作,则只需写入 /etc/rc.d/rc.local 配置文件即可。这个文件的内容如下:

[root@localhost ~]# ll /etc/rc.local
Irwxrwxrwx. 1 root root 13 4月10 21:46 /etc/rc.local -> rc.d/rc.local
#有一个链接文件,两个文件修改哪一个都可以
[root@localhost ~]#vi /etc/rc.d/rc.local
#!/bin/sh
#
#This script will be executed *after* all the other init scripts.
#You can put your own initialization stuff in here if you don't
#want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
#默认会touch这个文件,每次系统启动时都会touch这个文件,这个文件的修改时间就是系统的启动时间
/etc/rc.d/init.d/httpd start
#如果写入RPM包安装的apache服务的启动命令,apache服务就会在开机时自动启动

 

总结

Linux 的

我们把启动流程图补充完整,如图 1 所示。


CentOS 启动流程_第4张图片
图 1 Linux启动流程


系统的启动过程就是这样的,最终我们就能登录字符界面的 Linux 了。不过,如果需要启动图形界面的 Linux,则还需要调用 X Window 接口。

在启动过程中还有一个配置文件会生效,就是 /etc/init/start-ttys.conf,这个文件主要定义了 Linux 支持的 1~6 个本地终端(tty[1-6])。如果在本机,则可以使用快捷键 Alt+F1~F6 来切换这 6 个本地终端;如果安装并启动了图形界面,则可以使用快捷键 Ctrl+Alt+F7 来切换图形终端。

至此,字符界面的启动过程就介绍完了。是不是非常复杂?如果你是初学者,则只需了解,不需要彻底掌握。但是掌握了 Linux 系统的启动过程,会更加了解 Linux 的结构。当然,如果你非常自信,则可以尝试安装 gentoo Linux 这个版本,因为这个 Linux 版本到目前为止还是纯源码安装的,如果能够安装成功,就会对 Linux 系统的结构及启动过程有更深入的理解。

 


关于系统默认运行级别,作如下记录:

可以看到,/etc/rc.d/rc.sysinit 配置文件已经将基本的系统配置数据都写好了,我们可以查询 /var/log/dmesg 文件或使用 dmesg 命令查看系统在启动时到底发生了什么。当然,我们也可以通过这个命令来看看 Linux 服务器的硬件信息。

在 CentOS 6.x 中,/etc/inittab 配置文件只能用来设置系统的默认运行级别。

那么,什么是运行级别呢?其实 Linux 是通过运行级别来确定系统启动时到底启动哪些服务的。Linux 默认有 7 个运行级别,具体如表 1 所示。
 

表 1 运行级别
运行级别 含 义
0 关机
1 单用户模式,可以想象为 Windows 的安全模式,主要用于系统修复
2 不完全的命令行模式,不含 NFS 服务
3 完全的命令行模式,就是标准字符界面
4 系统保留
5 图形模式
6 重新启动


在 Linux 系统中可以使用 runlevel 命令来查看系统的运行级别,命令如下:

[root@localhost ~]# runlevel
N 3
#N代表在进入这个级别前,上一个级别是什么;3代表当前级别

在这个命令的结果中,"N 3"中的N代表在进入这个级别前,上一个级别是什么;3 代表当前级别。"N" 就是 None 的意思,也就是说,系统是开机直接进入 3 运行级别的,没有上一个运行级别。那如果从图形界面切换到字符界面,再查看运行级别,就应该是这样的:

[root@localhost ~]# runlevel
5 3
#代表由5级别进入3级别

那么,可以手工改变当前的运行级别吗?当然可以了,只需使用 init 命令(注意这不是 init 进程)即可,命令如下:

[root@localhost ~]# init 5
#进入图形界面,当然要已经安装了图形界面才可以
[root@localhost ~]# init 0
#关机
[root@localhost ~]# init 6
#重新启动

不过要注意,使用 init 命令关机和重启并不是太安全,容易造成数据丟失。所以推荐大家使用 shutdown 命令进行关机和重启。

知道了运行级别的作用,我们回到系统启动过程中来。/etc/inittab 配置文件的功能就是确定系统的默认运行级别,也就是系统开机后会进入那个运行级别。此文件的内容如下:

[root@localhost ~]#vim /etc/inittab
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# System initialization is started by /etc/init/rcS.conf
#系统会先调用/etc/init/rcS.conf
# Individual runlevels are started by /etc/init/rc.conf
#在调用/etc/init/rc.conf,在不同的运行级别启动不同的服务
# Ctrl-Alt-Delete is handled by/etc/init/control-alt-delete.conf
#通过这个配置文件判断Ctri+Alt+Delete热启动键是否可用
# Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
# with configuration in /etc/sysconfig/init.
#判断系统可以启动的本地终端数量及终端的基本设置(如颜色)
# For information on how to write upstart event handlers, or how
# upstart works, see init(5), init(8), and initctl(8).
#
# Default runlevel. The runlevels used 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)
#很眼熟吧,就是刚刚的 0~6运行级别的说明
id:3:initdefault:
#这就是系统的默认运行级别,也就是系统开机后直接进入哪个运行级别

注意,这里的默认运行级别只能写 3 或 5,其他的级别要么是关机重启,要么是保留或单用户,都不能作为系统默认运行级别。


 

你可能感兴趣的:(Linux)