现在的位置: 首页 > 综合 > 正文

Jenkins(三)

2012年11月06日 ⁄ 综合 ⁄ 共 3922字 ⁄ 字号 评论关闭

在使用Jenkins的过程中,当然也会遇到一些问题。在这里我把我遇到的,比较奇怪的问题列出来,供大家参考。

环境变量

我在一个slave node上运行job时发现,被启动的程序显示找不到环境变量。

原来,当Jenkins在slave上启动一次build时,不会应用当前用户的profile。因此我们得自己解决这个问题。

解决方式有很多:

1,在创建slave node时,可以指定要传递的环境变量。这种方法不好的地方就是,相当于hard code,当实际的环境变量改变时,也需要手工修改slave node的配置。

2,想办法自己应用:运行shell前运行:. /usr/usr_account/.profile (注意第一个点后面有空格),这个是最好的方法,因为所有的环境变量都会生效,而不是仅仅某一个。

或者在调用的ant中,或ksh script中指定某个具体的环境变量。

进程被kill

需求是这样的:在Jenkins中一个job运行完毕时,可以配置它触发下一个job运行。这种情况很常见,例如一个job中启动一个程序并运行了UT,当运行完毕时,我们可能会希望一个集成测试的job被触发。这里隐含的意思就是,我们希望程序能一直运行,直到所有的测试结束,最后再显式的停止这个程序。

然而在实施的过程中,我遇到了一个大问题:在第一个job运行结束后,程序就被杀掉了。第二个job没有运行测试的时间。

来看看这个人遇到的类似的问题:

I am trying to run a shell script to stop/start the JBoss instance, but when the Hudson job completes, the JBoss instance shutdowns.  Does anybody have any recommendations on how we can spawn an instance of JBoss from a Hudson job without using the daemonize
script?

由于现实中事情的复杂性(在Jenkins中调用了ant,ant调用了ksh,ksh最终启动了程序),我绕了很大一圈才怀疑到Jenkins上。在这之前,我尝试在ant中使用<parallel>,在调用ksh时使用nohup,但是问题依旧。

而问题的根本在于是Jenkins使用processTreeKiller杀掉了所有子进程,而且这是Jenkins的默认行为。其实回头来看这个问题,就发现Jenkins的做法非常合理。当一次build异常结束,或被人终止时,必然需要结束所有这次build启动的子进程。下面的link提供了更多细节,以及解决方法。

https://wiki.jenkins-ci.org/display/JENKINS/ProcessTreeKiller

Jenkins home目录下的tools目录没有被同步到slave node

在Jenkins的home目录下,有两个自动生成的目录: tools and usercontent。

当我在使用slave node时,我注意到在每个slave node的上,Jenkins自动建了一个tools目录。因此我想当然的以为,tools目录是用来存放用户自己需要的第三方工具的。

例如,我在project中需要使用ant 1.8.2。而tools中则存放了ant 1.8.2,同时在建立slave node时,Jenkins自动将ant1.8.2拷贝到了slave node的tools下。

然而在之后的使用中,我发现在master node的tools中放置其他的第三方工具后,slave node的tools中并没有增加。因此slave node上的project并不能使用对应的第三方工具。

事实真相是,我应该使用usercontent目录,而不是直接使用tools目录。

当用户需要某个第三方工具时,正确的做法是将安装包放到usercontent目录。然后在Jenkins system management中要求安装这个工具。

userContent目录的说明:

You can use this directory to place your own custom content onto your Jenkins server. You can access files in this directory at http://myserver/hudson/userContent (if you are running
Jenkins on an application server) or http://myserver/userContent (if you are running in standalone mode).

之后Jenkins会自动将该工具安装到tools目录下,同时也会同步到slave node的tools下。像我这样直接扔在master node的tools下,是不会自动同步的。

还有一种解决方案:

Jenkins 并没有机制自动将master node上的tools目录下的内容同步到slave node上。这意味着如果在slave node上运行project需要某些特殊工具(或jar包),只能事先在slave node所在的box上安装好(或准备好)。

但是在某些极端条件下,slave node并没有准备好这些工具。

例如,我们使用Jenkins来自动deployment最新的release到production,而安装release意味着很多附加功能,例如环境检查,安装程序,自动启停程序,启动cluster等复杂操作。

我们使用Ant script来完成这些操作。但Ant在production环境没有安装。

因此我希望将ant相关的jar放到master jenkins根目录的tools目录,然后将tools同步到slave node的tools目录下,之后在slave node上运行Ant就可以使用这些jar包了。

但是目前我们只能通过使用一个工具rsync来将tools下的内容同步到slave node:

On master, I have a little shell script that uses rsync to synchronize master's/var/jenkins to slaves (except/var/jenkins/workspace) I use this to replicate tools on all slaves.

如何取得slave node上的jenkins home
我在脚本里,或Ant中使用环境变量JENKINS_HOME的时候发现一个问题: 尽管限制了job在slave node上运行,但是这个变量的值还是master node的JENKINS_HOME。而不是在slave node的配置中配置的“Remote FS root”
一个解决方案是,在创建slave node时,在配置页面下方的node properties中添加一个环境变量:SLAVE_HOME=上面配置的“Remote FS root”目录。这样就可以在slave node上使用这个变量了。
 
You can also specify environment variables. These will be passed into your build jobs, and can be a good way to allow your build jobs to behave differently depending on where they are being executed.
比如在ant中,加入:
<property environment="env"/> 来获取所有的环境变量。
之后用<echo message="home is ${env.SLAVE_HOME}"/>就可以了。

这里顺便提一下,有一个plugin可以显示每次build时,jenkins自动生成的环境变量。在shell, ant中都可以方便的使用这些变量。


在所有的projects中传递参数
一个需求:有3个projects,run.program, run.ut, run.integration.test
它们使用在一个project完成后自动trigger另外一个的方式,形成了一个chain。同时第一个project是parameterized- project,即build时需要提供输入参数。其中一个输入参数是,boolean ifRunUT,是否运行UT。
现在,如果在第一个project中选择不运行UT,则skip后面的那个project,之后继续运行第三个project,也就是集成测试。

解决方法是安装这个plugin:https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Trigger+Plugin
同时将后面的run.ut改为parameterized-project,同时有唯一的一个输入参数ifRunUT。
上面的plugin可以将第一个project的输入参数传递到它触发的下一个project。这样当后面的run.ut发现ifRunUT=false时,就自动返回successful,之后该project继续触发之后的run.integration.test。
听上去有点无聊,但是试想一下,如果有两个关于ut的project:run.ut.1 run.ut.2。上面的方法就可以一次配置,skip掉两个projects,而不需要配置多次。
更重要的是,这种做法使得整个chain的配置都集中在一个地方,而不是分散在各个project中。每次build都需要去多个projects配置参数是很让人崩溃的。

 

 

抱歉!评论已关闭.