一、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里设置的启动顺序依次寻找可引导设备,第一个有引导程序的设备即为启动PC server所用到的设备
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
[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、6、7上的init程序各不相同:
CentOS 5:传统SysV的init,且只有/etc/inittab
CentOS 6:由ubantu开发的upstart,在CentOS 6上也表现为init
/etc/inittab,/etc/init/*.conf
CentOS 7:systemd,也表现为init
在/etc/inittab和/etc/init/*.conf中,大致规定了以下动作:
取得runlevel即运行级别
使用/etc/rc.d/rc.sysinit进行系统初始化
根据runlevel启动相应的服务并关闭需要停止的服务
确定Ctrl+Alt+Delete组合键功能
启动字符终端
启动图形终端
系统运行级别:
0:关机
1:single user mode,单用户模式;直接以root身份登录,无需身份认证,且不会开启网络服务
2:multi user mode,不支持NFS功能
3:完全多用户模式,文本接口
4:未使用,预留级别
5:完全多用户模式,图形接口
6:重启
可在命令行切换级别:init #
[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,数字越小,越优先启动或关闭
[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意为重置,即恢复成服务脚本中的初始设置
[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
[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过程如下:
[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 ~]# 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
[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