最近在 Jenkins 中编写项目的 Build 脚本时碰到一个关于 grep 的副作用的问题,让人感觉挺费解,解决时需要用一点小技巧,因此在这里记录一下。
先描述一下所碰到的问题的现象,我需要用 Jenkins Shell script 将为我们的项目部署到 Kubernetes cluster 上,在部署之前会进行一些权限的检查和设置,因此在脚本中直接使用了 kubectl
查询资源并结合 grep 的方式来判断资源是否已经创建出来了,例如:
...
is_service_account_exists=$(kubectl get sa --name myns | grep 'my-service-account')
if [ -z "$is_service_account_exists" ]; then
echo "The service account does not exist, will create it ..."
fi
...
当 Jenkins Job 开始运行时,虽然 service account 并不存在,但是该 Job 却莫名其妙失败了,并没有看到期待的输出 “The service account does not exist, will create it …”。经过一番检查发现问题出在 grep 命令上。当 grep 正确执行,且从标准输入上匹配到期望的内容时,它会返回错误代码 0,例如:
$ kubectl get sa --namespace kube-system | grep tiller
tiller 1 392d
$ echo $?
0
否则如果没有匹配到任何内容,该管道命令会返回 1,还是以上面的例子为例,当我故意查找并不存在的内容时,返回结果如下:
$ kubectl get sa --namespace kube-system | grep not-exists
$ echo $?
1
而 Jenkins Shell 脚本在执行时默认使用了 -xe 参数,-x 参数将打印每一行执行的命令, -e 则在运行 script 时检查每一行的输出结果,如果结果是非 0 则立即停止脚本执行。在本例子中,我们只想通过获取 grep 结果的输出来判断是否获得期待的结果,因此我们希望 ‘kubectl get sa –name myns | grep ‘my-service-account’ 无论如何都返回 0。解决办法是将 ‘|| true’ 添加到命令的最后,我们知道 shell 脚本通过布尔操作符连接时,会根据命令的返回结果来决定是否运行布尔操作符连接的其他命令。通过 || 操作符,可以保证 true 始终被执行,从而保证该命令的执行始终能够返回 0。例如:
$ kubectl get sa --namespace kube-system | grep not-exists || true
$ echo $?
0
最终将 Jenkins 脚本修改如下,并成功执行。
...
is_service_account_exists=$(kubectl get sa --name myns | grep 'my-service-account || true')
if [ -z "$is_service_account_exists" ]; then
echo "The service account does not exist, will create it ..."
fi
...
参考:https://stackoverflow.com/questions/22814559/how-when-does-execute-shell-mark-a-build-as-failure-in-jenkins/22816074
最近在学习docker和k8s; 居然可以看明白一点点了,经常来逛逛您的主页,挺好;
谢谢!一起加油!