为什么我的新兴服务在系统启动时没有启动?

这个问题之后,我为我的无头Ubuntu Server 11.04盒子编写了一个简单的upstart服务(/etc/init/pms.conf)如下所示:
start on filesystem and net-device-up IFACE=eth0
stop on runlevel [016]
respawn

exec /home/administrator/pms-current/PMS.sh

我可以通过命令行随意启动(或停止)此服务:
service pms start

而且我可以看到它确实在运行。

然而,当我首次启动我的机器时,服务不会启动。如果我通过SSH登录到该服务器并检查服务状态,我会得到以下结果:

$ service pms status
pms stop/waiting

我的问题是为什么会发生这种情况?为什么我的服务在启动时没有启动? 更新1:我不确定我的服务是否被启动然后停止,或者根本没有启动,所以我在PMS.sh中添加了以下内容:
echo "STARTED" > $STARTLOG

这显然只是给我找了个“东西”看。我通过自己启动服务,然后检查start.log进行了测试。然后我删除了start.log并重新启动。重新启动后它不在那里,所以看起来upstart肯定没有启动我的服务。我想它可能在进程的早期阶段就停止了,但鉴于整个过程的简单性,这似乎相当不太可能。
更新2:我刚刚升级到11.10版,其中包括一个upstart升级,但这个问题仍然存在。
更新3:根据要求,我使用--debug引导。cat /var/log/syslog | grep init的输出太长无法放在问题中,但您可以在这里查看它here
更新4:更多日志,这次包括upstart conf在顶部。Run 1run 2

你确定脚本没有执行吗?PMS的stop/waiting消息意味着Upstart作业已经运行,并且所有命令都正常终止。 - arrange
在启用了Upstart的引导日志记录后,按照Upstart调试页面上的指示,将cat /var/log/syslog | grep init的输出添加进去。 - Ciaran Liedeman
@Anarci:请查看我问题中的第三个更新。 - Kent Boogaart
大多数用户不会像那样直接提供他们的电子邮件地址,而是会提供一个类似于Ubuntu pastebin的pastebin网站的链接。 - Ciaran Liedeman
@Anarci:完成了,请查看我的问题。 - Kent Boogaart
你用什么代码开始生成那个系统日志的? - Ciaran Liedeman
是的,抱歉 - 我在开始子句上做了一些调整。我将其设置为 start on mounted FILESYSTEM=/home 或者其他正确的语法形式。 - Kent Boogaart
让我们在聊天中继续这个讨论。 - Ciaran Liedeman
我们可能看不到记录器输出,因为您可能已经在日志中使用了“init”字符串进行过滤。 - arrange
@Oxwivi: 我错了,它表示工作已经开始或者已读取配置,但并不意味着它正常终止。http://netsplit.com/2010/12/03/event-matching-in-upstart/ - arrange
检查为什么initctl reload-configurationless /var/log/messages的最后几行没有起作用。 - Jose Alban
12个回答

我建议增加工作的详细程度,例如通过使用预启动/后启动条目。
pre-start script
  logger "pre-start for myprog"
end script

post-start script
  logger "post-start for myprog"
end script

# and for PMS itself:
script
  logger "just before executing PMS"
  exec /home/administrator/pms-current/PMS.sh
end script

更多信息请参考http://upstart.ubuntu.com/cookbook/

还可以查看http://upstart.ubuntu.com/wiki/Debugging


这真的让我头疼。我根据你的帖子尝试了十几种不同的方法,但都以各种晦涩的日志信息失败告终。我最新的尝试导致了init: pms主进程(1329)以状态143终止,这对我来说毫无意义。我可以看到PMS.sh甚至没有被启动,因为它的第一件事就是写入自己的日志,而该日志条目并不存在。我可以看到我的预启动输出,告诉我目标文件存在且可执行。我明天会继续处理这个问题,但如果你有任何想法,我很乐意听取。谢谢。 - Kent Boogaart
嗨 @KentBoogaart,我似乎遇到了与你相同的问题。你找到解决办法了吗? - Daniele B
@KentBoogaart 我和你有同样的问题?你解决了吗? - Mevin Babu

