浅析Linux初始化init系统第一部分 – Sysvinit

浅析Linux初始化init系统第一部分 – Sysvinit

什么是Init系统

Linux操作系统的启动首先从BIOS开始,接下来进入boot loader,由bootloader载入内核,进行内核初始化。内核初始化的最后一步就是启动pid为1init进程。这个进程是系统的第一个进程,它负责产生其他所有用户进程。

init以守护进程方式存在,是所有其他进程的祖先。init 进程非常独特,能够完成其他进程无法完成的任务。

Init系统能够定义、管理和控制init进程的行为。它负责组织和运行许多独立的或相关的始化工作(因此被称为init系统),从而让计算机系统进入某种用户预订的运行模式。

仅仅将内核运行起来是毫无实际用途的,必须由init系统将系统代入可操作状态。比如启动外壳shell后,便有了人机交互,这样就可以让计算机执行一些预订程序完成有实际意义的任务。或者启动X图形系统以便提供更佳的人机界面,更加高效的完成任务。这里,字符界面的shell或者X系统都是一种预设的运行模式。

大多数Linux发行版的init系统是和SystemV相兼容的,被称为sysvinit。这是人们最熟悉的init系统。一些发行版如Slackware采用的是BSD风格Init系统,这种风格使用较少,本文不再涉及。其他的发行版如Gentoo是自己定制的。Ubuntu和RHEL采用upstart替代了传统的sysvinit。而Fedora从版本15开始使用了一个被称为systemd的新init系统。

可以看到不同的发行版采用了不同的init实现,本系列文章就是打算讲述三个主要的Init系统:sysvinit,UpStart和systemd。了解它们各自的设计特点,并简要介绍它们的使用。

在Linux主要应用于服务器和PC机的时代,SysVinit运行非常良好,概念简单清晰。它主要依赖于Shell脚本,这就决定了它的最大弱点:启动太慢。在很少重新启动的Server上,这个缺点并不重要。而当Linux被应用到移动终端设备的时候,启动慢就成了一个大问题。为了更快地启动,人们开始改进sysvinit,先后出现了upstart和systemd这两个主要的新一代init系统。Upstart已经开发了8年多,在不少系统中已经替换sysvinit。Systemd出现较晚,但发展更快,大有取代upstart的趋势。

Sysvinit概况

sysvinit就是systemV风格的init系统,顾名思义,它源于SystemV系列UNIX。它提供了比BSD风格init系统更高的灵活性。是已经风行了几十年的UNIXinit系统,一直被各类Linux发行版所采用。

运行级别

Sysvinit用术语runlevel来定义“预订的运行模式”。Sysvinit检查/etc/inittab文件中是否含有initdefault项。这告诉init系统是否有一个默认运行模式。如果没有默认的运行模式,那么用户将进入系统控制台,手动决定进入何种运行模式。

sysvinit中运行模式描述了系统各种预订的运行模式。通常会有8种运行模式,即运行模式0到6和S或者s(其实S或s就是single,它与级别1是一样的,S或s相当于是级别1的别名,所以实际上只有7种级别,并非8种)。

每种Linux发行版对运行模式的定义都不太一样。但0/1/6却得到了大家的一致赞同:

  • 0 关机
  • 1 单用户模式
  • 6 重启

通常在/etc/inittab文件中定义了各种运行模式的工作范围。比如RedHat定义了runlevel 3和5。运行模式3将系统初始化为字符界面的shell模式;运行模式5将系统初始化为GUI模式。无论是命令行界面还是GUI,运行模式3和5相对于其他运行模式而言都是完整的正式的运行状态,计算机可以完成用户需要的任务。而模式1,S等往往用于系统故障之后的排错和恢复。

很显然,这些不同的运行模式下系统需要初始化运行的进程和需要进行的初始化准备都是不同的。比如运行模式3不需要启动X系统。用户只需要指定需要进入哪种模式,sysvinit将负责执行所有该模式所必须的初始化工作。

sysvinit运行顺序

Sysvinit巧妙地用脚本,文件命名规则和软链接来实现不同的runlevel。首先,sysvinit需要读取/etc/inittab文件。分析这个文件的内容,它获得以下一些配置信息:

  • 系统需要进入的runlevel
  • 捕获组合键的定义
  • 定义电源fail/restore脚本
  • 启动getty和虚拟控制台

得到配置信息后,sysvinit顺序地执行以下这些步骤,从而将系统初始化为预订的runlevelX。

  • /etc/rc.d/rc.sysinit
  • /etc/rc.d/rc 和/etc/rc.d/rcX.d/ (X 代表运行级别 0-6)
  • /etc/rc.d/rc.local
  • X Display Manager(如果需要的话)

首先,运行rc.sysinit以便执行一些重要的系统初始化任务。在RedHat公司的RHEL5中(RHEL6已经使用upstart了),rc.sysinit主要完成以下这些工作。

  • 激活udev和selinux
  • 设置定义在/etc/sysctl.conf 中的内核参数
  • 设置系统时钟
  • 加载keymaps
  • 使能交换分区
  • 设置主机名(hostname)
  • 根分区检查和remount
  • 激活RAID和LVM设备
  • 开启磁盘配额
  • 检查并挂载所有文件系统
  • 清除过期的locks和PID文件

完成了以上这些工作之后,sysvinit开始运行/etc/rc.d/rc脚本。根据不同的runlevel,rc脚本将打开对应该runlevel的rcX.d目录(X就是runlevel),找到并运行存放在该目录下的所有启动脚本。每个runlevelX都有一个这样的目录,目录名为/etc/rc.d/rcX.d。

