免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1281 | 回复: 0
打印 上一主题 下一主题

Upstart: Ubuntu 的基于事件的启动进程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-20 09:26 |只看该作者 |倒序浏览

在Ubuntu中,inittab软件包已经被
Upstart
软件包替换了,所有的配置信息都在/etc/event.d/目录下。
******************************************************************
By
Mark Sobell
on February 08, 2008 (9:00:00 AM)
原文链接:http://www.linux.com/feature/125977
翻译时间:2008年3月7日
译者:王旭(gnawux at gmail.com)
译注:尽管译者是一位铁杆的Debian粉丝,但也注意 upstart 很久了,就译者本人观点,upstart 应该说是
Ubuntu 所做的众多工作中最为杰出的一个,它将可以极大地加快 Linux 系统启动的过程。尽管它不是惟一的下一代 init
程序,但它已经作为 Ubuntu 的缺省 init 进程工作了相当长的时间,这点将极大有助于程序的成熟;而且,upstart
使用了基于事件的模型,而不是简单的将各个 daemon 并行化,这个架构上的突破也是具有革命性的,下面我们来看这篇文章吧。
因为传统的System V 的 init daemon (Sysvinit)无法很好地处理现代硬件,如热插拔设备、USB硬盘或山村、网络文件系统等,Ubuntu 使用了
Upstart
init daemon。
本文抽取自最近出版的
A Practical Guide to Ubuntu Linux
.
目前已经有多种 sysvinit 的替代产品了,这其中最为著名的一个就是
initng

它已经可以用于 Debian 了,并且在 Ubuntu 上也能工作。在同一位置上,Solaris 使用 SMF (Service
Management Facility),而 Mac OS 则使用 launchd。而 Ubuntu 则更倾向于集这些软件的优点于一身。
Sysvinit daemon 是一个基于运行级别的初始化程序,它使用了运行级别(如单用户、多用户等)并通过从 /etc/rc?.d 目录到
/etc/init.d 目录的初始化脚本的链接来启动与终止系统服务。自从 Feisty 开始,Ubuntu 转向了 Upstart init
daemon,并开始将Sysvinit 设置转换为 Upstart 的设置。本文探讨 Upstart 和残存的部分 Sysvinit
遗迹:/etc/rc?.d 和 /etc/init.d 目录以及运行级别的概念。
Upstart init daemon
是基于事件的,当系统中的什么情况发生变化时,它会运行某个特定的程序。这里被运行的程序多半是用来启动或终止服务的脚本。这个配置方式和systemv
在系统进入某个运行级别的时候运行init脚本的链接的概念实际上是非常类似的,只不过 upstart 更加灵活一些。Upstart
不仅能在运行级别改变的时候启动或终止服务,也能在接收到系统发生其他改变的信息的时候启动或终止服务。这些系统的改变被称为“事件”。例如,当
upstart 从 udev 接收到运行时文件系统加载、打印机安装或其他类似的设备添加或删除的信息,并采取相应的行动。Upstart
也可以在系统启动、关闭或某个任务状态改变的时候启动或关闭服务。
Upstart由五个包组成,(Ubuntu 中)它们都会被缺省安装:
  • upstart 提供Upstart init daemon 和 initctl 工具。
  • upstart-logd 提供 logd daemon 和 logd 服务的工作定义文件。
  • upstart-compat-sysv 提供了 rc 任务的工作定义文件,并提供了 reboot, runlevel, shutdown, telinit 等工具,以便与 sysvinit 相兼容。
  • startup-tasks 提供了系统启动任务的工作定义文件。
  • system-services 提供了 tty 服务的工作定义文件。

