centos系统启动流程

Posted xiaoshiwang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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系统启动流程

前提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 -r
run-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 stop
Stopping 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 on
service 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 start
start 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 -1
lrwxrwxrwx. 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 start
Redirecting 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-default
graphical.target

centos7的init程序:Systemd

? 使用的配置文件: /usr/lib/systemd/system目录下的文件,和/etc/systemd/system目录下的文件

c/c++ 学习互助QQ群:877684253

技术图片

本人微信:xiaoshitou5854

以上是关于centos系统启动流程的主要内容,如果未能解决你的问题,请参考以下文章

CentOS系统启动流程

CentOS 6开机启动流程实验篇

Centos系统启动流程

CentOS系统启动流程

CentOS系统启动流程

CentOS 6系统启动流程