(本文为Reo1原创文章,转载请注明出处)
一、概述
Jenkins Pipeline的日志内容太大,在浏览器打开很卡很慢,怎么办呢?配置以下工具,日志的获取、分析都明显加速,工作体验得到极大改善。
二、解决方案(太长不看)
-
环境
我的jenkins是跑在k8s pod中的,其中pipeline日志储存的位置是
JENKINS_HOME/jobs/PIPELINE_NAME/builds/BUILD_NUMBER/log
( 类似于/var/jenkins_home/jobs/builder/builds/1234/log) -
实现方法
Jenkins pod --(scp)--> Linux机 --(scp)--> Windows机(Mac实现方式类似,经过简单修改即可适配) -
不使用 Windows / Mac 直连 Jenkins pod 主要是考虑到
(1)PC根据网络情况不通,IP经常变动;K8s各种网络代理,IP难获取;
(2)因此,使用Linux开发机作中转,可以使用固定的IP作为文件接收方和发送方。
三、部署
- Step1、在个人Linux开发机上部署
get_jenkins_log_tolinux.sh
手动将该文件部署在你的linux机器的某位置(假设脚本地址为ScriptPath),修改文件开头的Configuration。
YOUR_IPNAME是你的Linux机器IP,URL_TO_SSHPASS是一个通过url下载sshpass的方式。
如果没有url下载sshpass的方式,可以通过手动在pod里部署sshpass,直接scp k8s master机器的sshpass到pod即可,只是pod每次重启都要重新配置而已)
# Set Your Linux PC Configuration
YOUR_IPNAME=root@xxx.xxx.xxx.xxx
YOUR_PASSWD=password
JENKINS_MASTER_IPNAME=root@yyy.yyy.yyy.yyy
JENKINS_MASTER_PASSWD=password
URL_TO_SSHPASS=http://www.baidu.com/sshpass
- Step2、在Windows上部署
下载jenkins日志.bat
将jenkins日志.bat放在windows机器上,修改文件开头的Configuration。注意其中的LINUX_SCRIPT_PATH默认设置为/home/tools/get_jenkins_log_tolinux.sh,需要将其修改为Step1的脚本地址ScriptPath。
rem Set Your Linux PC Configuration
set LINUX_HOST_NAME=root@xxx.xxx.xxx.xxx
set LINUX_SCRIPT_PATH=/home/tools/get_jenkins_log_tolinux.sh
此时可以执行该bat文件,试着使用工具,正常情况下,日志会被正常拉取到与bat脚本相同的目录下;然而,如果Windows机器到Linux机器没有ssh免密,过程中需要输入N次密码,十分麻烦。
- Step3、配置ssh免密
考虑到给Windows装sshpass较麻烦,可以把Windows的公钥id_rsa.pub添加到自己的Linux机器/root/.ssh/authorized_keys内,以实现ssh免密。步骤简单概括为:
-
查看Windows
C盘/用户/你的用户名/下有没有.ssh文件,若无,打开cmd执行ssh-keygen生成.ssh -
复制上述.ssh文件夹下的公钥
id_rsa.pub内容到Linux开发机的家目录~/.ssh/authorized_keys内,若无~/.ssh,执行ssh-keygen生成该文件夹,若无authorized_keys文件,直接在.ssh下vim新建即可 -
大部分报错都是因为ssh不通,可以通过在windows cmd命令行使用ssh,来检查windows到linux开发机的ssh免密是否正常;通过在linux开发机执行sshpass -p...测试linux开发机到k8s master的ssh连接是否正常
四、代码
get_jenkins_log_tolinux.sh
#!/bin/bash
set -ex
# Set Your Linux PC Configuration
YOUR_IPNAME=root@xxx.xxx.xxx.xxx
YOUR_PASSWD=password
JENKINS_MASTER_IPNAME=root@yyy.yyy.yyy.yyy
JENKINS_MASTER_PASSWD=password
URL_TO_SSHPASS=http://www.baidu.com/sshpass
# System Configuration
# No need to change, unless changes have been made in windows bat shell.
TARGET_PATH=/tmp/jenkinslog
# Check Input
if [ $# -ne 1 ];then
echo "Error: 1 param (Job Num) is needed. For example, 1234"
exit 1
fi
expr $1 "+" 10 &> /dev/null
if [ $? -eq 0 ];then
# $1 is number
echo "legal input: $1, Downloading..."
else
# $1 is not number
echo "Error: illegal input: $1 is not number"
exit 1
fi
# Main Script
JOB_NUM=$1
JENKINS_POD_NAME=$(sshpass -p$JENKINS_MASTER_PASSWD ssh -o StrictHostKeyChecking=no $JENKINS_MASTER_IPNAME kubectl get po|grep jenkins|awk '{print $1}')
QUERY_LOG_NUM=$(sshpass -p$JENKINS_MASTER_PASSWD ssh -o StrictHostKeyChecking=no $JENKINS_MASTER_IPNAME "kubectl exec $JENKINS_POD_NAME -- ls /var/jenkins_home/jobs/build/builds/$1/log 2>&1")
LOG_NOT_EXIST_FLAG="$(echo $QUERY_LOG_NUM|grep "No such file or directory")"||:
if [[ "$LOG_NOT_EXIST_FLAG" -ne "" ]];then
echo "Log num $1 not found in jenkins pod, JENKINS_HOME/..."
exit 1
fi
mkdir -p $TARGET_PATH
rm -f $TARGET_PATH/$1
# Manually transfer sshpass to jenkins pod is ok, but whenever jenkins pod is restart the script will fail
# (For example, when server power off / restart )
# Transfer sshpass to pod by curl minio
sshpass -p$JENKINS_MASTER_PASSWD $JENKINS_MASTER_IPNAME "kubectl exec $JENKINS_POD_NAME -- curl -o /tmp/sshpass $URL_TO_SSHPASS"
# chmod 777 sshpass
sshpass -p$JENKINS_MASTER_PASSWD ssh $JENKINS_MASTER_IPNAME "kubectl exec $JENKINS_POD_NAME -- chmod 777 /tmp/sshpass"
# Transfer logs from pod to Linux PC
sshpass -p$JENKINS_MASTER_PASSWD ssh $JENKINS_MASTER_IPNAME "kubectl exec $JENKINS_POD_NAME -- /tmp/sshpass -p$YOUR_PASSWD scp -o 'StrictHostKeyChecking no' /var/jenkins_home/jobs/build/builds/$1/log $YOUR_IPNAME:$TARGET_PATH/$1.log"
# sed to clean jenkins display format
sed -i 's/.[8mha:.*[0m//g' $TARGET_PATH/$1.log
echo Success:
echo $(ls -lh $TARGET_PATH/$1.log)
下载jenkins日志.bat
rem @echo off
@echo off
rem Set Your Linux PC Configuration
set LINUX_HOST_NAME=root@xxx.xxx.xxx.xxx
set LINUX_SCRIPT_PATH=/home/tools/get_jenkins_log_tolinux.sh
echo Enter job number (Jenkins pipeline build's job) :
set /P NUM=Input Number: %=%
ssh %LINUX_HOST_NAME% bash %LINUX_SCRIPT_PATH% %NUM%
scp %LINUX_HOST_NAME%:/tmp/jenkinslog/%NUM%.log .
ssh %LINUX_HOST_NAME% rm -f /tmp/jenkinslog/%NUM%.log
PAUSE
五、具体流程(不重要)
今天修改jenkinsfile的代码,被一些Groovy的语法坑缠住出了一些问题。用户连续提了挺多bug,需要我看很多日志,这时在浏览器上看pipeline日志又卡又慢成为一个十分影响工作体验的事。于是我突发奇想,调研如何打开大文本比较快,网上冲浪找到一个好用的软件LogViewer,实测发现本地几十MB的日志文件毫秒级打开,毫不夸张的说,比txt、浏览器的开启速度快无穷倍。推测是由于LogViewer的打开文件的方式是只读,因为这个APP不能修改打开的文件。
解决了打开日志很慢、搜索日志内容很慢的问题后,日志的获取依然需要到Jenkins页面中点击View as plain text再另存为到本地,需要等待浏览器卡顿好一阵子,工作体验的提升不明显。如何优化呢?
我本来的想法是通过调用API下载日志文件,但也不知怎么,浏览器F12抓不到日志页面调的API(如果有人知道可以用API或者URL来下载请告知我)。于是就想着去jenkins的服务器本地找找pipeline的日志在哪,找到在/var/jenkins_home/jobs/builder/builds/1234/log,成功的一大步。
接下来,需要解决如何把该文件传输到Windows机器上的问题,也是核心问题。初步考虑是直接在Windows机器上scp拿去pod中的文件,可是pod使用接口映射,其ip没有暴露在公网中,且pod没有开放ssh的22端口,因此使用Windows主机ping不通也无法shh通pod。转换思路,在pod端ssh外部机器或scp发送文件给外部机器是可行的。所以给pod发送指令,就需要借助k8s host执行kucectl exec指令作为跳板。至此可以总结下载日志到本地的具体思路:
- 打通我们的Windows桌面机器到jenkins pod的k8s host的ssh(可以通过在Windows上安装sshpass或者把Windows的的id_rsa公钥加入host免密)
- 用我们的Windows机ssh到k8s host,让其执行kubectl exec调用jenkins pod内部指令(也就是让Windows能够间接ssh到pod)
- 同1,打通pod到Windows桌面机器的ssh,由于没解决以root进入k8s pod的方法,使用sshpass
- 直接让pod把对应的日志文件scp到我们的Windows机器
- 把得到的log文件拖动到LogViewer,日志毫秒级开启
然而,仍存在一些未解决的细节问题,由于没有找到以root权限进入pod的方法(若有人知道如何在没有docker的情况下以root进入pod请告知我),并不能轻易的把我们的Windows桌面机器公钥加入pod的/root/.ssh中,这时就想到使用sshpass,但pod中既没有yum也没有apt,怎么获取sshpass呢?通过复制其他机器的sshpass。在一台有sshpass的linux机器上执行whereis sshpass找到其sshpass的路径,并通过ls -l 刚才获取的地址来确定其不是ln软硬链接。又是相似的问题,如何把sshpass文件传输到pod中呢?上面提过,我们可以进入pod中用scp主动拿sshpass。pod的各种目录都没有权限mv文件进去(例如/home、/root、/bin、/var),但还好有/tmp。至此我们获得了pod中的/tmp/sshpass,给他赋可执行权限chmod 777 /tmp/sshpass。幸好,这个chmod指令非root用户也可以用,立刻执行/tmp/sshpass -p****** ssh -o 'StrictHostKeyChecking no' ***@***.***.***.***验证,ssh成功接通。至此所有问题解决,脚本编写水到渠成。