这里可能发生的情况是,在您的网络适配器启动之前,pms 就开始运行了,甚至在回环适配器(lo)之前也是如此。假设我们正在谈论的是 PS3 媒体服务器,它是一个网络服务,可能不喜欢在没有可用接口的情况下启动。
尝试更改您的启动条件为:
start on filesystem and net-device-up IFACE!=lo

意思是,在任何“真实”的网络接口启动之后开始。然而,如果eth0是下一个启动的接口,PMS会启动,但你真正想要PMS使用wlan0,那样就不行了。服务会启动,但可能无法选择您希望它监听的接口。假设您知道要流式传输的接口,并且它不会更改,我建议将其硬编码到作业中,例如:
start on filesystem and net-device-up IFACE=wlan0

在Oneiric(11.10)上,您可以使用事件static-network-up来等待所有静态配置的设备。这很好,因为它允许您编写依赖于网络的任务而不是硬编码接口。【注意:“所有静态配置的设备”是指使用/etc/network/interfaces而不是NetworkManager。它不是指静态IP与DHCP之间的静态意义。】

这听起来像是个诀窍,但它没有起作用。我只有loeth0,但我使用了你的第二个建议:start on filesystem and net-device-up IFACE=eth0。重启后仍然无法正常工作。我刚刚在PMS日志中注意到了一些可能是线索的东西。我会进行调查并回复... - Kent Boogaart
有趣。我没有提到的一件事是,我尝试了你的原始脚本,它能够在我的机器上启动。我认为这只是侥幸之中(也就是在我的竞争条件中,赢得了好车,在你的条件下则是坏车赢了)。我真的看不出我们还缺少了什么其他依赖。真奇怪。 - Mark Russell
2既然您可以在启动后开始它,那么我们肯定是遗漏了另一个服务依赖项。可能会有一个不太正规的方法(但并不会给我们提供任何启发),就是在执行 Shell 脚本之前,在“预启动脚本”中插入 sleep 10(或更长时间)来延迟一下。 - Mark Russell
抱歉马克 - 但我们在同一页面上。我已经在预启动脚本中尝试了"sleep 10"的方法,没有用。然后我尝试删除debug.log文件并重新启动。启动后,我仍然有相同的服务状态,并且没有debug.log文件,所以我不确定PMS是否实际运行。有没有一种简单的方法来诊断这个问题?如果我改变PMS.sh以输出一些内容,它会去哪里?我想我总是可以将其定向到自己的文件 - 下次可能会尝试这样做。 - Kent Boogaart
我刚刚更新了我的问题,并添加了更多信息。 - Kent Boogaart
要查看Upstart是否在尝试,我会选择在内核命令行上使用--verbose选项。http://upstart.ubuntu.com/cookbook/#add-verbose-or-debug-to-the-kernel-command-line - Mark Russell
谢谢 - 我明天试试看。今晚可能通过PMS看电影!;) - Kent Boogaart
刚试了一下,如果我指定“--debug”,屏幕上什么也没有显示:S - Kent Boogaart
我看到很多人都在说“在内核命令行上添加--verbose”。那我该怎么做呢? - Phương Nguyễn

从检查您的系统日志来看,pms进程在启动时没有出现错误,但是在短时间后,其目标从启动变为停止,意味着它被终止了。
这有点奇怪,因为您已经添加了重新启动子句,所以它应该在停止后尝试重新启动,但实际上并没有。所以我猜测您可能已经删除了重新启动子句。
在pms服务启动和停止之间,只有2个服务被启动:ufw和network-interface(eth0),还有一个服务被启动:udev-fallback-graphics。
看起来您的pms进程正在并行启动。不幸的是,upstart文档对于start on ... vanilla和start on starting ...以及start on started ...之间的确切区别描述得不够清楚。
请尝试将您的启动段落更改为
start on started networking

或者只是太
start on net-device-up IFACE=eth0

