一、Init程序
Init是位于/sbin/init的程序。是在linux系统启动过程中,初始化所有设备驱动程序和数据结构之后,由内核启动的一个用户级程序,并由此 Init 程序完成系统启动过程。
Init 程序主要有 Sysvinit 、Upstart 、Systemd 。新的 Init 程序的目标:1.希望更多的开机程序是并行开启的,而不是串行(即依赖shell脚本,并大量串行的
执行启动脚本,比如 Sysvinit); 2. 希望开机执行的程序越少越好、进入工作状态越快越好。
(一)、sysvinit
1. 运行级别
sysvinit 是较早使用的 Init 程序,基于运行级别。系统以何种运行级别启动由Init读取 /etc/inittab 文件中的缺省级别设置来确定。运行级别定义具体如下:
0 => 关机(halt)
1 => 单用户模式(single)
2 => 多用户
3 => 完整的多用户模式(标准的运行级)
4 => 系统保留
5 => 完整的多用户,使用 X11 (x window)
6 => 重启(reboot)
Ubuntu 默认是没有 /etc/inittab 文件的,且运行级别的定义也有不同,具体如下:
0 => 关闭系统(halt)
1 => 单用户模式(single)
6 => 重启(reboot)
2,3,4,5 => 多用户模式(multi-user)
2. 服务启动
启动与关闭服务的脚本存放在 /etc/rc[?].d 目录下。其中 [x] 表示0~6,分别对应级别0~6。/etc/rcS.d/ 路径下的脚本会先于 /etc/rc[?].d/ 执行。/etc/rc.local 会在 /etc/rc[?].d/
路径下的脚本执行完成后,最后执行。例如:运行级别为2,将执行 /etc/rc2.d/ 下的脚本。其中的脚本命名方式:K开头(k=>kill)、S开头(S=>start)。K、S 后面跟着的
数字代表执行优先级,数字越小,执行顺序越高(优先执行,比如K15 优先于K20被执行)。当执行K 开头的脚本,比如,K20acpid 会执行 /etc/init.d/acpid脚本,并给脚本
传递一个stop参数,指示其关闭 acpi daemon 服务。S 开头的会传递 start参数,指示其开启服务。而且 /etc/rc[?].d/ 下面的脚本都是软链接,指向 /etc/init.d/ 中真正的执行
脚本。若想要添加用户自定义的服务,需要将自定义服务的启动脚本放到 /etc/init.d/ 路径下,并且在对应的运行级别目录下为其添加软链接即可。
命令:service 服务名 start | stop | restart 或者 /etc/init.d/ 服务名 start | stop | restart
服务管理工具:chkconfig sysv-rc-conf
注:在Ubuntu 中系统定义的服务存放在 /etc/services 文件中。部分非常驻服务由 xinetd 服务控制。xinetd服务配置文件保存在 /etc/xinetd.conf 。例如 Telnet 服务就是
由xinetd 代理服务的。
3. Init 执行流程
sysvinit 时代 Linux 启动流程:
1. BIOS
2. MBR
3. Grub
4. Linux-Kernel
5. Init
a. 运行 /sbin/init
b. 读取 /etc/inittab(该文件定义了运行级别,在Ubuntu中演变为 /etc/init/rc-sysinit.conf)
c. 执行 /etc/rc.d/rc-sysinit (Ubuntu中是 /etc/init/rc-sysinit.conf)
d. 执行 /etc/rcS.d/ 目录下的脚本
e. 切换到默认的运行级别执行(Ubuntu默认执行 " env DEFAULT_RUNLEVEL=2 " telinit "${DEFAULT_RUNLEVEL}" )
执行 /etc/rc2.d/ 目录下的脚本
f. 执行 /etc/rc.local (用户自定义的开机服务可放到该脚本中)
g. 执行 /bin/login (此时,已完成 Init 全过程)
6. 完成系统初始化,用户登录。
(二)、Upstart(Upstart init daemon)
1. 事件和作业
事件:
Upstart init daemon 是 sysv init daemon 的替代者,基于事件而非运行级别(并行启动部分服务)。可在系统启动、关闭、任务状态改变时启动或关闭服务。
事件就是 Init 得到的关于服务状态的变更信息。用户可通过 initctl emit 命令来手动触发一个事件,但通常情况下,事件是自动触发的。
Upstart的三种事件类型:Signal Event:异步且非阻塞的、Method Event:同步且阻塞的、Hook Event:同步且阻塞的。
Upstart的三个主要进程:
1)init: upstart 主进程(PID=1)。职责是读取配置文件,处理各种服务和应用程序的依赖关系。根据事件来启动这些功能和服务,并动态的进行管理。
2)initctl: Upstart 事件管理器。可被应用程序用来通知 init 哪些事件发生。initctl list 可类比 Sysvinit 的 chkconfig工具。
3)telinit: 管理运行级别。要研究 Upstart 是如何兼容 sysvinit 的,就要从telinit入手。
附:/etc/init/rc-sysinit.conf 脚本中 telinit 的使用(省略部分,只留下关键的):
作业(Job):
job是 Init 可以理解的一系列指令。用户可以用 initctl start 和 initctl stop 命令手动启动或终止一项工作。作业有10种状态,此处不赘述。
分类:1) 任务(Task):运行、并在执行结束后返回到等待状态的工作;
2) 服务(Services):通常不会自己结束到工作;
3) 抽象作业(Abstact job):只存在于 Upstart 内部。没有PID,定义 “永久运行” 的作业。
2. 服务启动
Upstart 的所有服务放在 /etc/init/ 目录下,以服务名.conf 文本文件存放。*.conf 配置文件中:
start on、stop on: 服务的依赖关系;
exec: 服务启动命令;
respawn :设置服务异常停止后服务自动重启;
script ... end script :服务启动前后执行脚本(参看作业的10种状态);
说明:要在开机启动自定义服务,只要向 /etc/init/ 中添加 自定义服务.conf 配置文件即可。
命令/工具:initctl list=>查看所有服务状态 initctl start | stop | restart 服务名
3. Init 执行流程
upstart 下 Init 执行流程:
1. BIOS
2. MBR
3. Grub
4. Linux-Kernel
5. Inita. 运行 /sbin/init
b. Upstart 内部初始化,触发 startup 事件
c. 触发依赖 startup 事件的服务,主要包括挂载文件系统、本地回环网络(即定义了 start on startup 的服务脚本)
d. 触发 rc-sysinit 事件(/etc/init/rc-sysinit.conf ),首先执行 /ec/rcS.d/目录下的脚本(事实上,此后的过程与sysvinit 执行过程类似)
e. 切换到默认的运行级别执行脚本。例如:/etc/rc2.d/ 目录下的脚本(Ubuntu 默认是 " env DEFAULT_RUNLEVEL=2 " telinit "${DEFAULT_RUNLEVEL}" )
f. 执行 /etc/rc.local
g. 执行 /bin/login(完成init过程)
6. 完成系统初始化,用户登录。
说明:很多细节的东西还是有待研究,放到实际应用的场合学习、理解可能效果更好。
(三)、Systemd
1. 基本概念及原理
systemd 同样是 sysv init daemon 的替代者。特点是与 sysvinit 完全兼容、更清晰的服务依赖关系、开机系统初始化服务并行启动、更少的shell开销。每个服务就是
一个 unit,对应于运行级别,systemd有一个 target (multi-user.target)。这当然要比 Upstart 做的更彻底,还记得本文开头说的,Init设计的两个目标吗?
FedoraProject 官网对 Systemd 的介绍(Fedora已经使用systemd作为默认的Init):
systemd 是 Linux 下一个与 SysV 和 LSB 初始化脚本兼容的系统和服务管理器。systemd 使用 socket 和 D-Bus 来开启服务,提供基于守护进程的按需启动策略,
保留了 Linux cgroups 的进程追踪功能,支持快照和系统状态恢复,维护挂载和自挂载点,实现了各服务间基于从属关系的一个更为精细的逻辑控制,拥有前卫的并行
性能。systemd 无需经过任何修改便可以替代 sysvinit 。
2. 服务启动
服务配置文件放在 /lib/systemd/system/ 目录下,以 *.service命名。没有运行级别的概念,但是完全兼容sysvinit。
rsyslog.service文件格式:
[Unit]
Description=System Logging Service
[Service]
ExecStartPre=/bin/systemctl stop systemd-kmsg-syslogd.service
ExecStart=/usr/sbin/rsyslogd -n -c5
Sockets=syslog.socket
StandardOutput=null
[Install]
WantedBy=multi-user.target
命令:systemctl enable | disable *.service => 设置服务 自动启动 | 非自动启动
systemctl start | stop | restart *.service => 服务启动 | 停止 | 重启
systemctl status *.service => 查看服务状态
工具:systemadm => 一个图形化的管理工具
3. Init 执行流程
Systemd init 执行流程:
附:linux2.6.32.61内核启动时的一段代码 ( /init/main.c ),说明 kernel 与/sbin/init 的关系。
init是Linux系统操作中不可缺少的程序之一。
所谓的init进程,它是一个由内核启动的用户级进程。
内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。所以,init始终是第一个进程(其进程编号始终为1)。
内核会在过去曾使用过init的几个地方查找它,它的正确位置(对Linux系统来说)是/sbin/init。如果内核找不到init,它就会试着运行/bin/sh,如果运行失败,系统的启动也会失败。
Linux执行完一些初始化以后,第一个启动init进程。init进程是所有进程的父进程,负责启动其它进程,这些进程大多数是服务进程(daemon)。随着时间的推移这个启动过程也在变化。但目前主要有两种:System V style的runlevel式启动和upstart代表的event-based启动。
init进程会读取/etc/inittab来决定进入哪一个runlevel。
/sbin/init => /etc/inittab => runlevel rc script [/etc/rcN.d]
runlevel有些类似Windows中你按下F8进入的安全模式,但比Windows划分的更细,除此之外你还可以通过配置决定每个runlevel加载一些什么服务。不同的Linux发行版对runlevel的解释会有所不同,但runlevel思想是一样的:init通过/etc/inittab决定它的runlevel,然后去/etc/rcN.d/(N代表runlevel的数字表示)去找相应的启动脚本。
通过/etc/inittab的启动已经不能满足当前的需要了,比如支持一些热插拔设备。一种event-based的init启动产生了。ubuntu中就是使用upstart来启动系统的。upstart使用/etc/init/目录来决定系统在启动时运行那些服务。你可以通过intctrl来控制upstart启动的服务。
你若查看/etc/init/目录,你可以看见一个为rc.conf的脚本,这个脚本起到的作用就是对system v style runlevel的模拟。我们看下这个脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# rc - System V runlevel compatibility
#
# This task runs the old System V-style rc script when changing between
# runlevels.
description
"System V runlevel compatibility"
author
"Scott James Remnant
emits deconfiguring-networking
emits unmounted-remote-filesystems
start on runlevel [0123456]
stop on runlevel [!$RUNLEVEL]
export
RUNLEVEL
export
PREVLEVEL
console output
env
INIT_VERBOSE
task
exec
/etc/init
.d
/rc
$RUNLEVEL
|
这个脚本通过执行/etc/init.d/rc $RUNLEVEL来运行具体的rc script。这些rc script在/etc/rcN.d/目录下。由此完成了对system v style runlevel的模拟。
不仅如此,ubuntu还提供了update-rc.d命令,你可以通过此命令来完成system v style runlevel启动脚本的配置。比如你想在启动时不启动apache:
update-rc.d apache2 disable
ubuntu将所有启动脚本放在/etc/init.d/这个目录下,当你运行update-rc.d命令时update-rc.d会根据你的参数新建一些symbol link到相应的/etc/rcN.d/目录。