现在是让 CruiseControl 运行了,但是还不能让它在没人参与的情况下运行。它目前在一个终端窗口中运行,所以需要让 cruise 用户永远登录,才能保持它一直运行。终端还是控制程序的唯一方式:可以按下 Ctrl+C 停止 CruiseControl,并再次运行程序重新启动它。除非使用虚拟网络计算(VNC)会话或类似的东西,否则就不能远程地做上面这些事。如果 CruiseControl(或者 JVM)崩溃,就需要手动地重启它。而且当重新启动机器时,也需要手动地建立新会话、创建终端、再次启动程序,CruiseControl 才能重启。所以需要让 CruiseControl 作为一个服务运行,或者用 Unix 的术语来说,作为一个 守护程序 运行。
让程序在 Linux 下持续运行的方法有许多种。最常用的方法可能是把合适的脚本挂上 init
系统初始化进程,在系统启动时启动程序。这些脚本可以启动和停止程序,但是不能在程序出现故障时自动重启程序。
我用的方法 I 是下载并安装 Daniel J. Bernstein 的 daemontools
(请参阅 参考资料)。这是一个小的程序包,负责启动一组服务并保持这些服务一直运行。要执行自己的 daemontools
安装,需要登录为 root:
[root@fcvm ~]# mkdir -p /package [root@fcvm ~]# chmod 1755 /package [root@fcvm ~]# cd /package [root@fcvm package]# wget -q http://cr.yp.to/\ daemontools/daemontools-0.76.tar.gz [root@fcvm package]# gunzip daemontools-0.76.tar.gz [root@fcvm package]# tar -xpf daemontools-0.76.tar [root@fcvm package]# rm daemontools-0.76.tar rm: remove regular file 'daemontools-0.76.tar'? y [root@fcvm package]# |
要让这个包能够在 Fedora Core 4 上干净地构建,必须对包的 C 源代码稍做调整。请用文本编辑器,把 src/error.h 的第 6 行从 extern int errno;
改成 #include <errno.h>
。下面是使用 ed
的处理方法:
[root@fcvm package]# cd admin/daemontools-0.76 [root@fcvm daemontools-0.76]# ed src/error.h 595 6 extern int errno; c #include <errno.h> . wq 596 [root@fcvm daemontools-0.76]# |
现在可以完成安装了:
[root@fcvm daemontools-0.76]# package/install Linking ./src/* into ./compile... Compiling everything in ./compile... [...] Creating /service... Adding svscanboot to inittab... init should start svscan now. [root@fcvm daemontools-0.76]# ps -ef | grep svs root 21160 1 0 16:09 ? 00:00:00 /bin/sh /command/svsca nboot root 21162 21160 0 16:09 ? 00:00:00 svscan /service root 21173 20051 0 16:10 pts/1 00:00:00 grep svs [root@fcvm daemontools-0.76]# |
daemontools
提供了叫作 svscan
的守护进程,它负责管理服务集合。每个服务都由 /service 目录中的一个目录代表,所以需要在这里为 CruiseControl 服务创建一个目录。对于 /service 中的每个子目录,svscan
都启动一个子进程,运行 supervise
程序。
supervise
是负责管理 CruiseControl 这样的独立服务的程序。它创建子进程,运行服务子目录中的 run
(例如 /service/cruisecontrol/run),从而启动服务。如果子进程中止,supervise
会重新启动它。supervise
也可以向子进程发送信号,停止或重新启动子进程。
daemontools
还提供了两个机制,负责处理它管理的服务的日志记录。首先,叫作 readproctitle
的程序捕捉写入标准错误流(在 Java 世界中,是 System.err
)的输出并把输出拷贝到一个小缓冲区中,这个小缓冲区是 ps
命令显示的进程标题的一部分:
[root@fcvm daemontools-0.76]# ps -ef | grep proctitle
root 25040 25037 0 20:58 ? 00:00:00 readproctitle service
errors: ..............................................................
......................................................................
......................................................................
......................................................................
......................................................................
..........................................................
root 25047 24006 0 20:59 pts/1 00:00:00 grep proctitle
[root@fcvm daemontools-0.76]# |
在启动时,缓冲区被初始化为包含点号,但是在出现错误时就被错误信息替代。这个机制对于少量信息(例如关键错误信息)来说很好。但是缓冲区尺寸小造成它不适合更大数量的日志信息,而且记录的信息不能保存到磁盘也使得难以分析一段时间内的性能。daemontools
提供了第二种机制 —— multilog
程序,它负责这种大量日志。第二种机制在命令行参数输出的指令控制下,把自己标准输入中的行写入日志文件。它包含对日志轮转的控制,日志轮转可以保持定量的日志信息,以使存储空间不会耗尽。例如,multilog /home/cruise/log
这个简单的命令就可以把信息记录到 /home/cruise/log 目录中的文件,当日志文件的尺寸达到 99,999 个字节时就轮转日志文件,并保持 10 个旧的日志文件。
multilog
也由 supervise
管理,就像其他服务一样。在 svsccan
发现的每个目录中,它都会查找叫作 log 的子目录,并创建一个 supervise
进程来管理这个目录下 run
脚本的执行。它还安排一个管道,把主服务的标准输出作为日志进程的标准输入。
那么,要让 daemontools
管理 CruiseControl,需要做什么呢?必须为这个服务和它的 multilog
伙伴创建目录结构。还必须创建它们各自的 run
脚本,并为日志文件创建目录。开始时,把服务目录命名为 .cruisecontrol。前导点号会让 svscan
忽略这个目录,从而可以在第一次启动服务之前进行设置:
[cruise@fcvm ~]$ mkdir -p log/cruisecontrol [cruise@fcvm ~]$ su - Password: [enter root password] [root@fcvm ~]# cd /service [root@fcvm service]# mkdir .cruisecontrol [root@fcvm service]# cd .cruisecontrol [root@fcvm .cruisecontrol]# mkdir log [root@fcvm .cruisecontrol]# |
然后,创建叫作 env 的目录。要用这个目录的内容设置 CruiseControl 的环境变量以及它要启动的其他进程。在这里要确保 JAVA_HOME
有合适的值。在这里还要设置将要使用的构建工具需要的环境变量,例如 MAVEN_HOME
。
[root@fcvm .cruisecontrol]# mkdir env [root@fcvm .cruisecontrol]# cd env [root@fcvm env]# echo /usr/lib/jvm/java >JAVA_HOME [root@fcvm env]# echo /home/cruise/pkg/maven-1.0.2 >MAVEN_HOME [root@fcvm env]# ls JAVA_HOME MAVEN_HOME [root@fcvm env]# cd .. [root@fcvm .cruisecontrol]# |
清单 2 显示了 /service/cruisecontrol/run 脚本:
清单 2. /service/cruisecontrol/run 的内容
#!/bin/sh svc=`pwd` cd /home/cruise exec 2>&1 exec setuidgid cruise \ envdir ${svc}/env \ java -jar pkg/cruisecontrol-2.2.1/main/dist/cruisecontrol.jar |
这个脚本相当简单。它执行以下这些步骤:
- 保存服务目录的名称(在这个示例中是 /service/cruisecontrol)留待后用。
- 把当前目录变为 /home/cruise。
- 让标准错误流写入到
multilog
进程的管道,这个管道已经连接到了标准输出流。 - 启动 JVM,运行 CruiseControl,以 cruise 这个用户身份运行进程,并根据 /service/cruisecontrol/env 目录中创建的文件设置环境。
清单 3 演示了 /service/cruisecontrol/log/run 脚本,它更简单。它以 cruise 用户的身份运行 multilog
:
清单 3. /service/cruisecontrol/log/run 的内容
#!/bin/sh exec setuidgid cruise multilog /home/cruise/log/cruisecontrol |
请注意,必须使用 chmod
把两个脚本变成可执行的。而且,这两个脚本都要小心地使用 exec
外壳命令,这个命令用一个程序替代另一个程序,但是没有创建新进程。这一点很重要,因为 supervise
只能管理自己的直接子进程。如果没有使用 exec
,那么 JVM 会作为执行 run 脚本的外壳的一个子进程启动。如果向 supervise
发送了杀死其子进程的信息,那么外壳会接收到信号并退出,但是 JVM 会继续运行,从而变成孤儿。supervise
并不会知道这一点,所以可能会接着启动守护程序的第二个拷贝 —— 这并不是想要的结果。
在设置好服务目录之后,可以把它改名,删除前导点号。然后 svscan
就会自动启动 CruiseControl,它的输出也会出现在日志文件中:
[root@fcvm .cruisecontrol]# cd .. [root@fcvm service]# mv .cruisecontrol cruisecontrol [root@fcvm service]# cat /home/cruise/log/cruisecontrol/current [cc]Aug-24 21:45:45 Main - CruiseControl Version 2.2.1 [cc]Aug-24 21:45:46 trolController- projectName = [xstream] [cc]Aug-24 21:45:46 Project - Project xstream: reading settings from config file [/home/cruise/config.xml] [cc]Aug-24 21:45:47 BuildQueue - BuildQueue started [cc]Aug-24 21:45:47 Project - Project xstream starting [cc]Aug-24 21:45:47 Project - Project xstream: idle [cc]Aug-24 21:45:47 Project - Project xstream started [cc]Aug-24 21:45:47 Project - Project xstream: next build in 1 hours [cc]Aug-24 21:45:47 Project - Project xstream: waiting for next time to build [root@fcvm service]# |
文章来源于领测软件测试网 https://www.ltesting.net/