本文讲述了从按下开机按钮到ubuntu(14.04 LTS)启动完毕的过程。grub 入门知识和设置进程开机启动方法。

计算机启动

主要分为4个步骤

  1. 加载BIOS
    上个世纪70年代初,”只读内存”(read-only memory,缩写为ROM)发明,开机程序被刷入ROM芯片,计算机通电后,第一件事就是读取它。
    这块芯片里的程序叫做”基本輸出輸入系統”(Basic Input/Output System),简称为BIOS。
    BIOS程序首先检查,计算机硬件能否满足运行的基本条件,这叫做”硬件自检”(Power-On Self-Test),缩写为POST。
    硬件自检完成后,BIOS把控制权转交给下一阶段的启动程序。这时,BIOS需要知道,”下一阶段的启动程序”具体存放在哪一个设备。也就是说,BIOS需要有一个外部储存设备的排序,排在前面的设备就是优先转交控制权的设备。这种排序叫做”启动顺序”(Boot Sequence)。
    打开BIOS的操作界面,里面有一项就是”设定启动顺序”。
  2. 读取MBR
    BIOS按照”启动顺序”,把控制权转交给排在第一位的储存设备。
    这时,计算机读取该设备的第一个扇区,也就是读取最前面的512个字节。如果这512个字节的最后两个字节是0x55和0xAA,表明这个设备可以用于启动;如果不是,表明设备不能用于启动,控制权于是被转交给”启动顺序”中的下一个设备。
    这最前面的512个字节,就叫做”主引导记录”(Master boot record,缩写为MBR)。
    “主引导记录”只有512个字节,放不了太多东西。它的主要作用是,告诉计算机到硬盘的哪一个位置去找操作系统。
    主引导记录由三个部分组成:
    (1) 第1-446字节:调用操作系统的机器码。
    (2) 第447-510字节:分区表(Partition table)。
    (3) 第511-512字节:主引导记录签名(0x55和0xAA)。
    其中,第二部分”分区表”的作用,是将硬盘分成若干个区。
  3. Bootloader
    在这种情况下,计算机读取”主引导记录”前面446字节的机器码之后,不再把控制权转交给某一个分区,而是运行事先安装的”启动管理器”(boot loader),由用户选择启动哪一个操作系统。
    Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。
    Boot Loader有若干种,其中Grub、Lilo和spfdisk是常见的Loader。Linux环境中,目前最流行的启动管理器是Grub。
  4. 加载内核
    内核的加载请见后文grub入门部分。
    内核加载后,接开始操作系统初始化,根据进程的优先级启动进程。详细请见下文。

参考网址:

  1. ubuntu启动过程,操作系统启动讲解没细讲
  2. 计算机启动过程

操作系统的启动

linux操作系统有3中方式:System V init,upstart,systemd
虽然本文讲述ubuntu 14.04 LTS启动过程,但查询过程中看到了其他操作系统的启动过程,这里也顺带讲述一下。

System V init 启动方式

Debian System V 启动过程:
内核文件加载以后,就开始运行第一个程序 /sbin/init,它的作用是初始化系统环境。
由于init是第一个运行的程序,它的进程编号(pid)就是1。其他所有进程都从它衍生,都是它的子进程。

许多程序需要开机启动。它们在Windows叫做”服务”(service),在Linux就叫做”守护进程”(daemon)。
init进程的一大任务,就是去运行这些开机启动的程序。但是,不同的场合需要启动不同的程序,比如用作服务器时,需要启动Apache,用作桌面就不需要。Linux允许为不同的场合,分配不同的开机启动程序,这就叫做”运行级别”(runlevel)。也就是说,启动时根据”运行级别”,确定要运行哪些程序。

Linux预置七种运行级别(0-6)。一般来说,0是关机,1是单用户模式(也就是维护模式),6是重启。运行级别2-5,各个发行版不太一样,对于Debian来说,都是同样的多用户模式(也就是正常模式)。
Debian init进程首先读取文件 /etc/inittab,它是运行级别的设置文件。如果你打开它,可以看到第一行是这样的:

id:2:initdefault:

对于CentOS系统来说: 

