背景
废话少说, 在新建一个jenkins流水线时, 碰到了打包死活无法成功的问题, 相关配置如下图
运行后最后的日志如图
定位问题
通过查看日志, 发现报错的模块是构建后执行shell的时候, 但是由于我的shell没有输出, 还不明确是哪行出的问题.
仔细观察了下shell, 发现并没有任何的语法与逻辑问题, 这就让我感到有点奇怪了: 真的是执行shell出错了吗? 这么简单的shell在哪出错的?
通过看jenkins日志, 连问题出在哪都不太明确, 所以我到应用服务器上确认下, 通过查看jar包的更改时间, 发现jar包已经被更新; 再通过ps -ef
查看进程, 发现没有这个jar包对应的进程; 查看日志文件, 发现应该被重命名的日志文件没有被重命名.
通过上述情况可以得知, 应该是kill
命令到mv
命令这一段shell出错了, 但是怎么看都没有问题, 我还是无法想象这么简单的脚本哪里出错了.
排查问题
第一感觉
既然shell的语法和逻辑没问题, 那么我第一时间想到的是环境有问题, 翻译一下就是mv
命令或者kill
命令不存在??? 登录应用服务器, 执行type mv
和type kill
命令, 发现都是正常的.
但是此时我的是交互式shell, jenkins执行shell用的是非交互式shell, 二者环境还是有点差细微异的, 但是不至于连这么基础的命令都有差异, 不过既然想到了, 就要验证一下.
在jenkins的shell中, 加入了type mv
和type kill
语句, 看日志发现也是正常的.
在应用服务器上执行shell
既然不知道哪里出问题了, 那我只有祭出最后的绝招了: debug shell脚本! 没错, shell脚本也是可以debug的, debug脚本可以清楚的看到每行执行的过程以及每个变量.
我在应用服务器上新建了一个 test.sh 文件, 并将jenkins中的shell写入文件中, 通过执行bash -x test.sh
来debug脚本, 然而结果是, 脚本执行成功了!!! shell脚本所有逻辑都执行成功了!!!???
不死心的我执行了echo $?
, 发现结果是一个大大的0, 脚本真的执行成功了(苦涩+绝望)
找到并解决问题
应用服务器上的脚本执行成功真的给我很大的冲击, 但是冷静下来之后, 觉得我手动执行脚本和jenkins执行shell可能还是有差异的, 所以放弃了在应用服务器上debug脚本, 直接在jenkins中手动添加echo
语句做为调试日志, 添加调试语句后的shell如下图所示:
然后再次构建, 查看jenkins日志, 仔细观察日志后终于发现问题在哪了!!!
通过日志可以看到执行完for循环后就不往下继续执行了, for循环中的kill也是执行了的, 但是! kill执行了两次, 其中一次kill 8214
是kill原本运行的jar包, 还有一次kill 8301
, 8301这个进程是? 观察前面ps -ef
的结果, 发现8301这个进程是bash -c ......一大串
, 这一大串不就是我在jenkins中写的shell命令吗? 原来jenkins执行shell命令是通过bash -c ......
的方式来执行, 原来for循环中的kill自己把自己杀了, 到这里一切都真相大白了!
既然知道了原因, 那修改起来也很简单了, 将for循环的ps -ef | grep java | grep $JAR_NAME | awk '{print $2}'
修改为ps -ef | grep java | grep $JAR_NAME | grep -v grep | awk '{print $2}'
, 多添加一个| grep -v grep
就可以解决这个问题
总结与感悟
公司里启动应用都是将命令写到脚本里, 将启动脚本放在应用服务器上, jenkins的shell只是简单的一行执行脚本的命令, 这样也可以避免上述的问题, 原来还有这层考虑, 学习到了