当前位置:K88软件开发文章中心编程语言LinuxLinux01 → 文章内容

linux系统启动流程详解

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-4 8:59:31

-->

一、linux系统的总体启动流程如下:
POST –> BIOS(Boot Sequence) –> MBR(bootloader) –> kernel + initramfs(或initrd) –> mount rootfs (ro) –> /sbin/init设定默认运行级别 –> 使用/etc/rc.d/rc.sysinit初始化系统 –> 分别启动并关闭指定服务 –> Ctrl+Alt+Delete组合键 –> 启动字符终端 –> 启动图形终端

二、linux系统启动各阶段详述:
1、post:加电自检。通电后,CPU会加载位于CMOS中的BIOS程序,BIOS由一系列的汇编指令组成,它会识别并检测主板上的所有硬件,然后按照BIOS里设置的启动顺序依次寻找可引导设备,一旦找到便停止寻找

2、MBR:CPU读取可引导设备的第一个扇区即MBR(Master boot record),也称“主引导记录”,大小为512字节,其中存放着:
引导加载程序(boot loader):446bytes,常用的boot loader有LILO和GRUB,现以GRUB为主;
分区表:64bytes
有效性标记:2bytes
CPU把boot loader加载到内存中执行,boot loader帮我们从磁盘上找到内核并加载到内存中

3、kernel:内核被加载后,它要做的工作主要有:探测硬件、装载驱动程序、以只读方式装载根文件系统(rootfs)、启动第一个进程/sbin/init。
这里会有个“鸡生蛋”还是“蛋生鸡”的问题,根文件系统存在于磁盘上,内核要装载根文件系统就需要先能驱动磁盘,即需要先装载驱动程序,而驱动程序又在磁盘上。为解决此问题,boot loader在加载内核的同时也把initramfs(或initrd)加载到内存中(有关initramfs和initrd的详细说明见文末补充部分),它是一个临时的根文件系统,里面包含了启动所必须的驱动模块。内核挂载这个临时根,装载驱动程序,然后释放临时根,挂载实际的根文件系统,并启动第一个进程/sbin/init。
kernel和initramfs文件位于boot分区(或目录)下:
内核:/boot/vmlinux-VERSION-release
initramfs:/boot/initramfs-VERSION-release.img

1
2
3
[root@node2 ~]# ls /boot
config-2.6.32-431.el6.x86_64  grub                                 lost+found                        System.map-2.6.32-431.el6.x86_64
efi                           initramfs-2.6.32-431.el6.x86_64.img  symvers-2.6.32-431.el6.x86_64.gz  vmlinuz-2.6.32-431.el6.x86_64