在这些目录下存放着很多不同的脚本。文件名以S开头的脚本就是启动时应该运行的脚本,S后面跟的数字定义了这些脚本的执行顺序。在/etc/rc.d/rcX.d目录下的脚本其实都是一些软链接文件,真实的脚本文件存放在/etc/init.d目录下。如下所示:

清单1.rc5.d目录下的脚本

[[email protected] ~]# ll /etc/rc5.d/
lrwxrwxrwx 1 root root 16 Sep  4  2008 K02dhcdbd -> ../init.d/dhcdbd
....(中间省略)....
lrwxrwxrwx 1 root root 14 Sep  4  2008 K91capi -> ../init.d/capi
lrwxrwxrwx 1 root root 23 Sep  4  2008 S00microcode_ctl -> ../init.d/microcode_ctl
lrwxrwxrwx 1 root root 22 Sep  4  2008 S02lvm2-monitor -> ../init.d/lvm2-monitor
....(中间省略)....
lrwxrwxrwx 1 root root 17 Sep  4  2008 S10network -> ../init.d/network
....(中间省略)....
lrwxrwxrwx 1 root root 11 Sep  4  2008 S99local -> ../rc.local
lrwxrwxrwx 1 root root 16 Sep  4  2008 S99smartd -> ../init.d/smartd

当所有的初始化脚本执行完毕,Sysvinit开始运行/etc/rc.d/rc.local脚本。

rc.local是Linux留给用户进行个性化设置的地方。您可以把自己私人想设置和启动的东西放到这里,一台Linux Server的用户一般不止一个,所以才有这样的考虑。

Sysvinit和系统关闭

Sysvinit不仅需要负责初始化系统,还需要负责关闭系统。在系统关闭时,为了保证数据的一致性,需要小心地按顺序进行结束和清理工作。

比如应该先停止对文件系统有读写操作的服务,然后再umount文件系统。否则数据就会丢失。

这种顺序的控制这也是依靠/etc/rc.d/rcX.d/目录下所有脚本的命名规则来控制的,在该目录下所有以 K 开头的脚本都将在关闭系统时调用,字母 K 之后的数字定义了它们的执行顺序。

这些脚本负责安全地停止服务或者其他的关闭工作。

Sysvinit的管理和控制功能

此外,在系统启动之后,管理员还需要对已经启动的进程进行管理和控制。原始的sysvinit软件包包含了一系列的控制启动,运行和关闭所有其他程序的工具。

halt:停止系统。

init:这个就是sysvinit本身的init进程实体,以pid 1身份运行,是所有用户进程的父进程,最主要的作用是在启动过程中使用/etc/inittab文件创建进程。

killall5:就是SystemV的killall命令。向除自己的会话(session)进程之外的其它进程发出信号,所以不能杀死当前使用的shell。

last:回溯/var/log/wtmp文件(或者-f选项指定的文件),显示自从这个文件建立以来,所有用户的登录情况。

lastb:作用和last差不多,默认情况下使用/var/log/btmp文件,显示所有失败登录企图。

mesg:控制其它用户对用户终端的访问。

pidof:找出程序的进程识别号(pid),输出到标准输出设备。

poweroff:等于shutdown -h –p,或者telinit 0。关闭系统并切断电源。

reboot:等于shutdown –r或者telinit 6。重启系统。

runlevel:读取系统的登录记录文件(一般是/var/run/utmp)把以前和当前的系统运行级输出到标准输出设备。

shutdown:以一种安全的方式终止系统,所有正在登录的用户都会收到系统将要终止通知,并且不准新的登录。

sulogin:当系统进入单用户模式时,被init调用。当接收到启动加载程序传递的-b选项时,init也会调用sulogin。

telinit:实际是init的一个连接,用来向init传送单字符参数和信号。

utmpdump:以一种用户友好的格式向标准输出设备显示/var/run/utmp文件的内容。

wall:向所有有信息权限的登录用户发送消息。

不同的Linux发行版在这些sysvinit的基本工具基础上又开发了一些辅助工具用来简化init系统的管理工作。比如RedHat的RHEL在sysvinit的基础上开发了initscripts软件包,包含了大量的启动脚本(如rc.sysinit),还提供了service,chkconfig等命令行工具,甚至一套图形化界面来管理init系统。其他的Linux发行版也有各自的initscript或其他名字的init软件包来简化sysvinit的管理。

只要您理解了sysvinit的机制,在一个最简的仅有sysvinit的系统下,您也可以直接调用脚本启动和停止服务,手动创建inittab和创建软连接来完成这些任务。因此理解sysvinit的基本原理和命令是最重要的。您甚至也可以开发自己的一套管理工具。

Sysvinit 的小结

Sysvinit的优点是概念简单。Service开发人员只需要编写启动和停止脚本,概念非常清楚;将service添加/删除到某个runlevel时,只需要执行一些创建/删除软连接文件的基本操作;这些都不需要学习额外的知识或特殊的定义语法(UpStart和Systemd都需要用户学习新的定义系统初始化行为的语言)。

其次,sysvinit的另一个重要优点是确定的执行顺序:脚本严格按照启动数字的大小顺序执行,一个执行完毕再执行下一个,这非常有益于错误排查。UpStart和systemd支持并发启动,导致没有人可以确定地了解具体的启动顺序,排错不易。

但是串行地执行脚本导致sysvinit运行效率较慢,在新的IT环境下,启动快慢成为一个重要问题。此外动态设备加载等Linux新特性也暴露出sysvinit设计的一些问题。针对这些问题,人们开始想办法改进sysvinit,以便加快启动时间,并解决sysvinit自身的设计问题。

接下来请看第二部分:浅析Linux初始化init系统第二部分 – UpStart

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

浅析Linux初始化init系统第一部分 – Sysvinit