init程序类型:  
1. SysV: init, CentOS 5之前  
配置文件:/etc/inittab  
2. Upstart: init,CentOS6  
配置文件:/etc/inittab, /etc/init/*.conf  
3. Systemd:systemd, CentOS 7  
配置文件:/usr/lib/systemd/system;/etc/systemd/system  

initdefault的值是2,表明系统启动时的运行级别为2。如果需要指定其他级别,可以手动修改这个值。
那么,运行级别2有些什么程序呢,系统怎么知道每个级别应该加载哪些程序呢?……回答是每个运行级别在/etc目录下面,都有一个对应的子目录,指定要加载的程序。

/etc/rc0.d  
/etc/rc1.d  
/etc/rc2.d  
/etc/rc3.d  
/etc/rc4.d  
/etc/rc5.d  
/etc/rc6.d

上面目录名中的”rc”,表示run command(运行程序),最后的d表示directory(目录)。下面让我们看看 /etc/rc2.d 目录中到底指定了哪些程序。

$ ls  /etc/rc2.d  

README  
S01motd  
S13rpcbind  
S14nfs-common  
S16binfmt-support  
S16rsyslog  
S16sudo  
S17apache2  
S18acpid

可以看到,除了第一个文件README以外,其他文件名都是”字母S+两位数字+程序名”的形式。
字母S表示Start,也就是启动的意思(启动脚本的运行参数为start),如果这个位置是字母K,就代表Kill(关闭),即如果从其他运行级别切换过来,需要关闭的程序(启动脚本的运行参数为stop)。
后面的两位数字表示处理顺序,数字越小越早处理,所以第一个启动的程序是motd,然后是rpcbing、nfs……数字相同时,则按照程序名的字母顺序启动,所以rsyslog会先于sudo启动。
这个目录里的所有文件(除了README),就是启动时要加载的程序。如果想增加或删除某些程序,不建议手动修改 /etc/rcN.d 目录,最好是用一些专门命令进行管理(参考这里和这里)。

/etc/inittab文件相关知识

每一行定义一种action以及与之对应的process
id : runlevel : action : process

id:代表init的主要工作选项,只是简单代表说明
runlevel:在那些等级下运行
action: initdefault:代表默认的runlevel设置值
sysinit:代表系统初始化的操作选项
ctrlaltdel:代表ctrl+alt+del三个按键是否可以重新启动
wait:代表后面设置的命令项目必须要执行完毕才能继续下面的其他操作
respawn:代表后边字段的命令可以无限制的重新启动
process:可以进行的命令

前面提到,七种预设的”运行级别”各自有一个目录,存放需要开机启动的程序。
不难想到,如果多个”运行级别”需要启动同一个程序,那么这个程序的启动脚本,就会在每一个目录里都有一个拷贝。这样会造成管理上的困扰:如果要修改启动脚本,岂不是每个目录都要改一遍?
Linux的解决办法,就是七个 /etc/rcN.d(N 取0,1 … 6) 目录里列出的程序,都设为链接文件,指向另外一个目录 /etc/init.d ,真正的启动脚本都统一放在这个目录中。init进程逐一加载开机启动程序,其实就是运行这个目录里的启动脚本。

下面就是链接文件真正的指向。

$ ls -l /etc/rc2.d  

README  
S01motd -> ../init.d/motd  
S13rpcbind -> ../init.d/rpcbind  
S14nfs-common -> ../init.d/nfs-common  
S16binfmt-support -> ../init.d/binfmt-support  
S16rsyslog -> ../init.d/rsyslog  
S16sudo -> ../init.d/sudo  
S17apache2 -> ../init.d/apache2  
S18acpid -> ../init.d/acpid  

这样做的另一个好处,就是如果你要手动关闭或重启某个进程,直接到目录 /etc/init.d 中寻找启动脚本即可。比如,我要重启Apache服务器,就运行下面的命令:

$ sudo /etc/init.d/apache2 restart

  
/etc/init.d 这个目录名最后一个字母d,是directory的意思,表示这是一个目录,用来与程序 /etc/init 区分。

upstart 启动方式

可以看到在sysvinit中,服务是按照顺序来执行的,这很影响效率。另一方面,sysvinit中,服务是预设的,不能实时启动(比如在系统被挂载了一个磁盘的时候自动启动)。而Upstart可以解决这些问题。它是基于事件机制的,可以按需启动服务,性能和很多其他方面都比sysvinit强,所以upstart被后来的Ubuntu等linux发行版采用。

基于事件的 Upstart 是 /sbin/init 守护进程的替代品,它仅为在需要那些服务的时候启动服务而生,(或者当它们在运行时管理它们),以及处理发生的实践,因此 Upstart 优于基于依赖的 sysvinit 系统。

一开始它是为 Ubuntu 发行版开发的,但在红帽企业版 Linux 6.0 中得到使用。尽管希望它能在所有 Linux 发行版中替代 sysvinit,但它已经被 systemd 超越。2014 年 2 月 14 日,Mark Shuttleworth(Canonical Ltd. 创建者)发布声明之后的 Ubuntu 发行版采用 systemd 作为默认初始化守护进程。

由于 Sysv 启动脚本已经流行很长时间了,很多软件包中都包括了 Sysv 启动脚本。为了兼容这些软件, Upstart 提供了兼容模式:它可以运行保存在常用位置(/etc/rc.d/rc?.d, /etc/init.d/rc?.d, /etc/rc?.d或其它类似的位置)的Sysv 启动脚本。因此,如果我们安装了一个还没有 Upstart 配置脚本的软件,仍然可以用原来的方式启动它。

在Upstart中,程序执行单位被称作作业(Job),所有的init作业都必须放置于目录/etc/init/之下,使用Upstart自己的配置文件来描述Job内容。Upstart启动时,从 /etc/init/ 目录中读取各个Job的配置文件,获取所有Job。然后发出Startup信号,所有监听这个信号的作业会被执行。在作业执行过程中,作业本身也可以自己发出信号,其他监听这个信号的服务接着就会被启动执行。Upstart通过这样的方式来达到异步和实时控制作业的启动执行。

比如在我的博客服务器中(精简):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ls -lh /etc/init/
total 356K
(...)
-rw-r--r-- 1 root root 297 Feb 9 2013 cron.conf
-rw-r--r-- 1 root root 489 Nov 11 2013 dbus.conf
-rw-r--r-- 1 root root 273 Nov 19 2010 dmesg.conf
-rw-r--r-- 1 root root 1.4K Apr 11 2014 failsafe.conf
-rw-r--r-- 1 root root 267 Apr 11 2014 flush-early-job-log.conf
-rw-r--r-- 1 root root 1.3K Mar 14 2012 friendly-recovery.conf
-rw-r--r-- 1 root root 284 Jul 23 2013 hostname.conf
-rw-r--r-- 1 root root 557 Apr 16 2014 hwclock.conf
-rw-r--r-- 1 root root 444 Apr 16 2014 hwclock-save.conf
-rw-r--r-- 1 root root 579 Aug 26 2014 irqbalance.conf
-rw-r--r-- 1 root root 689 Apr 10 2014 kmod.conf
-rw-r--r-- 1 root root 268 Feb 21 2014 mountall-bootclean.sh.conf
-rw-r--r-- 1 root root 1.3K Feb 21 2014 mountall.conf
(...)
-rw-r--r-- 1 root root 1.8K Feb 19 2014 mysql.conf
-rw-r--r-- 1 root root 2.5K Mar 20 2014 networking.conf
-rw-r--r-- 1 root root 534 Feb 16 2014 passwd.conf
(...)
-rw-r--r-- 1 root root 661 Apr 11 2014 rc.conf
(...)
-rw-r--r-- 1 root root 1.6K Apr 11 2014 rc-sysinit.conf

这些”*.conf”都是作业配置文件,在这个文件中指出作业什么start,什么时候stop,主进程是什么等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
xxxx:/etc/init$ ls | xargs grep "startup"
friendly-recovery.conf:emits startup
friendly-recovery.conf: initctl emit startup
hostname.conf:# This task is run on startup to set the system hostname from /etc/hostname,
hostname.conf:start on startup
kmod.conf:start on (startup
mountall.conf:start on startup
plymouth-ready.conf:start on startup or started plymouth-splash
plymouth-upstart-bridge.conf:start on (startup
udev-fallback-graphics.conf:# We only want this job to happen once per boot, hence 'startup and ...'.
udev-fallback-graphics.conf:start on (startup and
udev-finish.conf:start on (startup
udevmonitor.conf:start on (startup
udevtrigger.conf:start on (startup

作业hostname、kmod、mountall等都会监听startup信号(start on EVENT这个指令表示在EVENT发生时启动该程序)。Startup收集作业配置信息完成后,会发出”startup”信号,这些作业就会被执行了。

你可能想,那其他程序怎么办?

其他程序会监听这些程序发射的事件信号,当该事件发生时,那些程序也会被执行。比如mountall这个job就会发射”filesystem”这些类似的基础事件信号,这个代表着文件系统已经就绪了,很多其他作业(比如networking)都是监听这个信号,这样一级一级传递,启动程序就会被按照事件发生顺序一级一级的启动执行了。

####兼容sysvinit

最开始我们说到Upstart是兼容sysvinit的,怎么做到的?

在/etc/init/下有两个重要的作业: 作业 rc-sysinit 和 作业 rc

我们看一下这两个文件内容:

作业rc-sysinit配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
XXXX:/etc/init$ cat rc-sysinit.conf
# rc-sysinit - System V initialisation compatibility
#
# This task runs the old System V-style system initialisation scripts,
# and enters the default runlevel when finished.
description "System V initialisation compatibility"
author "Scott James Remnant <scott@netsplit.com>"
start on (filesystem and static-network-up) or failsafe-boot
stop on runlevel
# Default runlevel, this may be overriden on the kernel command-line
# or by faking an old /etc/inittab entry
env DEFAULT_RUNLEVEL=2
emits runlevel
# There can be no previous runlevel here, but there might be old
# information in /var/run/utmp that we pick up, and we don't want
# that.
#
# These override that
env RUNLEVEL=
env PREVLEVEL=
console output
env INIT_VERBOSE
task
script
# Check for default runlevel in /etc/inittab
if [ -r /etc/inittab ]
then
eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="\1";/p' /etc/inittab || true)"
fi
# Check kernel command-line for typical arguments
for ARG in $(cat /proc/cmdline)
do
case "${ARG}" in
-b|emergency)
# Emergency shell
[ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin
;;
[0123456sS])
# Override runlevel
DEFAULT_RUNLEVEL="${ARG}"
;;
-s|single)
# Single user mode
[ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S
;;
esac
done
# Run the system initialisation scripts
[ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS
# Switch into the default runlevel
telinit "${DEFAULT_RUNLEVEL}"
end script

作业rc的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
XXXX:/etc/init$ cat rc.conf
# 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 <scott@netsplit.com>"
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
script
if [ "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" -o "$RUNLEVEL" = "6" ]; then
status plymouth-shutdown 2>/dev/null >/dev/null && start wait-for-state WAITER=rc WAIT_FOR=plymouth-shutdown || :
fi
/etc/init.d/rc $RUNLEVEL
end script

你不必看懂每个具体配置细节,只要知道这三个配置指令就可以了:

start on EVENT: 在EVENT发生的时候启动该作业
stop on EVENT: 在EVENT发生的时候停止改作业
script … end script: 作业运行主程序脚本内容
所以根据以上配置,Upstart兼容sysvinit的过程是这样的:

作业rc-sysinit在收到 “(filesystem and static-network-up) or failsafe-boot” 的信号之后由Upstart启动。一切正常的话,rc-sysinit通过telinit完成运行级别信号的发送。
作业rc在收到运行级别信号之后,由Upstart启动。然后rc通过运行/etc/init.d/rc $RUNLEVEL这个命令, 来完成/etc/rcN.d/下相应程序的启动。
这样,就完成了兼容sysvinit的过程。

所以,在Upstart之下,你可以有2种方式添加系统服务程序:
按照System V 规则编写服务,并置于相应位置。
编写Upstart作业配置文件,置于 /etc/init/ 目录之下。

参考网页 4 讲的很好。
Upstart 流程:

参考网址:

  1. linux System V init、upstart启动方式讲解
  2. Debian System V启动方式讲解
  3. CetnOS6启动流程以及LVM下的fstab及boot恢复实验
  4. 浅析 Linux 初始化 init 系统,第 2 部分: UpStart
  5. Upstart Intro, Cookbook and Best Practises

systemd 启动方式

怎么查看系统使用 init 还是 systemd 方式启动的?

2014 年 2 月 14 日,Mark Shuttleworth(Canonical Ltd. 创建者)发布声明之后的 Ubuntu 发行版采用 systemd 作为默认初始化守护进程。

systemd 是另外一个被多种主流 Linux 发行版采用的服务和系统管理器。它的目标是允许系统启动时多个任务尽可能并行(而 sysvinit 并非如此,sysvinit 一般比较慢,因为它每次只启动一个进程,而且会检查彼此之间是否有依赖,在启动其它服务之前还要等待守护进程启动),充当运行中系统动态资源管理的角色。

因此,服务只在需要的时候启动,而不是系统启动时毫无缘由地启动(为了防止消耗系统资源)。

要查看你系统中运行的原生 systemd 服务和 Sysv 服务,可以用以下的命令。

详细 systemd 启动信息请见参考网址2。

参考网址:

  1. 通过 SysVinit、Systemd 和 Upstart 管理系统自启动进程和服务
  2. 走进Linux之systemd启动过程

grub 入门

grub一个来自GNU项目的多操作系统启动程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。

系统的启动是从读取grub.cfg(Ubuntu下是grub.cfg,不同操作系统,类似功能的文件名可能是menu.lst或grub.lst)开始的,grub.cfg文件的位置是在/boot/grub目录下。如果电脑上安装的是双系统的话,也可以通过修改grub.cfg文件,改变系统的启动项的排列顺序、等待时间等。

将文件打开后文件中有这么一段:(一开始 Windows 7 是在最下面的,我把 Windows 7 那项剪切到Ubuntu 的下面,这样每次启动的时候基本上就只要在第一第二项选择了)

这是一个标准的ubuntu引导菜单,menuentry那一行显示了该项目的名称,insmod是Linux下的指令,是加载模块的意思。

我们已经知道,IDE接口的硬盘是hd表示,SATA和SCSI接口的硬盘都是sd表示,那为什么grub文件有一行“setroot=’(hd0,8)’”代码呢?不应该是“sd”吗?通过在网上查找的相关资料,对于grub文件来说,硬盘都是用hd表示的,磁盘号是从0开始计算的,分区号是则是从1开始计算的(grub2是从1开始计算的,grub1是从0开始计算的),而对于Linux内核来说,IDE硬盘是hd表示的,SATA硬盘是用sd表示的,磁盘序号从a开始计算的,分区号是从1开始计算的。我电脑中的Linux系统是 Ubuntu 12.04 LTS 版本,grub文件是grub2版本。所以grub文件中的(hd0,8)代表的是第一块硬盘上的第八个分区即sda8。

search指令是寻找内核的意思,这就真正进入了Linux系统的引导过程,内核的存放位置是在/boot目录下。下面一行中的linux是一个指令,它告诉grub程序使用后面给出的内核,于是这个名为“vmlinuz-3.5.0-40-generic”的内核就被载入内存,并读取“root=UUID=abdb3fa2-45cd-447d-8cc5-83cf326195bd”这个分区的一些必要的文件。

第一个启动项的最后一行的命令的意思是:用名为“/initrd.img-2.6.32-33-generic”的文件先在内存中构造一个“虚拟”的根文件系统,以便于内核检测完硬件信息后载入必需的模块等等。

grub的工作到此结束,下面将由Linux内核接管电脑的控制权,开始初始化阶段。

实验

删除挂载在逻辑卷的根下的/etc/fstab配置文件以及/boot/目录下的文件。手动修复。

1
2
3
4
5
6
mkdir /root/boot && mv /boot/* /root/boot #将boot下的所有文件移动到家目录下的boot中(boot需要创建)
sync*3 #同步数据到磁盘
reboot #重启
进入救援模式
df #查看挂载,发现并没有被挂载!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
ls /dev/mapper && #mapper是所有LVM存放的地方,我们可以查看有没有逻辑卷存在
lvdisplay #使用lvdisplay命令查看LVM状态,发现都是不可用状态,并且很用容易看出根目录在哪个逻辑卷中
vgchage -ay #激活vg,也就是激活逻辑卷
lvdisplay #再次确认LVM状态
ls /dev/mapper #查看LVM设备
mount /dev/mapper/VolGroup-lv_root /mnt/sysimage #根据查看到的信息将根挂载到/mnt/image(sysimage可以是其他挂载点)下 cd /mnt/sysimage #切换到操作系统根目录下
ls #查看是否是操作系统根目录
vi etc/fstab #在当前目录下的etc下创建fstab文件,注意是当前目录而不是/
:r! ls /dev/mapper #在末行模式下使用r!读取出LVM的名字
/dev/sda1 /boot ext4 defaults 0 0
/dev/mapper/VolGroup-lv_root / ext4 defaults 0 0
/dev/mapper/VolGroup-lv_swap swap swap defaults 0 0 #注意,所有的LVM信息都需要写入
wq #保存退出
sync*3 #同步磁盘,sync输入三次
exit #退出bash,进入菜单reboot重启,必须退出重启
进入救援模式
chroot /mnt/sysimage/ #切根
mount /dev/cdrom /mnt #挂载光盘到/mnt
rpm -ivh /mnt/Packages/kernel-2.6.32-642.e16.x886_64.rpm --force #安装kernel包
ls /boot #查看boot下文件是否恢复
grub-install /dev/sda #修复grub
退出并重启
在grub后输入
kernel /vmlinuz-2(tab补全) root=/dev/mapper/VoGroup-lv_root selinux=0
initrd /init(tab补全)
boot #启动
#注意,修复grub.conf文件时临时有效,如果想永久修复需要重新编辑/boot/grub/grub.conf
default=0
timeout=5
title CentOS68
kernel (hd0,0)/vmlinuz-.... ro root=/dev/vg0/root
initrd /initramfs-...img

参考网址:

  1. Grub.conf 配置文件的解释
  2. Ubuntu GRUB2配置文件”grub.cfg”详解(GRUB2实战手册)
  3. Grub 命令行配置启动参数
  4. 安装grub,制作启动盘
  5. Ubuntu的启动配置文件grub.cfg(menu.lst)设置指南
  6. linux制作grub.conf文件,启动系统
  7. 删除挂载在逻辑卷的根下的/etc/fstab配置文件以及/boot/目录下的文件

开机自启服务程序编写

Run level Name Description
0 Halt 关机时进入
1 Single-user mode 超级用户模式,在系统启动出出错、文件系统出错等情况下进入
2 Multi-User Mode(without networking) 多用户模式,如果你没有网络接口可以配置进入此模式
3 Multi-User Mode 多用户模式,我的服务器默认为此运行级别
4 Not used/user definable 保留,用户也可以使用该运行级别来自定义自己的需求
5 GUI mode 图形界面模式
6 Reboot 重启时进入
s or S Single-user/Maintenance mode 特殊用途

将一个编好的服务程序(作为守护进程存在,提供服务,比如nginx/sshd),作为固定服务加入系统中的话,在sysvinit中这样做就好了:

将服务脚本置于/etc/init.d/中。
在相关运行级别创建启动软连接,例如,开机自启的话,在/etc/rc2.d/、/etc/rc3.d/、/etc/rc5.d/中创建启动服务脚本的软连接(命名S开头)。
(optional)如果有需要的话,在相关运行级别创建停止服务软连接。
举例来说,假设是你编写了一个nginx的服务,现在要将其添加进系统启动服务中:

将服务程序置于/etc/init.d/nginx
在/etc/rc2.d/、/etc/rc3.d/、/etc/rc5.d/中创建启动软连接:

# ln -s /etc/init.d/nginx /etc/rc2.d/S20nginx  
# ln -s /etc/init.d/nginx /etc/rc3.d/S20nginx  
# ln -s /etc/init.d/nginx /etc/rc5.d/S20nginx  

在/etc/rc0.d/,/etc/rc1.d/,/etc/rc6.d/中,创建停止服务软连接:

# ln -s /etc/init.d/nginx /etc/rc0.d/K20nginx  
# ln -s /etc/init.d/nginx /etc/rc1.d/K20nginx  
# ln -s /etc/init.d/nginx /etc/rc6.d/K20nginx  

这样,当系统启动的时候,就会启动nginx,而关机、重启的时候,会stop nginx。

service 命令理解

这里介绍一下我们常用的service命令到底怎么回事。

语法:

service SCRIPT COMMAND [OPTIONS]

这个命令的作用是: 运行一个sysvinit 程序或Upstart作业!,所以其是一个既支持Upstart作业,又支持sysvinit程序的命令。运行时,service首先从/etc/init.d/中去找SCRIPT,如果没找着再去/etc/init/目录下去找同名作业配置文件。然后运行这些程序/作业。

需要注意的是,service命令和/etc/rcN.d/这个目录没有任何关系。

例子:

service nginx start # 启动nginx服务
service nginx stop  # 停止nginx服务
service nginx restart # 重启nginx服务

在运行时,COMMAND 和 OPTTIONS都会被完整的传递给SCRIPT。故service nginx start其实最终执行的命令是/etc/init.d/nginx start,”start”这个操作,并不是由service来完成,service仅仅是起到一个寻找脚本位置的作用而已!

参考网址:

  1. linux System V init、upstart启动方式讲解
本文总阅读量次.

留言