Jenkins Pipeline的大日志在浏览器打开十分卡顿,怎么办

866 阅读6分钟

(本文为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免密。步骤简单概括为:
  1. 查看Windows C盘/用户/你的用户名/ 下有没有 .ssh 文件,若无,打开cmd执行 ssh-keygen 生成.ssh

  2. 复制上述.ssh文件夹下的公钥 id_rsa.pub 内容到Linux开发机的家目录 ~/.ssh/authorized_keys 内,若无 ~/.ssh ,执行 ssh-keygen 生成该文件夹,若无 authorized_keys 文件,直接在.ssh下vim新建即可

  3. 大部分报错都是因为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指令作为跳板。至此可以总结下载日志到本地的具体思路:

  1. 打通我们的Windows桌面机器到jenkins pod的k8s host的ssh(可以通过在Windows上安装sshpass或者把Windows的的id_rsa公钥加入host免密)
  2. 用我们的Windows机ssh到k8s host,让其执行kubectl exec调用jenkins pod内部指令(也就是让Windows能够间接ssh到pod)
  3. 同1,打通pod到Windows桌面机器的ssh,由于没解决以root进入k8s pod的方法,使用sshpass
  4. 直接让pod把对应的日志文件scp到我们的Windows机器
  5. 把得到的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成功接通。至此所有问题解决,脚本编写水到渠成。