Linxu系统的启动过程

Linxu系统的启动过程

简单描述.jpg

启动流程

1、引导Linux启动是从BIOS中的地址0xFFFF0处开始的,BIOS由两部分组成:POST代码和运行时服务,运行时服务是为操作系统提供一些接口,如温度检测等。

    • BIOS的第一个步骤是加电自检(POST),完成对硬件的的检测,如某些硬件出现错误无法通过检测就导致系统无法启动,POST完成之后将被清出内存;

    • BIOS的第二个步骤是进行设备的枚举和初始化,按CMOS的设置搜索处于活动状态并且可引导的设备(floppy、CD-ROM、USB、Disk、NFS),加载主引导记录(MBR),到内存。此时BIOS将控制权交给Boot Loader

2、MBR的前 446 个字节是主引导加载程序(Boot Loader),其中包含可执行代码和错误消息文本。接下来的 64 个字节是分区表,其中包含 4 个分区的记录(每个记录16 bytes)。MBR 以两个特殊数字(0xAA55)结束。这个数字会用来进行 MBR 的有效性检查。

    • Boot Loader就是stage1,通过内置的地址引导了stage1_5 的引导加载程序加载/boot分区,进而加载stage2。MBR中的Boot Loader备份在了 /boot/grub/stage1 中 

    • 比较.jpg

    • stage1_5在/boot/grub目录,用于识别内核所在分区的文件系统类型,是Boot Loader所处的 stage1 加载 stage2 的过渡,在这之后才能进入Grub引导程序。

3、Grub引导程序处于stage2,通过读取 /etc/grub.conf 文件,显示出内核列表,指定了内核镜像和 initrd 所在的分区为root,设定内核参数,并加载vmlinuz和initramfs这两个文件到内存中。在这一阶段可以编辑启动项目如指定根分区root,内核kernel,initrd镜像等;也可以进入grub command line手动写启动信息。


事实上,GRUB(GRand Unified Bootloader)管理开机启动的过程分成了三个阶段stage1/stage1.5/stage2。其中stage1主要负责BIOS和GRUB之间的交接。这部分才是真正放在MBR中的bootloader。而后stage1.5是连接stage1和stage2之间的通道,起着过渡的作用。最后才是GRUB中真正核心的部分stage2,它可以让用户以选项的方式将操作系统加载、修改选项和内核参数。


4、当内核映像被加载到内存中,并且stage2 的引导加载程序释放控制权之后,内核阶段就开始了,内核在完成自身的初始化之后进行探测可识别的所有硬件设备,由于内核中只包含了少量的硬件驱动,此时会借助内存中的initrd根文件系统加载相关驱动程序。当内核具备访问根文件系统功能时,initrd根文件系统将被卸载,并挂载真正的根文件系统。这就是内核的初始化过程,系统已经脱离了 /boot 分区,独立存活在内存中。

    • vmlinuz-xxx内核镜像是一个 zImage(压缩映像,小于 512KB)或一个 bzImage(较大的压缩映像,大于 512KB),它是使用 zlib 进行压缩过的内核文件

    • initramfs-xxx.img是由stage2 引导加载程序加载到内存中的,它会被复制到 RAM 中并挂载到系统上。这个 initrd 会作为 RAM 中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导。initrd文件包括可加载模块的驱动程序,为内核提供可访问磁盘和磁盘上的文件系统的接口,并为其他硬件提供了驱动程序。由于根文件系统是磁盘上的一个文件系统,因此内核通过initrd取得根分区的访问,并挂载真正的根文件系统。这是一个解包的initramfs镜像文件:

initrd.jpg

    • 内核非常小,rpm -ql kernel看到大部分驱动模块都在安装内核时放在了/lib/modules/version/目录下,只有编译内核过程中被选择的模块才会成为内核镜像的一部分,还有一部分驱动模块存放在initfd镜像中,这些驱动模块确保了Linux内核可以在众多的架构上运行,并且兼容绝大多数硬件平台。