4、init:内核初始化的最后一步就是启动pid为1的/sbin/init进程。这个进程是系统的第一个进程,它负责产生其他所有进程。init进程上来首先做的事是去读取/etc/inittab和/etc/init/*.conf(Centos 5上只有inittab文件)
在/etc/inittab和/etc/init/*.conf中,大致规定了以下动作:
取得runlevel即运行级别
使用/etc/rc.d/rc.sysinit进行系统初始化
根据runlevel启动相应的服务并关闭需要停止的服务
确定Ctrl+Alt+Delete组合键功能
启动字符终端
启动图形终端
系统运行级别:
0:关机
1:single user mode,即单用户模式
2:multi user mode,不支持NFS功能
3:完全多用户模式,文本接口
4:未使用,预留级别
5:完全多用户模式,图形接口
6:重启
可在命令行切换级别:init #

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@node2 ~]# cat /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
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
#
# 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)
#
id:3:initdefault:  #这里设置的运行级别是3

[root@node2 ~]# ls /etc/init
control-alt-delete.conf  plymouth-shutdown.conf  rc.conf             rcS-sulogin.conf          readahead-disable-services.conf  start-ttys.conf
init-system-dbus.conf    prefdm.conf             rcS.conf            readahead-collector.conf  serial.conf                      tty.conf
kexec-disable.conf       quit-plymouth.conf      rcS-emergency.conf  readahead.conf            splash-manager.conf

■补:CentOS 5中的/etc/inittab
与Centos 6不同,Centos 5上只有/etc/inittab,所有的初始化动作都是在此文件中定义的,此文件中定义的登记项都是以:隔开的四个段,格式如下:
id:runlevels:action:process 例如si::sysinit:/etc/rc.d/rc.sysinit
各字段的含义:
id:登记项的标识符,必须是唯一的
runlevels:系统的运行级别,表示process的action要在哪个级别下运行,可定义多个级别,各级别间不用分隔符;如果为空,表示在所有的运行级别下运行
具体的action有:
respawn:当process终止后马上启动一个新的
wait:当进入指定的runlevels后process才会启动一次,并且到离开runlevels为止
initfault:设定默认的运行级别
sysinit:系统初始化,只有系统开机或重启时process才会被执行一次

5、sysinit:在设定了运行等级后,Linux系统执行的第一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作包括:
设定主机名:读取/etc/sysconfig/network文件中的HOSTNAME参数,并以之设定主机名
打印文本欢迎信息
激活selinux和udev
挂载/etc/fstab文件中定义的其它文件系统
激活swap
检测根文件系统,并以读写方式重新挂载
设置系统时钟
根据/etc/sysctl.conf设置内核参数
激活LVM和RAID设备
加载额外设备的驱动程序
清理操作

6、启动指定的默认级别的默认为启动的服务,停止指定的级别下默认为关闭的服务
/etc/rc.d/rc#.d (#表示运行级别),该目录下都是符号链接文件,其指向的实际服务脚本位于/etc/rc.d/init.d目录中(该目录有个软链接/etc/init.d)。这些链接文件均以S或K开头:
S##:启动的服务
K##:停止的服务
##:01-99,数字越小,越优先启动或关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@node2 ~]# ls /etc/rc.d/
init.d  rc  rc0.d  rc1.d  rc2.d  rc3.d  rc4.d  rc5.d  rc6.d  rc.local  rc.sysinit
[root@node2 ~]# ll /etc/rc.d/rc3.d
total 0
...
lrwxrwxrwx. 1 root root 19 Aug  6 04:38 K75quota_nld -> ../init.d/quota_nld
lrwxrwxrwx. 1 root root 16 Aug  6 04:44 K76ypbind -> ../init.d/ypbind
lrwxrwxrwx. 1 root root 15 Aug  6 04:53 K80kdump -> ../init.d/kdump
lrwxrwxrwx  1 root root 24 Oct 31 07:28 K84wpa_supplicant -> ../init.d/wpa_supplicant
lrwxrwxrwx. 1 root root 21 Aug  6 04:34 K87restorecond -> ../init.d/restorecond
lrwxrwxrwx  1 root root 14 Oct 31 07:28 K88sssd -> ../init.d/sssd
lrwxrwxrwx. 1 root root 15 Aug  6 04:34 K89rdisc -> ../init.d/rdisc
lrwxrwxrwx. 1 root root 14 Aug  6 04:38 K99rngd -> ../init.d/rngd
lrwxrwxrwx. 1 root root 22 Aug  6 04:38 S02lvm2-monitor -> ../init.d/lvm2-monitor
lrwxrwxrwx. 1 root root 19 Aug  6 04:36 S08ip6tables -> ../init.d/ip6tables
...
lrwxrwxrwx. 1 root root 11 Aug  6 04:34 S99local -> ../rc.local  #最后一个启动链接文件指向父目录rc.local
[root@node2 ~]# cat /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

见上方,最后的一个启动链接文件为S99local,它指向/etc/rc.d/rc.local,如果我们不想把某些开机后的操作专门写成脚本,可写入此文件中。/etc/rc.d/rc.local还有一个软链接/etc/rc.local

若想控制某个脚本是否开机启动,可使用chkconfig命令
■chkconfig:查看或修改服务随系统启动的启动选项,它并不是直接激活或停止一个服务,而只是修改了其符号链接。用法如下:
①让指定的服务接受chkconfig命令管理:
第一步:在位于/etc/rc.d/init.d目录下的服务脚本中添加如下一行或多行注释:
# chkconfig: LEVEL SPRI KPRI ,例如# chkconfig: – 85 15
chkconfig后面有三个字段,它们的含义分别为:
LEVEL:当此服务由chkconfig控制时,默认在哪些运行级是启动的。若默认不在任何运行级启动,以“-”号表示
SPRI:启动优先级
KPRI:关闭优先级
第二步:chkconfig add SERVICE,该命令会自动在/etc/rc.d/rc#.d目录中创建链接文件
②chkconfig del SERVICE:让指定服务不再接受chkconfig管理,会删除链接文件
③chkconfig –list [SERVICE]:显示所有服务或指定服务的开机启动设置
④chkconfig [–level ###] SERVICE on/off/reset:若不指定–level选项,on和off操作默认只对运行级2、3、4、5有效,而reset默认对所有运行级有效,reset意为重置,即恢复成服务脚本中的初始设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@node2 ~]# cp testsrv /etc/rc.d/init.d/testsrv  #接受chkconfig管理的服务其服务脚本必须位于init.d目录下
[root@node2 ~]# vim /etc/init.d/testsrv

#!/bin/bash
#
# chkconfig: 2345 90 10  #添加这一行,表示默认在运行级别为2、3、4、5开机启动
srv=`basename $0`
 
lockFile="/var/lock/subsys/$srv"
 
[ $# -lt 1 ] && echo "Usage: $srv {start|stop|restart|status}" && exit 4

[ $UID -ne 0 ] && echo "Only root." && exit 5
 
if [ "$1" == 'start' ]; then
   if [ -f $lockFile ]; then
        echo "$srv is running."
        exit 7
...
[root@node2 ~]# chkconfig --add testsrv   #让testsrv接受chkconfig命令管理
[root@node2 ~]# ll /etc/rc.d/rc3.d | grep 'testsrv'  #显示已创建了链接文件
lrwxrwxrwx  1 root root 17 Oct 31 08:29 S90testsrv -> ../init.d/testsrv
[root@node2 ~]# chkconfig --list testsrv   #显示各级别开机启动设置
testsrv         0:off   1:off   2:on    3:on    4:on    5:on    6:off
[root@node2 ~]# chkconfig testsrv off  #默认关闭2-5级别开机启动
[root@node2 ~]# chkconfig --list testsrv
testsrv         0:off   1:off   2:off   3:off   4:off   5:off   6:off
[root@node2 ~]# chkconfig --level 23 testsrv on  #指定在2、3级别随开机启动
[root@node2 ~]# chkconfig --list testsrv
testsrv         0:off   1:off   2:on    3:on    4:off   5:off   6:off
[root@node2 ~]# chkconfig testsrv reset  #重置
[root@node2 ~]# chkconfig --list testsrv  #显示已恢复成初始设置
testsrv         0:off   1:off   2:on    3:on    4:on    5:on    6:off
[root@node2 ~]# chkconfig --del testsrv
[root@node2 ~]# ll /etc/rc.d/rc3.d | grep 'testsvr'
[root@node2 ~]# rm -f /etc/init.d/testsrv

7、Ctrl+Alt+Delete组合键
启动系统服务后就是确定Ctrl+Alt+Delete组合键的功能了,配置文件为/etc/init/control-alt-delete.conf

1
2
3
4
5
6
7
8
9
10
11
12
[root@node2 ~]# cat /etc/init/control-alt-delete.conf
# control-alt-delete - emergency keypress handling
#
# This task is run whenever the Control-Alt-Delete key combination is
# pressed.  Usually used to shut down the machine.
#
# Do not edit this file directly. If you want to change the behaviour,
# please create a file control-alt-delete.override and put your changes there.

start on control-alt-delete
 
exec /sbin/shutdown -r now "Control-Alt-Delete pressed"  #Control-Alt-Delete组合键的默认功能为重启系统

三、补充:initrd和initramfs
①initrd全称为initial ram disk,即linux初始RAM磁盘,它被加载到内存中后,会被内核当作block device。因为linux在设计上就会尽可能将读取/写入block device的文件予以cache,这样一来就会有重复的block device和cache资料,会浪费内存。
为解决此问题,linux 2.6之后引入了initramfs,它是一种ram filesystem,被加载至内存后,会被内核直接挂载并读取,不会再次cache
②initramfs或initrd实际是一个经过cpio和gzip工具处理后的归档压缩文件
展开initramfs过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@node2 ~]# ls /boot
config-2.6.32-431.el6.x86_64  grub                                 lost+found                        System.map-2.6.32-431.el6.x86_64
efi                           initramfs-2.6.32-431.el6.x86_64.img  symvers-2.6.32-431.el6.x86_64.gz  vmlinuz-2.6.32-431.el6.x86_64
[root@node2 ~]# file /boot/initramfs-2.6.32-431.el6.x86_64.img  #显示initramfs是经过zip压缩的
/boot/initramfs-2.6.32-431.el6.x86_64.img: gzip compressed data, from Unix, last modified: Thu Aug  6 04:42:48 2015, max compression
[root@node2 ~]# cp /boot/initramfs-2.6.32-431.el6.x86_64.img ./initramfs-2.6.32-431.el6.x86_64.img.gz  #要添加后缀后才能解压
[root@node2 ~]# gunzip initramfs-2.6.32-431.el6.x86_64.img.gz #解压
[root@node2 ~]# ls
anaconda-ks.cfg  Downloads                            install.log                      Pictures            samba-3.6.23-20.el6.x86_64.rpm  vmware-tools-distrib
a.txt            epel-release-latest-6.noarch.rpm     install.log.syslog               Public              Templates                       zabbix-2.4
Desktop          ftp-0.17-54.el6.x86_64.rpm           Music                            ramfs               testsrv
Documents        initramfs-2.6.32-431.el6.x86_64.img  mysql-5.1.73-5.el6_6.x86_64.rpm  RPM-GPG-KEY-EPEL-6  Videos
[root@node2 ~]# cd ramfs
[root@node2 ~]# file initramfs-2.6.32-431.el6.x86_64.img #显示为cpio归档文件
initramfs-2.6.32-431.el6.x86_64.img: ASCII cpio archive (SVR4 with no CRC)
[root@node2 ~]# mkdir ramfs
[root@node2 ~]# cd ramfs
[root@node2 ramfs]# cpio -i < ../initramfs-2.6.32-431.el6.x86_64.img  #展开
97331 blocks
[root@node2 ramfs]# ls
bin      dev                 emergency  init       initqueue-finished  initqueue-timeout  lib64  pre-pivot    pre-udev  sbin  sysroot  usr
cmdline  dracut-004-335.el6  etc        initqueue  initqueue-settled   lib                mount  pre-trigger  proc      sys   tmp      var

③使用工具dracut或mkinitrd创建initramfs
mkinitrd实际上也是调用dracut的功能,在Centos 6上已被dracut取代
用法:
dracut [-f] [-k DIR] /path/to/initramfs-KERNEL_VERSION.img KRENEL_VERSION
-f:覆盖现有的同名initramfs文件
-k DIR:指定加载内核模块的位置;默认为/lib/modules/KERNEL_VERSION
示例:针对当前运行内核创建
dracut /boot/initramfs-$(uname -r).img $(uname -r)
针对指定内核创建:(要确保能找到对应的内核模块)
dracut /boot/initramfs-3.10.1.img 3.10.1

1
2
3
4
5
6
[root@node2 boot]# mv initramfs-2.6.32-431.el6.x86_64.img initramfs-2.6.32-431.el6.x86_64.img.back   #备份现有initramfs文件
[root@node2 boot]# dracut initramfs-$(uname -r).img $(uname -r)  #针对当前系统内核创建initramfs
[root@node2 boot]# ls
config-2.6.32-431.el6.x86_64  initramfs-2.6.32-431.el6.x86_64.img       symvers-2.6.32-431.el6.x86_64.gz
efi                           initramfs-2.6.32-431.el6.x86_64.img.back  System.map-2.6.32-431.el6.x86_64
grub                          lost+found                                vmlinuz-2.6.32-431.el6.x86_64

linux系统启动流程详解