日志输出有点奇怪,因为网络设备启动事件发生得比较晚,但是pms在此之前就开始了。
这样可以确保您的进程只在所有网络设置完成后才启动,即任务不仅已经开始,而且已经完成。
同时,不要完全依赖日志输出,因为在引导过程的早期,将日志输出到任何文件并不总是有效的。请参考Debugging Upstart中的答案。

通过使用“start on runlevel”来解决类似问题。
start on runlevel [2345]

我曾经遇到过同样的问题,最终我通过以下方法简单地解决了它:
start on runlevel [2345]
没有任何net-device-up或started networking之类的东西
这是完整的upstart脚本,它完美地工作着:
# MyApp

description     "MyApp"
author          "me"

start on runlevel [2345]
stop on runlevel [016]

respawn

exec /usr/bin/myapp 2>> /var/logs/myapp.log

我在RHCSA/CE培训中遇到了chkconfig
sudo apt-get install chkconfig
sudo chkconfig pms on

你可以查看它的Oneiric man page,以了解更多关于它的功能的详细信息。

我已经找到了解决方案,但我不理解它。如果我将PMS从/home/administrator移动到以root为所有者的/bin/pms中,一切都可以正常工作。
如果我将其保留在/home/administrator/下,但确保除/home/administrator/目录本身之外的所有内容都是root所有,它仍然无法正常工作。
如果我将administrator设置为所有者并更改脚本的相关部分为:
sudo su administrator -c '/home/administrator/pms-current/PMS.sh'

还是不起作用。

我想现在我会创建一个/home/root/目录并将所有东西移动到那里,尽管我真的很想完全理解这个。


那么chkconfig也没起作用吗?你试过将PMS.sh所在的目录给予root权限了吗?如果只有你的解决方案有效,那就去Upstart的Launchpad页面直接联系开发人员。 - Oxwivi
如果只需移动.sh文件,那就把一切都留在原处,并编辑脚本以指向该目录(或甚至改变目录?)。 - Oxwivi
是的,我尝试将整个PMS目录的所有权交给root。可能没有成功是因为/home/administrator/不是由root拥有。 - Kent Boogaart
无论如何,这都没有意义。我经常在我的/home目录下通过upstart运行脚本而没有问题,奇怪。 - arrange
更奇怪的是:我刚刚尝试了一切在/home/root/下的东西,显然这些都是属于root的。但是没有起作用。我把所有东西都移回到/bin/pms下,然后它又正常工作了。所以看来在我的系统上,试图从/home目录下启动PMS是行不通的。 - Kent Boogaart
你的/home分区没有以noexecuser(s)的方式挂载吗? - arrange
不,这只是使用“默认”。此外,当我开机后启动时它可以正常工作,所以绝对不是原因。 - Kent Boogaart
对我来说真的很奇怪的是它确实启动了,但很快就终止了。 - Ciaran Liedeman

你的主目录在NFS上吗?有时候root无法访问NFS。
就记录而言,在我刚才对12.04进行的小测试中:
  • start on started networkingstart on network-interface-up INTERFACE=eth0都不起作用,但是

  • start on started network-interface INTERFACE=eth0可以。

感谢http://os4.org/wiki/upstart.html指出initctl list始终显示网络作业已停止。

所引用的链接已损坏。 - slm

当我意识到我的脚本依赖于一个位于我的主目录中的文件,并且该主目录由标准的Ubuntu机制(.Private)加密,我遇到了类似的“无法启动”的问题。

start on local-filesystems 事件在解密过程结束之前(可能)被触发。


和 @xuhcc 类似,我来这里是为了弄清楚为什么我的 Vagrant Upstart 脚本无法运行。以下代码应该有效:

start on vagrant-mounted

但在某些构建中却无法运行,原因是以下错误导致的。

https://github.com/mitchellh/vagrant/issues/6074

报告中列出的解决方法对我非常有效:
$ cat /etc/init/workaround-vagrant-bug-6074.conf 
# workaround for https://github.com/mitchellh/vagrant/issues/6074
start on filesystem
task

env MOUNTPOINT=/vagrant

script
  until mountpoint -q $MOUNTPOINT; do sleep 1; done
  /sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=$MOUNTPOINT
end script

对我来说效果很好