定义
有几个名词帮助我们理解 init 相关的东西。事件(event)是 init
可以得到的状态变更信息。几乎系统所有的内部或外部状态变更都可以触发一个事件。比如,引导程序会触发启动(startup)事件,系统进入运行级别2会
触发运行级别2(runlevel
2)事件,而文件系统加载则会触发路径加载(path-mounted)事件,拔掉或安装一个热插拔或USB设备(如打印机)也会触发一个时间。用户还可
以通过 initctl emit 命令来手动触发一个事件。
一个工作(job)是 init 可以理解的一系列指令。典型的指令包括一个程序(二进制文件或是脚本)和事件的名称。Upstart init
daemon 会在事件触发的时候运行相应的程序。用户可以分别用 initctl start 和 stop
命令手动启动或终止一项工作。工作又可以分为任务和服务。
任务是运行、并在执行结束后返回到等待状态的工作。
服务是那些通常不会自己结束的工作。比如,logd daemon 和 gettys 就被实现为服务。init daemon 会监测每个服务的状态,如果服务出现问题会重启服务,在某些事件触发时或手工停止时会杀死服务。
/etc/event.d 目录下包含着一系列的工作定义文件(定义了 upstart init daemon
运行的工作的文件)。最初,这个目录由 Upstart 包来生成。在 Feisty 之后的 Ubuntu
中,被安装的服务会向这个目录中添加控制服务的文件,替代哪些安装到 /etc/rc?.d 和 /etc/init.d 目录的文件。
Upstart init daemon 的核心是一个状态机。它持续跟踪各个工作的状态,当有事件触发的时候,跟踪工作的状态改变。当 init 跟踪到一个工作的状态从一个转变到了另一个的时候,就可能会执行工作的命令或是终止工作。
System V 的 init daemon 通过改变运行级别来启动或停止服务。而使用 Upstart init daemon 的
Ubuntu 系统没有运行级别的概念。为了将基于运行级别的系统平滑移植到基于事件的系统,并为面向其他发布版的软件提供一定的兼容性,Ubuntu
使用 Upstart 模拟了运行级别。
在 /etc/event.d/rc? 文件中定义的 rc? 工作会运行 /etc/init.d/rc 脚本,这个脚本会运行链接到
/etc/rc?.d 目录中的 /etc/init.d 中的启动脚本,以模拟 SysVinit 的行为。当系统进入一个运行级别的时候,rc?
工作就会运行这些脚本。同时,Upstart 提供了 runlevel 和 telinit 工具以提供与 SysVinit 的兼容性。
使用 initctl (init control) 工具,具有 root 权限的管理员可以和 Upstart init daemon
通信。这个工具可以用来启动、停止或报告(report)一项工作。 比如,initctl list 命令会列出所有的工作和它们的状态:
$ sudo initctl list
logd (stop) waiting
rc-default (stop) waiting
rc0 (stop) waiting

tty5 (start) running, process 4720
tty6 (start) running, process 4727
要获得更详细的信息,可以参考 initctl 的 man page 或本节的例子。使用 initctl help 命令 (help
前没有横杠)可以列出 initctl 的命令列表。此外,也可以用 initctl list –help 来列出 list
命令的帮助信息,当然,将 list 换乘其它的 initctl 命令会得到该命令对应的信息。start, stop 和 status 工具是
initctl 的链接,会直接运行 initctl 的对应命令。
工作(Job)
/etc/event.d 目录下的每个文件都定义了一个工作,其中至少应该包含一个事件和一个命令。当事件被触发的时候,init 执行对应的命令。本节将介绍管理员自定义的工作和 Upstart 包中包含的工作。
下面的管理员自定义的工作使用 exec 关键字执行了一条 shell 命令。实际上,也可以用这个关键字执行一个 shell 脚本或一个二进制可执行文件。
$ cat /etc/event.d/mudat
start on runlevel 2
exec echo “Entering multiuser mode on ” $(date) > /tmp/mudat.out
这个文件定义了一个任务:当系统进入到多用户模式(运行级2)的时候执行 echo 命令。这个命令会向 /tmp/mudat.out
文件写出一条包含日期时间消息。shell 会运行 date 命令替换其中的内容。在任务结束后, mudat 任务会停止并进入等待状态。
在下一个的例子中,cat 命令展示了 /tmp/mudat.out 文件的内容和 initctl list 命令关于这个任务的输出(status 工具也可以得到同样的信息):
$ cat /tmp/mudat.out
Entering multiuser mode on Tue Jul 10 17:34:39 PDT 2007
$ sudo initctl list mudat
mudat (stop) waiting
如果 exec 命令行中包含 shell 的特殊字符, init 会运行 /bin/sh(dash
的符号链接)并把命令行交给它来处理。否则,exec 会直接运行命令行。如果要执行多个 shell
命令,可以把他们放到脚本文件中并运行脚本,或是使用 script….end script (下面会介绍)。
Upstart initdaemon  只能监测哪些使用 exec 运行的工作(服务),无法监测使用 script…end script 运行的工作。换句话说,服务应该使用 exec 运行,而任务则可以使用任意的方法。
myjob 示例
用户也可以自己定义一个事件,并让一个工作被这个事件触发。如下的 myjob 工作定义文件定义了一个被 hithere 事件触发的工作:
$ cat /etc/event.d/myjob
start on hithere
script
        echo “Hi there, here I am!” > /tmp/myjob.out
        date >> /tmp/myjob.out
        end script
