Skip to content

系统启动过程 ​

早期开机方式 ​

为什么这里要特别强调早期呢?因为现在启动方式已经变了。这时肯定就有很多人有疑惑了, 既然都变了, 为什么还要讲旧的呢?

其实这种早期的启动方式还是很有必要学的。原因有以下几点。

  • 现在的启动方式也是通过早期的方式优化过来的, 有一定的关联性。
  • 有很多老项目, 现在还在用这种init进程的启动方式。
  • 新的启动方式大规模使用的时间并不久, 也就在2018年左右才开始普及, 现在百度搜索linux系统的开机过程, 显示的几乎全部是init进程的启动方式。

linux系统的开机过程很重要, 但是真正重要的其实就那么几步。

alt text

早期开机过程 ​

我把开机过程分为了以下六个阶段:

一、从开机自检(BIOS)到加载内核阶段 ​

  • 这一阶段对应的知识我们完全不必掌握, 知道这是从开机到载入内核的过程就可以了
  • 注意: 这个不重要只是对我们想做C++后端的人来说, 对于做嵌入式的朋友, 这是绝对的核心, 如果是运维的话, 这些还是应该掌握的

二、启动init进程: ​

使用命令 ps -ef | more 查看进程

  • 这个进程是linux系统的第一个进程, PID为1, 又叫超级进程, 也叫根进程。
  • 负责产生其它所有的用户进程, 所有的进程都被挂在这个进程下, 如果这个进程退出了, 那么所有进程都会被kill。如果一个子进程的父进程退出了, 那么这个子进程会被挂到这个根进程下面。
  • linux又是以进程为最小执行单元的, 也就是说做任何事情都要依靠进程。从这里, 大家应该也能感觉到这个进程的重要性了

三、读取inittab ​

init进程在启动时会读取/etc/inittab, 接着根据该配置文件的启动层级和执行项来启动对应的程序。

以下的代码就是一个典型的inittab文件

# Default runlevel. The runlevels used by RHS 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:5:initdefault:

我们发现inittab文件其实很简单, 真正有用的其实就一行: id:5:initdefault

在讲解这一行代码前, 我们先介绍一下linux系统的运行级别, linux系统总共设置了7种运行级别, 不同的运行级别对应不同的执行方式。这7种运行级别分别是:

0级1级2级3级4级5级6级
关机单用户模式无网络的多用户模式多用户模式(无图形界面)未使用多用户模式(有图像界面)重启

以上的inittab文件表示init进程要启动的进程将会完成操作系统5级的功能。

四、执行系统初始化脚本(/etc/rc.d/rc.sysinit) ​

对linux系统一些必备的东西进行初始化, 比如时钟, 键盘, 磁盘, 文件系统等。

这个脚本比较长, 也比较复杂, 而且都是对系统级的操作, 没什么讲解的必要。就不讲解这个脚本的内容了。

五、执行启动层级对应的脚本(/etc/rc*.d) ​

linux系统不同的运行级别有不同的进程, 这些进程就要依靠这些脚本来启动。

比如: 在上面的例子中, /etc/inittab文件中记录的运行级别为: 5。所以, 由init进程执行/etc/rc5.d进程, 进行5运行级别必要的操作。

所以: 在早期, 如果有系统级的进程想要设置为开机启动, 就将启动该进程的命令放在该文件中。这种进程通常是一种服务, 至于什么是服务, 进程那里会详细讲解的。 后面有了service系统, 就不需要手动更改配置文件了。

六、不同的运行级别执行不同操作 ​

例如: 对于3级, 5级来说, 就是启动对应的终端。5级为图形终端, 3级为命令行终端。然后执行rc.local文件。

所以: 早期如果有什么用户级进程需要在系统启动时自动启动, 就添加到rc.local文件中。 后面有了service系统, 就不需要手动更改配置文件了。

