centos系统启动流程
linux内核特点:
- 支持模块化:模块文件的名字以.ko(kernel object)结尾
- 支持内核运行时,动态加载和卸载模块文件。
linux内核组成部分:
核心文件:/boot/vmlinuz-VERSION-release
# ll /boot/vmlinuz-3.10.0-957.el7.x86_64
-rwxr-xr-x. 1 root root 6639904 Nov 9 2018 /boot/vmlinuz-3.10.0-957.el7.x86_64
# file /boot/vmlinuz-3.10.0-957.el7.x86_64
/boot/vmlinuz-3.10.0-957.el7.x86_64: Linux kernel x86 boot executable bzImage, version 3.10.0-957.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) #1 S, RO-rootFS, swap_dev 0x6, Normal VGA
模块文件:/lib/modules/VERSION-release
如果按照了多个内核版本,则/lib/modules下,有多个目录
# ll /lib/modules
drwxr-xr-x. 8 root root 4096 Feb 20 10:03 3.10.0-957.el7.x86_64
3.10.0-957.el7.x86_64目录下的文件:
# ls /lib/modules/3.10.0-957.el7.x86_64/
build modules.alias modules.builtin.bin modules.drm modules.softdep updates
extra modules.alias.bin modules.dep modules.modesetting modules.symbols vdso
kernel modules.block modules.dep.bin modules.networking modules.symbols.bin weak-updates
misc modules.builtin modules.devname modules.order source
其中有:kernel目录
# ls /lib/modules/3.10.0-957.el7.x86_64/kernel/
arch crypto drivers fs kernel lib mm net sound virt
arch:平台特有;crypto:加密/解密;drivers:驱动管理;mm:内存管理。fs:文件系统;net:网络管理;sound:声卡驱动
ramdisk:
ramdisk的由来:操作系统不知道用户的电脑上的磁盘设备是什么型号的,访问特定磁盘是要使用特定的磁盘驱动程序的,所以操作系统可能就要把市面上主流的磁盘驱动程序都准备好,放入安装盘中,这样一来安装盘太臃肿。为了解决这个问题,操作系统不准备任何磁盘驱动程序,而是在安装操作系统的过程中,扫描用户的硬件,根据硬件自动生成磁盘驱动程序,并把这个驱动程序存放入磁盘中。
开机后,内核被装载到内存后,就要去从磁盘找根文件系统。内核要想访问磁盘,必须需要访问磁盘的驱动程序,可是磁盘的驱动程序又在根文件系统里,所以内核就无法找到磁盘的驱动程序,也就无法访问磁盘。所以需要一个临时的根文件系统,在里面放磁盘的驱动程序。这个临时的驱动程序和根文件系统,是在安装操作系统时,由安装程序扫描机器的硬件后,根据硬件的型号自动生成的。有了这个东西后,内核就先把一段内存模拟成磁盘,把这个东西放到内存中,从它的里面取得到磁盘驱动,然后使用好不容易得到的驱动程序,去访问真的磁盘,得到真的根文件系统。然后真的根文件系统,取代这个东西。
这个东西叫:ramdisk。
我们使用
free
命令,可以看到buff和cache。为什么有buff和cache呢?因为磁盘IO太慢,所以把经常访问的磁盘上的数据,载入内存的buff和cache区域。# free
total used free shared buff/cache available
Mem: 3880164 459420 2525300 12596 895444 3076684
Swap: 4063228 0 4063228
centos5:/boot/initrd-VERSION-release.img
由于是用内存模拟磁盘,所以内存又使用buff和cache机制,缓存了磁盘的内容,造成了双重buff和cache。
centos6,7:/boot/initramfsVERSION-release.img
为了防止双重buffer和cache,centos6和7使用ramfs,ramfs是文件系统,就防止了双重buff和cache。
# ll /boot/initramfs-3.10.0-957.el7.x86_64.img
-rw-------. 1 root root 31489644 Nov 29 17:11 /boot/initramfs-3.10.0-957.el7.x86_64.img
ramdisk的做成工具程序:
- centos5:
mkinitrd
- centos6,7:
dracut
。为了兼容centos5,也可以使用mkinitrd
- centos5:
centos5系统启动流程
前提pc主机,MBR架构
第一步:post(power on system test)加电自检。
pc机的主板上有个rom芯片(CMOS),加电后,cpu去找这个raw,然后读取里面的指令,检测机器上是否有:内存,硬盘,显示设备等。
CMOS里有个bios(basic input output system)程序
第二步:boot sequence(bios里设置是用光盘启动,还是硬盘启动等)
按次序查找引导设备,第一个有引导程序(bootloader)的设备即为本次启动要用到的设备。
bootloader:引导程序
功能:
- 提供一个可以让用户选择的菜单,上面写着,可以选择运行的内核列表
- 把用户选定的内核程序从磁盘加载到内存的特定空间中,然后解压,展开,此后,内核就开始真正运行起来了,然后bootloader退出,由内核接管一切。
注意:由于bootloader仅有446字节,它无法读取LVM,软RAID的逻辑分区,只能读取物理分区,所以内核程序只能存放在物理分区上。
种类:
LILO:linux loader。它有个致命弱点,如果内核在磁盘的1024以后的柱面上存储着的话,它无法加载内核。安卓手机用的是LILO。
GRUB:Grand Uniform Bootloader
centos5,6用的版本是:grub 0.x(别名:grub legacy)
cengtos7用的版本是:grub 1.x(别名:grub2)
bootloader程序放在哪里了?
如果是MBR架构,则放在了在0号track(磁道),0号sector(扇区)里 的前446bytes 。
由于只有446字节,空间太小了,能写的程序实在有限,所以linux使用GRUB机制。
GRUB机制:不让bootloader直接加载内核,而是让bootloader加载磁盘上的另外一个程序/boot/grub。由于/boot/grub是放在磁盘上的,所以突破了446字节的约束。
- 第一阶段:bootloader加载/boot/grub程序
- 第1.5阶段:filesystem driver?
- 第二阶段:/boot/grub程序加载内核。
第三步:kernel自身初始化
探测所以硬件设备
为了加载磁盘上的根文件系统,所以先加载ramdisk上的文件系统,找到里面的磁盘驱动程序。
注意:也有可能不使用ramdisk。当自己在自己的机器上编译内核时,编译程序就探测到了本地磁盘类型,所以在编译的时候,就可以把磁盘的驱动,编译到内核里,所以内核就不需要再去找ramdisk了。
使用磁盘驱动,以只读方式,加载根文件系统。只读的目的:防止内核有bug,把根文件系统里面的东西删除了。没问题后,再改为读写方式。
运行用户空间的第一个应用程序:/sbin/init
centos5之前的init程序:SysV init
使用的配置文件:/etc/inittab
centos6的init程序:Upstart
使用的配置文件:/etc/init/*.conf
centos7的init程序:Systemd
使用的配置文件: /usr/lib/systemd/system目录下的文件,和/etc/systemd/system目录下的文件
第四步:/sbin/init会启动/sbin/mingetty程序,显示可以登录的文本界面。
Linux的运行级别
为了系统的维护等目的设定了7个级别(0~6)
- 级别0:关机 shutdown
- 级别1:单用户模式(single user),以root用户登录,无需输入root密码。root密码忘记了,使用级别1。输入维护模式。
- 级别2:多用户模式(multi user),会启动网络功能,但不会启动NFS。属于维护模式。
- 级别3:多用户模式(multi user),完全功能模式,但不启动图形界面。
- 级别4:预留级别,没有被使用,但习惯以同3级别功能使用。
- 级别5:多用户模式(multi user),完全功能模式,开机自动启动图形界面。
- 级别6:重启 reboot
默认级别是3或5,server用级别3;个人主机用级别5.
切换级别的命令:init 级别
查看当前的级别:who -r
或者runlevel
run命令的结果里的N:上一次的级别。由于没切换过级别,所以上一次就是N。
# who -rrun-level 5 2020-02-20 10:03
# runlevel
N 5
init程序的配置文件说明
1,centos5,6:/etc/inittab
每行定义一种action,以及与之对应的process
每一行的格式:id:runlevel:action:process
id:标识
runlevel:运行级别
action:指明启动process的条件
- wait:当运行级别切换至此行的级别时,执行一次process
- respawn:一旦此行的process终止,就自动重新启动它
- initdefault:设定系统开机时默认的运行级别,所以此行的process省略
- sysinit:设定系统初始化的方式,所以runlevel省略,process一般为/etc/rc.d/rc.sysinit脚本
process:程序
例子:
id01:3:initdefault:
系统开机时,以级别3运行。
id02::sysinit:/etc/rc.d/rc.sysinit
不管以哪个级别运行,都使用/etc/rc.d/rc.sysinit脚本完成系统初始化。
id03:3:wait:/etc/rc.d/rc 0
当切换到级别3后,运行脚本:/etc/rc.d/rc 0一次。
脚本/etc/rc.d/rc的作用:当切换运行级别时,定义先kill哪些进程,然后再启动哪些进程。
- 脚本参数:运行级别
解释脚本/etc/rc.d/rc之前,先看看目录/etc/rc.d/下的构成。
下面有rc0.d,rc1.d,rc2.d,rc3.d,rc4.d,rc5.d,rc6.d目录
# ll /etc/rc.d/drwxr-xr-x. 2 root root 4096 Feb 21 09:19 init.d
-rwxr-xr-x. 1 root root 2617 Jun 19 2018 rc
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc0.d
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc1.d
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc2.d
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc3.d
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc4.d
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc5.d
drwxr-xr-x. 2 root root 4096 Feb 21 09:19 rc6.d
-rwxr-xr-x. 1 root root 220 Jun 19 2018 rc.local
-rwxr-xr-x. 1 root root 20199 Jun 19 2018 rc.sysinit
/etc/rc.d/rc的脚本内容摘要:
变量$runlevel,就是执行此脚本时,传进来的参数,也就是运行级别。
# First, run the KILL scripts.for i in /etc/rc$runlevel.d/K* ; do
#省略
$i stop
#省略
done
# Now run the START scripts.
for i in /etc/rc$runlevel.d/S* ; do
#省略
$i start
#省略
done
所以当运行/etc/rc.d/rc 3的时候,实际运行的脚本的就/etc/rc3.d/目录下的:K*和S*的所有脚本。
查看一下ls /etc/rc.d/rc3.d的目录,发现都是符号链接文件,指向的是/etc/init.d目录下的相应的脚本。其他的rc1.d等目录下也都是符号链接,而且指向的也是/etc/init.d目录下的相应的脚本。所有不管传的运行级别参数是什么,实际运行的脚本都是/etc/init.d下的相应的脚本。
# ll /etc/rc.d/rc3.d/K*lrwxrwxrwx. 1 root root 15 Jan 31 14:09 /etc/rc.d/rc3.d/K01numad -> ../init.d/numad
lrwxrwxrwx. 1 root root 16 Jan 31 14:09 /etc/rc.d/rc3.d/K01smartd -> ../init.d/smartd
# ll /etc/rc.d/rc3.d/S*
lrwxrwxrwx. 1 root root 17 Jan 31 14:09 /etc/rc.d/rc3.d/S01sysstat -> ../init.d/sysstat
lrwxrwxrwx. 1 root root 22 Jan 31 14:09 /etc/rc.d/rc3.d/S02lvm2-monitor -> ../init.d/lvm2-monitor
lrwxrwxrwx. 1 root root 14 Jan 31 14:09 /etc/rc.d/rc3.d/S05rdma -> ../init.d/rdma
那么,为什么弄出这么多符号链接呢?
观察这些符号链接,发现:K和S的后面都有2位数字。
这2位数字是为了排序用的,/etc/rc.d/rc脚本的for i in /etc/rc$runlevel.d/K* ; do
语句,就把以K后S开头的按后面的数字排序了。
- K##:要被结束的进程。##数字越小,先被结束。所以不被别的进程依赖的进程,数字小。
- S##:要被启动的进程。##数字越小,先被启动。所以被别的进程依赖的进程,数字小。
启动服务时,都是使用service 服务程序名 start
,其实service命令,调用的是就是/etc/init.d目录下的脚本,所以直接运行脚本和使用service命令的效果是一样的,试验如下:
# /etc/init.d/crond stopStopping crond: [ OK ]
# /etc/init.d/crond start
Starting crond: [ OK ]
# /etc/init.d/crond status
crond (pid 4822) is running...
# /etc/init.d/crond restart
Stopping crond: [ OK ]
Starting crond: [ OK ]
# service crond status
crond (pid 4850) is running...
# service crond restart
Stopping crond: [ OK ]
Starting crond: [ OK ]
# service crond stop
Stopping crond: [ OK ]
# service crond start
Starting crond: [ OK ]
当想让某个服务进程开机就自动运行的话,在目录/etc/init.d下创建自己的脚本文件:
#!/bin/bash#
# test servvice
#
# chkconfig: 2345 90 60
# description: test service
prog=$(basename $0)
if [ $# -lt 1 ]; then
echo "Usage:$prog {start|stop|status|restart}"
exit 1
fi
if [ "$1" == "start" ]; then
echo "start $prog done"
elif [ "$1" == "stop" ]; then
echo "stop $prog done"
elif [ "$1" == "restart" ]; then
echo "restart $prog done"
elif [ "$1" == "status" ]; then
if [ pidof $prog &> /dev/null ]; then
echo "$prog is running"
else
echo "$prog is stopped"
fi
else
echo "Usage:$prog {start|stop|status|restart}"
exit 2
fi
注意:chkconfig: 2345 90 60
2345:级别
90:启动优先级
60:终止优先级
有个命令chkconfig
可以帮助我们,在rc0.d,rc1.d,rc2.d,rc3.d,rc4.d,rc5.d,rc6.d目录下自动创建符号链接,符号链接的名字:S90mySer.sh和K60mySer.sh。但不是在所以目录都创建,根据写的级别创建,这里写的是2345,所以在rc2.d,rc3.d,rc4.d,rc5.d目录下创建S90mySer.sh和K60mySer.sh
虽然【# chkconfig: 2345 90 60】是注释,但必须有这行。否则,执行chkconfig
命令出下面的错误:
# chkconfig mySer.sh onservice mySer.sh does not support chkconfig
使用chkconfig mySer.sh on
就是在2345目录下创建S90mySer.sh文件
使用chkconfig mySer.sh off
就是在2345目录下创建K90mySer.sh文件
# chkconfig mySer.sh on# ls /etc/rc.d/rc0.d/ | grep mySer
# ls /etc/rc.d/rc1.d/ | grep mySer
# ls /etc/rc.d/rc2.d/ | grep mySer
S90mySer.sh
# ls /etc/rc.d/rc3.d/ | grep mySer
S90mySer.sh
# ls /etc/rc.d/rc4.d/ | grep mySer
S90mySer.sh
# ls /etc/rc.d/rc5.d/ | grep mySer
S90mySer.sh
# ls /etc/rc.d/rc6.d/ | grep mySer
# chkconfig mySer.sh off
# ls /etc/rc.d/rc0.d/ | grep mySer
# ls /etc/rc.d/rc1.d/ | grep mySer
# ls /etc/rc.d/rc2.d/ | grep mySer
K60mySer.sh
# ls /etc/rc.d/rc3.d/ | grep mySer
K60mySer.sh
# ls /etc/rc.d/rc4.d/ | grep mySer
K60mySer.sh
# ls /etc/rc.d/rc5.d/ | grep mySer
K60mySer.sh
# ls /etc/rc.d/rc6.d/ | grep mySer
有了这些链接文件后,就可以使用service
命令,来启动我们的服务了。
# service mySer.sh startstart mySer.sh done
# service mySer.sh stop
stop mySer.sh done
# service mySer.sh restart
restart mySer.sh done
chkconfig选项:
查看:--list [scriptname]
# chkconfig --list
abrt-ccpp 0:off 1:off 2:off 3:on 4:off 5:on 6:off
abrtd 0:off 1:off 2:off 3:on 4:off 5:on 6:off
acpid 0:off 1:off 2:on 3:on 4:on 5:on 6:off
atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off
auditd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
autofs 0:off 1:off 2:off 3:on 4:on 5:on 6:off
# chkconfig --list mySer.sh
mySer.sh 0:off 1:off 2:on 3:on 4:on 5:on 6:off
指定运行级别:--level LEAVES
# chkconfig --list mySer.sh
mySer.sh 0:off 1:off 2:on 3:on 4:on 5:on 6:off
# chkconfig --level 35 mySer.sh off
# chkconfig --list mySer.sh
mySer.sh 0:off 1:off 2:on 3:off 4:on 5:off 6:off
当只是单纯开机运行某个进程,而不需要额外的脚本的话,直接修改/etc/rc.d/rc.local文件即可。
下面添加了touch /tmp/welcome
,所以开机后,就会创建这个文件;
添加了/usr/sbin/httpd
,所以开机后,就会启动httpd进程。
#!/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 /tmp/welcome
/usr/sbin/httpd
为什么编辑/etc/rc.d/rc.local文件就好用呢?
因为这个文件被rc2.d,rc3.d,rc4.d,rc5.d目录里的最后一个文件S99local链接了
# ll /etc/rc.d/rc2.d/ | tail -1lrwxrwxrwx. 1 root root 11 Jan 31 14:08 S99local -> ../rc.local
# ll /etc/rc.d/rc3.d/ | tail -1
lrwxrwxrwx. 1 root root 11 Jan 31 14:08 S99local -> ../rc.local
# ll /etc/rc.d/rc4.d/ | tail -1
lrwxrwxrwx. 1 root root 11 Jan 31 14:08 S99local -> ../rc.local
# ll /etc/rc.d/rc5.d/ | tail -1
lrwxrwxrwx. 1 root root 11 Jan 31 14:08 S99local -> ../rc.local
系统初始化脚本/etc/rc.d/rc.sysinit的作用:
- 设置主机名
- 设置欢迎信息
- 激活udev(创建设备文件用的)和selinux
- 挂载/etc/fstab文件中定义的所以文件系统
检测根文件系统,没有问题后,以读写方式重新挂载根文件系统。
- 读取硬件时钟,设置系统时钟
- 读取配置文件/etc/sysctl.conf里的内核参数,修改内核的行为。
- 激活lvm及软raid设备
- 激活swap设备
- 从根文件系统,加载硬件的驱动程序
清理操作
总结:/sbin/init的启动流程
1,通过读取配置文件/etc/inittab,获得运行级别
2,执行脚本/etc/rc.d/rc.sysinit,完成系统初始化
3,根据取得的运行级别,先停止这个级别不需要运行的进程(K##),再启动这个级别需要运行的进程(S##)
4,设置登录终端。如果是级别3则登录终端是文本界面
5,如果是级别5,则需要启动图形界面服务,显示图形登录界面;
centos6系统启动流程
基本和centos5相同,只列出不同点
1,init程序:upstart,但依然为/sbin/init。其配置文件不是/etc/inittab了,而是/etc/init/*.conf。但/etc/inittab里也有用,只放默认运行级别一行(id:3:initdefault:)。
2,系统初始化脚本是/etc/init/rcS.conf,但里面运行的是/etc/rc.d/rc.sysinit
3,脚本/etc/init/rc.conf里面,调用/etc/rc.d/rc $RUNLEVEL
centos7系统启动流程
启动流程是一样的,实现的细节不一样。
兼容centos5和6,所以也可以使用service命令。
# service crond startRedirecting to /bin/systemctl start crond.service
# service crond status
Redirecting to /bin/systemctl status crond.service
centos7使用systemctl
命令。
centos7没有了运行级别的概念,改用target概念
- graphical.target对应运行级别5
- multi-user.target对应运行级别3
systemctl get-default
# systemctl get-defaultgraphical.target
centos7的init程序:Systemd
使用的配置文件: /usr/lib/systemd/system目录下的文件,和/etc/systemd/system目录下的文件
c/c++ 学习互助QQ群:877684253
本人微信:xiaoshitou5854
以上是 centos系统启动流程 的全部内容, 来源链接: utcz.com/z/513696.html