myjob 文件提供了另一种运行命令的方法:在 script 和 end script 关键字之间包含了两行命令。这两个关键字常常导致
init 去运行 /bin/sh。例中的命令将一条消息和日期输出到了 /tmp/myjob.out 文件。现在可以使用 initctl
emit 命令触发这个工作。如下,init 展示了 myjobs 在我们的触发下所经历的各个状态:
$ sudo initctl emit hithere
hithere
myjob (start) waiting
myjob (start) starting
myjob (start) pre-start
myjob (start) spawned, process 6064
myjob (start) post-start, (main) process 6064
myjob (start) running, process 6064
myjob (stop) running
myjob (stop) stopping
myjob (stop) killed
myjob (stop) post-stop
myjob (stop) waiting
$ cat /tmp/myjob.out
Hi there, here I am!
Sat Jul 7 20:19:13 PDT 2007
$ sudo initctl list myjob
myjob (stop) waiting
在上面的例子里,cat 展示了 myjob 产生的输出,initctl 展示了工作的状态。同样也可以用 initctl start
myjob(或直接用 start myjob)来运行它。initctl start
十个非常有用的命令,这样你就可以在没有事件的情况下启动一个工作。比如,你可以用 initctl start mudat 来直接运行前面例子中的
mudat 工作而不会触发 runlevel 2 事件。
指定带参数的事件
telinit 和 shutdown 工具发送带有参数的 runlevel 事件。比如,shutdown 发送 runlevel 0,telinit 2 会发送 runlevel 2 事件。你可以在工作定义中用如下格式匹配这些事件:
start | stop on event [arg]
其中 event 是一个事件,而 arg 是一个可选参数。要在系统进入 runlevel 2 的时候停止一个工作,可以指定 stop
on runlevle 2,也可以指定 runlevel [235] 来匹配运行级 2, 3 和 5,或用 runlevel [!2] 来匹配
2 之外的运行级。
尽管 Upstart 会忽略掉多余的事件参数,但工作定义文件中的事件名称里的参数必须在事件中存在。比如,没有参数的 runlevel
可以匹配所有的 runlevel 事件,不论是否有参数,但 runlevel S arg2 将不会匹配任何事件,因为 runlevel
事件只会带有一个参数。
/etc/event.d 中的工作定义文件
随着 Ubuntu 从 SysVinit 向 Upstart 的迁移,更多地工作会在 /etc/event.d 文件中定义。本节介绍一些 Upstart 包放在这个目录中的工作定义文件。
/etc/event.d/rc2 工作定义文件定义了 rc2 任务,这和其他的 rc? 任务没什么区别。rc2
任务在系统进入到多用户模式的时候会被触发(事件名称是 runlevel 2);当系统进入到其它任意运行级的时候(runlevel
[!2])会结束。脚本的第一个部分调用 runlevel 工具,它会让系统显示自己在运行级2
(当然,实际上已经没有运行级这个玩意儿了)并给两个变量赋值。接下来的工作由 exec 命令完成,它会使用参数 2 运行
/etc/init.d/rc 脚本。这个脚本使用相应的参数调用 /etc/rc?.d 目录中的那些链接。这里 rc2 任务会运行
/etc/rc2.d 下的符号链接对应的 init 脚本。
$ cat /etc/event.d/rc2
# rc2 - runlevel 2 compatibility
#
# This task runs the old sysv-rc runlevel 2 (”multi-user”) scripts. It
# is usually started by the telinit compatibility wrapper.
start on runlevel 2
stop on runlevel [!2]
console output
script
        set $(runlevel –set 2 || true)
        if [ “$1″ != “unknown” ]; then
                PREVLEVEL=$1
                RUNLEVEL=$2
                export PREVLEVEL RUNLEVEL
        fi
        exec /etc/init.d/rc 2