5、内核初始化的最后一步就是启动 init 进程。在init 以守护进程方式存在,是所有其他进程的祖先(PID=1),init 进程非常独特,能够完成其他进程无法完成的任务。

    • CentOS 5中使用 sysvinit 初始化系统:sysvinit 就是 system V 风格的 init 系统,顾名思义,就是源于 System V 系列 UNIX

    • init 通过读取 ‘/etc/inittab’ 文件完成系统初始化的过程:

    • . 系统选择进入 runlevel

      . 运行系统初始化脚本,即/etc/rc.d/rc.sysinit

      . 运行指定运行级别对应的目录下的脚本,即/etc/rc.d/rc#.d/目录下的服务脚本

      . 捕获组合键的定义

      . 定义电源 fail/restore 脚本

      . 启动 getty 和虚拟控制台

    • inittab文件 

    • 字段定义格式及含义 id:runlevels:action:process 

      . id:标识符 

      . runlevels:在哪个级别运行此行 

      . action:在什么情况下执行此行 

      . process:要运行程序 

      [action] 

      . initdefault:设定默认运行级别 

      . sysinit:系统初始化 

      . wait:等待级别切换至此级别时执行 

      . respawn:一旦程序终止,会重新启动

    • 选择runlevel :Sysvinit 读取 ‘/etc/inittab’ 文件中是否含有 ‘initdefault’ 项,有则init 将启动默认运行的模式。如果没有默认的运行模式,将进入系统控制台,手动决定进入何种运行模式。

      • who -r 与 runlevel #查看当前的runlevel

      • runlevel通常会 7 种模式,即runlevel 0 ~ 6 。 
        通常: 
        # 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)

  • /etc/rc.d/rc.sysinit 

    • 运行 rc.sysinit 以便执行一些重要的系统初始化任务。在RHEL 5中rc.sysinit 主要完成以下这些工作: 

    • 激活 udev 和 selinux

    • 设置定义在/etc/sysctl.conf 中的内核参数

    • 设置系统时钟

    • 加载 keymaps

    • 使能交换分区

    • 设置主机名(hostname)

    • 根分区检查和 remount

    • 激活 RAID 和 LVM 设备

    • 开启磁盘配额

    • 检查并挂载所有文件系统

    • 清除过期的 locks 和 PID 文件

  • /etc/rc.d/rc 和/etc/rc.d/rc#.d/ 

    • rc是个脚本,后面接参数,如:l5:5:wait:/etc/rc.d/rc 5 ,这里的wait意味着init系统将等待rc启动服务脚本。

    • rc 根据 runlevel 执行rc#.d 目录下启动脚本。每个 runlevel 都有一个对应的 rc#.d 目录

    • 在这些目录下存放着很多不同的脚本,文件名以 S 开头的脚本表示在当前runlevel中启动,K开头的脚本表示不在当前runlevel中启动

    • 在/etc/rc.d/rc#.d 目录下的脚本其实都是一些软链接文件,真实的脚本文件存放在/etc/init.d 目录下,也就是说在/etc/init.d目录下的文件会自动以S##script或K##script的软链接存在于各 runlevel 的目录下

    • chkconfig –levle comm off实质上就是把S##script 改成了 K##script文件。注意这里的数字是在脚本内部定义的。自定义服务脚本时,定义的S数字尽量大,以免依赖的服务还没有启动。当使用 init #命令切换runlevel时,有些服务被关闭,此时定义的K数字尽量小,在依赖服务关闭前停止。

  • /etc/rc.d/rc.local 

    • rc#.d/S99local文件没有链接至/rc.d/init.d/而是rc#.d/S99local -> ../rc.local,因此,命令放置于/etc/rc.d/rc.local目录可实现开机时自动运行,简化了些服务脚本的过程。

  • /sbin/mingetty,X Display Manager(如果需要的话) 

  • init在等待/etc/rc.d/rc执行完毕之后,将在指定的各个虚拟终端上运行/sbin/mingetty,等待用户的登录。 至此,Linux的启动完成

自定义服务脚本

#自定义服务脚本,使用 chkconfig 管理
[root@cent6]/etc/rc.d/init.d>cat testsrv 
 #!/bin/bash    
 #chkconfig:35 92 22    #默认启动runlevel 3 5 ,S92testsrv ,K22testsrv
 #description:test service in /etc/rc.d/init.d/    #放在/etc/rc.d/init.d/自动链接至 0 - 6 runlevel
……
[ -x \$0 ]||chomd +x $0
#添加至服务列表
[root@cent6]~>chkconfig --add testsrt
#从服务列表删除
[root@cent6]~>chkconfig --del testsrt

#确认当前testsrv启动的runlevel
[root@cent6]/etc/rc5.d>chkconfig --list testsrv
testsrv         0:off   1:off   2:off   3:on    4:off   5:on    6:off
#选择on的rc5.d/,此时有S92testsrv文件,并且是一个软链接
[root@cent6]/etc/rc5.d>ll S92testsrv 
lrwxrwxrwx. 1 root root 17 Aug 17 11:37 S92testsrv -> ../init.d/testsrv

#修改S92 为预定义的 K22 文件,目的是看看runlevel5是否仍然 on
[root@cent6]/etc/rc5.d>mv S92testsrv K22testsrv
#runlevel5已经是off,说明chkconfig off 等于创建 K 开头的文件
[root@cent6]/etc/rc5.d>chkconfig --list testsrv
testsrv         0:off   1:off   2:off   3:on    4:off   5:off   6:off

#再次开启 runlevel5的testsrv服务
[root@cent6]/etc/rc5.d>chkconfig --level 5 testsrv on
testsrv         0:off   1:off   2:off   3:on    4:off   5:on    6:off
#rc5.d/目录下再次生成了S92testsrv文件
[root@cent6]/etc/rc5.d>ll S92testsrv 
lrwxrwxrwx. 1 root root 17 Aug 17 11:37 S92testsrv -> ../init.d/testsrv
  • Sysvinit 不仅需要负责初始化系统,还需要负责关闭系统。在系统关闭时,为了保证数据的一致性,需要小心地按顺序进行结束和清理工作。比如应该先停止对文件系统有读写操作的服务,然后再 umount 文件系统,否则数据就会丢失。这种顺序的控制这也是依靠/etc/rc.d/rc#.d/目录下所有脚本的命名规则来控制的,在该目录下所有以 K 开头的脚本都将在关闭系统时调用,字母 K 之后的数字定义了它们的执行顺序。这些脚本负责安全地停止服务或者其他的关闭工作。

Sysvinit 管理命令和控制功能

  • halt、init、killall、last、lastb、mesg、pidof、poweroff、reboot、shutdown、runlevel、sulogin、telinit、utmpdump、wall

Sysvinit 小结

  • sysvinit 的一个重要优点是确定的执行顺序:脚本严格按照启动数字的大小顺序执行,一个执行完毕再执行下一个,有利于错误排查

  • 串行地执行脚本导致 sysvinit 运行效率较慢,此外动态设备加载等 Linux 新特性体现出 sysvinit 的一些问题

补充:守护进程

  • 独立守护进程:就像上面的myservice一般能实现自我管理的守护进程

  • 超级守护进程:xinetd服务,就像一个代理人,如管理telnet服务,虽然端口开着,但是服务没有被激活

  • 瞬时守护进程:不需要关联至运行级别,以服务的方式被激活,由超级守护进程xinetd管理,可以认为这是Systemd的启动方式

Upstart

  • UpStart 主要的概念是 job 和 event。Job 就是一个工作单元,用来完成一件工作,比如启动一个后台服务,或者运行一个配置命令。每个 Job 都等待一个或多个事件,一旦事件发生,upstart 就触发该 job 完成相应的工作。UpStart 解决了之前提到的 sysvinit 的缺点。采用事件驱动模型

  • UpStart 可以: 
    更快地启动系统 
    当新硬件被发现时动态启动服务 
    硬件被拔除时动态停止服务

  • 这些特点使得 UpStart 可以很好地应用在桌面或者便携式系统,处理这些系统中的动态硬件插拔特性。

  • 原inittab下的记录 
    /etc/init/control-alt-delete.conf:快捷键重启的脚本,建议注释掉,防止误操作 
    /etc/init/tty.conf:重启终端脚本 
    /etc/init/start-ttys.conf:登录终端脚本 
    /etc/init/rc.conf:启动脚本 
    /etc/init/prefdm.conf:图像界面脚本

Systemd

  • CentOS 7 使用systemd替换了SysV。Systemd目的是要取代Unix时代以来一直在使用的init系统,兼容SysV和LSB的启动脚本,而且够在进程启动过程中更有效地引导加载服务

  • systemd的特性有: 
    支持并行化任务 
    同时采用socket式与D-Bus总线式激活服务; 
    按需启动守护进程(daemon); 
    利用 Linux 的 cgroups 监视进程; 
    支持快照和系统恢复; 
    维护挂载点和自动挂载点; 
    各服务间基于依赖关系进行精密控制。

原创文章,作者:helloc,如若转载,请注明出处:http://www.178linux.com/46234