总结早期linux启动过程:

  • 完成开机自检到加载内核阶段
  • 启动init进程负责产生其它所有的用户进程
  • 读取inittab 并根据配置的启动层级和执行项来启动对应的程序
  • 执行系统初始化脚本(rc.sysinit)
  • 根据启动层级启动对应对应的脚本(rc*.d)

现代开机方式 ​

现代的启动方式就是systemd系统。根据linux习惯, 字母d是守护(deamon)的缩写。systemd在名称上就是要守护整个linux系统的含义。

systemd系统极其庞大, 复杂。这里更多的是对systemd系统更多的是一个介绍 和 基本的设置。

systemd与早期的区别 ​

一、启动的进程将不再是/etc/init进程, 而是/lib/systemd/systemd。 ​
  • 我们使用命令 ps -ef | more 查看进程。看到pid为1的进程还是/sbin/init
  • 我们再使用命令ls -l /sbin/init输出/sbin/init -> /lib/systemd/systemd
  • 可以看到他只是个软链接罢了 真正pid为1的其实还是systemd进程
二、默认启动的系统级进程通过系统目录进行配置(代替/etc/inittab的配置方式) ​
优先级1级2级3级
配置目录/etc/systemd/system/run/systemd/system/lib/systemd/system

systemd根据优先级从高到低的从这些目录中读取配置文件。启动这些配置文件对应的进程。如果同一服务三个地方都配置了, 优先级高的会覆盖优先级低的。

  • 在安装好samba服务后, 系统会在/lib/systemd/system目录中添加一个默认的配置文件(smbd.service)。
  • 如果想自己设置配置文件, 只要在/etc/systemd/system目录下添加自定义的配置文件
  • 这样就将/lib/systemd/system目录下的配置文件覆盖掉了。
  • 至于/run/systemd/system是系统用来配置的, 我们不需要去管。
三、apt list ​
  • apt list:查看可以下载的所有包
  • apt list --installed:查看已经被下载的所有包
  • apt list --installed | grep samba:正则表达式查看被下载的相关samba包
  • apt list --installed 2> /dev/null | grep samba:重定向把error和warning扔到null里
四、重定向 ​
重定向>>>2>
作用覆盖文件内容文件末尾追写只输入error和warining 剩下的原位置输出

systemd配置文件 ​

现在大家只要知道一个服务的配置文件有三块就可以了, 具体表示什么, 如果之后用到了配置服务的情况, 再详细讲解。到时有了例子, 也好讲多了。

部分unit块service块install块
作用启动顺序与依赖关系启动行为定义如何安装这个配置文件, 即如何做到开机自启

systemd优势 ​

systemed系统功能强大, 使用简单。systemd系统可以对这些配置文件按照固定的格式优化, 比如可以让多个服务同时启动, 大幅提高服务启动效率。

init系统配置文件中仅仅是些让脚本启动的命令, 脚本具体是什么格式完全由开发人员确定。这就导致整个系统难以优化, 各种服务只能线性的依次启动, 效率很低。

systemed系统组成 ​

systemed系统 缺点就是体系庞大, 十分复杂

单元unitscopeslicesnapshotsocketswaptimer
作用路径不是由systemd启动的外部进程进程组systemd快照套接字文件交换
单元unitserveicetargetdevicemountautomountpath
作用服务运行级别设备文件系统的挂载点自动挂载点路径

当然不需要全部掌握, 否则东西太多了, 每一个 unit 知识点都很多。实际上我们只需要掌握 service 单元就可以了。

可以去百度一下 timer unit 和 target unit , 这两个网络配置时也是会用到的

systemctl 命令 ​

systemctl 命令是 systemd 的主要命令, 可以用于管理服务单元。

  • systemctl enable httpd.service: 使某任务开机自启
  • systemctl disable httpd.service: 使某服务不开机自启
  • systemctl status httpd.service: 服务详细信息
  • systemctl list-units --type=service: 显示所有已经启动的服务
  • systemctl start httpd.service: 启动某服务
  • systemctl stop httpd.service: 停止某服务
  • systemctl restart httpd.service: 重启某服务