end script
tty 服务
如下是一个在 tty1 上启动并监视 getty 进程的服务的工作定义文件:
$ cat /etc/event.d/tty1
# tty1 – getty
#
# This service maintains a getty on tty1 from the point when
# the system is started until it is shut down again.
start on runlevel 2
start on runlevel 3
start on runlevel 4
start on runlevel 5
stop on runlevel 0
stop on runlevel 1
stop on runlevel 6
respawn
exec /sbin/getty 38400 tty1
这个服务由 runlevel 2 到 5 (多用户模式)来触发,启动 getty 进程,并在系统关闭、重启或进入单用户模式,即运行级
0,1 和 6 时触发来关闭该服务。respawn关键字告诉 init 在服务终止后重启服务,而 exec 命令是让 getty 进程以
38400 波特率运行在 tty1。如下,initctl 工具显示该服务处于启动状态,进程ID 4747,ps 命令显示该服务的进程:
$ sudo initctl list tty1
tty1 (start) running, process 4747
$ ps -ef | grep 4747
root   4747   1 0 Jul02 tty1   00:00:00 /sbin/getty 38400 tty1
rc-default 任务和 inittab
在 SysVinit 中,/etc/inittab 文件通过 initdefault 项告诉 init
在系统启动的时候进入哪个运行级,而 Ubuntu 没有 inittab 文件,缺省的,Upstart init daemon (使用
rc-default 任务)引导系统进入多用户模式(缺省运行级为2)。如果希望系统启动进入其他运行级别,那么就创建一个 inittab
文件。如下会让系统缺省进入单用户模式 (runlevel S):
$ cat /etc/inittab
:id:S:initdefault:
当系统进入到单用户(修复)模式,如果系统的root帐号没有被锁定,init 会在显示 root 提示符之前要求输入 root 密码。否则,它会不要求输入密码而直接显示 root 提示符。
注意:不要将系统设置启动到运行级别 0 或 6,这样系统将永远无法正常启动。要直接进入多用户模式(运行级 2),如果有 inittab 删除这个文件,或者用上述的例子,将里面的 S 替换成 2.
Upstart的未来
从 SysVinit 到 Upstart 的迁移涉及到了 Linux 系统的很多部分。要让这个转换尽量平滑并且引入尽量少的问题,Upstart 团队决定通过多个 release 来完成这个迁移。
Ubuntu 从 Feisty 开始使用 Upstart init daemon。在 Feisty 和 Gutsy+2
之间,Ubuntu 将完成 SysVinit 到更加干净、更加灵活的 Upstart 的迁移。随着越来越多的服务被放到 Upstart
的控制之下,/etc/event.d 目录下的内容将会替代 /etc/init.d 和 /etc/rc?.d 目录下的内容。运行级将不再作为
Ubuntu 正式支持的特征,虽然它们可能为了保持与第三方软件的兼容性而继续保留。最终 Upstart 将会替换掉 crond。
*********************************************************************
转到kubuntu之前曾经学习了一下,了解到ubuntu在6.10开始用upstart替代init,主要脚本都在/etc/event.d下面,默认情况下/etc下没有inittab文件。
刚装上kubuntu时候专门到/etc/event.d下看了一下,特别注意到rc-default这个脚本,里面有一段内容:
说明默认情况下inittab虽然不存在,但是用户建立的inittab还是会被注意到的。
然后又经别人的指点看了一下/usr/share/doc/upstart/下面的文档,其中README.Debian中有这么一段内容:
这就给我这样一个印象,即虽然ubuntu用upstart替代init,但还是和init保持兼容。
今天正好需要将系统直接启动到字符界面下,即不启动kdm。

就试试自建一个inittab文件,并按照以前的习惯写入一行id:3:initdefault:
,保存后重新启动,结果发现毫无变化,依然启动到桌面,有点纳闷,难道inittab不起作用?在终端里输入runlevel检查当前状态,显示 N
3,说明inittab有效果,那是什么原因呢?
将刚才建立的inittab移除,将系统恢复到之前的状态并重新启动,再用runlevel检查,显示 N 2,说明ubuntu系统的default runlevel可能是2,这和我以前的常识有些冲突,看来又需要学习了。

去分别查看/etc/rc2.d至rc5.d下的内容,发现基本一致,都启动了kdm。这与其他的linux发行版不太一致,通常runlevel
3是Multi user mode,即直接登录到字符界面;而runlevel 5是Multi user mode with
GUI,即登录到图形界面。
后来在Debian的FAQ里面搜索到这样的内容:
小区别就在这里了,看来debian以及衍生出来的发行版,如ubuntu的default runlevel确实是2,而且id 2至5都是一样的。
真相大白,再次建立inittab,写入id:3:initdefault: ,然后进入/etc/rc3.d,将S13kdm移动到其他目录备份起来,重新启动系统,如愿以偿进入字符界面。
                                       


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/70991/showart_2073774.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP