jenkins包装shell实践
背景
单纯在服务器上使用shell脚本执行ci/cd任务有一些弊端:
- 输出无持久化,不方便回溯
- 无图形界面,需要记忆参数
- 功能扩展不方便,必须增加邮件通知等
本文记录在保持原有shell脚本大体不变的基础上,将其封装为jenkins任务的流程,以实现对以上几个问题的解决。
增加节点
为了尽量减少环境的重装操作,最简便的方法是把shell脚本执行的机器直接作为节点加入到jenkins中
-
jenkins页面:manage node,新建节点
-
启动方式选择controller或java web,提交。
-
点击进入该新增的节点,下载agent.jar,复制启动命令
-
在slave节点用systemd把上述启动命令包装成systemd服务:
vim /lib/systemd/system/jenkins.service
[Unit] Description=jenkins slave process to connect to jenkins master After=network.target [Service] Type=forking ExecStart=/root/jenkins/start.sh ExecStop=/root/jenkins/stop.sh EnvironmentFile=/root/jenkins/envfile [Install] WantedBy=multi-user.target
systemd里引用的各文件内容如下:
start.sh
#!/bin/bash nohup java -jar /root/jenkins/agent.jar -jnlpUrl http://$IP:8070/computer/245%2E207/jenkins-agent.jnlp -secret $SECRET -workDir "/home/jenkins" &
stop.sh
#!/bin/bash ps -ef | grep agent.jar | grep -v "grep" | awk '{print $2}' | xargs kill -9
envfile
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/git/bin HOME=/root
特别需要注意的是systemd启动的服务不同于直接从shell终端启动的服务,无法继承终端里的各种环境变量。所以对于jenkins构建过程中需要用到的各种环境变量,都需要在envfile里单独指出。
-
systemctl daemon-reload && systemctl enable jenkins --now
启动服务,验证节点成功加入master
脚本支持参数解析
结合getopts,为普通的shell脚本增加命令行短参数,并对原始脚本中使用了read从stdin读取的变量增加命令行短参数支持,使得脚本既可以单独执行,从stdin读取用户输入,又可以被jenkins直接调用,通过短参数传递参数。
关键逻辑如下:
- 声明变量并赋予默认值,这些变量将同时被getops和read使用
- getops尝试解析短参数,并把得到的值赋予上一步声明的变量
- read前判断变量是否是默认值,是的话,再用read从stdin读取,否则跳过这步
例:
#!/usr/bin/env bash
# 默认值
image_origin="undefined"
target_path="undefined"
vim_readme="undefined"
chart_origin_branch="dev-master"
# 如果有对应的短参数,则覆盖默认值
function ParseFlag() {
# 解析短参数
while getopts ':i:t:v:b:' OPT; do
case $OPT in
i) image_origin="$OPTARG" ;;
t) target_path="$OPTARG" ;;
v) vim_readme="$OPTARG" ;;
b) chart_origin_branch="$OPTARG" ;;
?) ;;
esac
done
}
ParseFlag
# 如果是默认值,则从stdin读
if [ "${image_origin}" == "undefined" ]; then
read -p "从开发环境拉镜像[p]/从代码构建镜像[b]/手动放置镜像[a]" -r image_origin
fi
# 最终消费参数的值
if [ "z${image_origin}" == "zp" ]; then
echo "从开发环境拉镜像"
./pull.sh
elif [ "z${image_origin}" == "zb" ]; then
echo "从代码构建镜像"
./build.sh -c y all "${version}"
elif [ "z${image_origin}" == "za" ]; then
echo "手动放置镜像,跳过"
else
echo "错误的选项"
exit 1
fi
node-gyp离线问题
项目依赖使用了node-gyp,会在构建期依赖公网的nodejs代码,需要提前在基础镜像里放置并配置
FROM node:16.10.0-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk add --no-cache -U python3 && \
apk add --no-cache -U make && \
apk add --no-cache -U g++ && \
apk add --no-cache -U curl
WORKDIR /tarball
# node-gyp 在离线环境也需要下载文件,所以先预置在镜像里,同时需要安装g++
RUN curl -k -o node-v16.10.0-headers.tar.gz -L https://unofficial-builds.nodejs.org/download/release/v16.10.0/node-v16.10.0-headers.tar.gz
RUN npm config set tarball /tarball/node-v16.10.0-headers.tar.gz \
其他插件
-
AnsiColor:支持shell中的彩色文字
# 红色文字输出,用于醒目提醒 function ColorEcho() { RED='\033[0;31m' # red NC='\033[0m' # No Color # $*可以接收数组 $1只能接字符串 echo -e "${RED}$*${NC}" }
-
Date Parameter:支持基于日期的环境变量
-
Extended Choice Parameter:多选框
-
Parameterized Trigger:构建后带参数触发其他任务
参考
如何在Jenkins中使用日期参数(变量) (shuzhiduo.com)
systemd配置开机自启动java脚本_浮生忆梦的博客-CSDN博客
在基于Docker的NodeJS工程中使用node-gyp - 简书 (jianshu.com)
https://stackoverflow.com/a/64052237/6792174
「Jenkins Pipeline」- 使控制台彩色化输出(使用 AnsiColor 插件) @20210307_研究林纳斯的那个系统的博客-CSDN博客
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。