Jenkins 流水线实战:拉码、构建、发布与企微通知

Jenkins 装好、SonarQube 能扫之后,我把整条链路串了一遍:开发推代码到 GitLab,Jenkins 自动拉取、扫描、打包,分发到 WEB 服务器完成切换,最后往企业微信群里发一条通知。这篇文章把这套流程的每一段拆开讲清楚,包括那个”软链切换”的发布方案——它是整条链路里最值得抄走的设计。

一、先看整条链路的全貌

1
2
3
4
5
6
7
8
9
10
11
12
13
开发 push 代码
│
▼
GitLab 仓库 ── webhook 触发 ──► Jenkins
│ 1. 拉取代码(SSH 密钥)
│ 2. SonarQube 代码扫描
│ 3. 打包 tar.gz
▼
scp 分发到 WEB 服务器
│ 4. 解压到按时间命名的目录
│ 5. 软链 html → 新版本目录(秒级切换)
▼
企业微信通知构建结果

技术含量不在”自动化”三个字,而在几个细节:发布目录按时间命名可追溯、软链切换可秒回滚、扫描和通知都挂在同一条流水线上。

二、让 Jenkins 能拉到 GitLab 的代码

先在 GitLab 建好仓库、把代码推上去,然后回 Jenkins 操作:

  1. 新建自由风格项目,源码管理选 Git,填仓库地址(git@10.0.8.200:ops/game.git);
  2. Jenkins 服务器生成密钥对,公钥贴到 GitLab 的 SSH Keys 页面:
1
2
ssh-keygen -t rsa -b 2048      # 一路回车
cat ~/.ssh/id_rsa.pub # 复制内容贴到 GitLab
  1. 第一次手动克隆一次,回答 yes 把主机指纹写进 known_hosts——这步不能省,否则 Jenkins 里构建时卡在指纹确认上:
1
git clone git@10.0.8.200:ops/game.git /tmp/test_clone   # 输入一次 yes
  1. 回项目页面点”立即构建”,构建成功后验证工作目录:
1
2
ls /var/lib/jenkins/workspace/game_job/
# 能看到仓库里的代码文件,说明拉取链路通了

如果项目配置页还在报错,保存退出再重新进一次——页面缓存引起的误报,遇到过两次。

三、把代码发布到 WEB 服务器

WEB 侧先准备好:装 Nginx,站点目录指向 /code/html:

1
2
3
4
5
6
7
8
9
# web01 上的 Nginx 站点配置
server {
listen 80;
server_name localhost;
location / {
root /code/html;
index index.html index.htm;
}
}

然后做 Jenkins 到 WEB 的免密,再写构建脚本:

1
ssh-copy-id -i ~/.ssh/id_rsa.pub 10.0.8.7

构建时执行的 Shell,核心是”打包 → 分发 → 解压 → 换软链”四步:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DATE=$(date +%Y-%m-%d-%H-%M-%S)
CODE_DIR="./"
WEB_DIR="/code"

get_code_tar(){
cd $CODE_DIR && tar zcf /opt/web-$DATE.tar.gz ./*
}
scp_code_web(){
scp /opt/web-$DATE.tar.gz 10.0.8.7:$WEB_DIR
}
code_tarxf(){
ssh 10.0.8.7 "cd $WEB_DIR && mkdir web-$DATE && tar xf web-$DATE.tar.gz -C web-$DATE"
}
ln_html(){
ssh 10.0.8.7 "cd $WEB_DIR && rm -rf html && ln -s web-$DATE html"
}
main(){
get_code_tar
scp_code_web
code_tarxf
ln_html
}
main

这个方案的精妙之处在最后一步:Nginx 始终读 html 这个软链,切换版本只是改指向。

  • 发布:新版本解压到 web-2024-04-21-10-30-00 目录,软链指过去;
  • 回滚:软链指回上一个目录,一条命令,秒级完成;
  • 追溯:每个时间戳目录就是一次发布记录,磁盘写不下旧的直接删。

比起”覆盖式”发布(直接往站点目录里覆盖文件),这套方案发布和回滚都是原子操作,不会出现”一半新一半旧”的中间状态。我后来把这套模式复制到了所有静态站点的发布上。

四、webhook:让一切自动发生

前面还要手动点”立即构建”,webhook 把它也省了:

  1. Jenkins 项目里勾选触发器,生成一个 Token 并保存;
  2. 到 GitLab 项目的 Webhooks 设置里,填 Jenkins 地址 http://10.0.8.201:8082/job/game_job/build?token=<你的Token>;
  3. 测试:改一行代码推送到 GitLab,观察 Jenkins 自动开始构建。

验证方法很直接:推代码后去 Jenkins 看构建历史里有没有新的构建记录,有就通了。没通的话先查 GitLab 的网络出口能不能访问到 Jenkins(内网防火墙很常见)。

五、质量门禁:集成 SonarQube

装好扫描器之后,把它挂进项目构建步骤:

  1. 系统管理 → 系统设置 → SonarQube Server:填名称、URL http://10.0.8.203:9000、认证 Token(存成 Secret text 类型);
  2. 全局工具配置:填 sonar-scanner 的安装目录,让 Jenkins 找得到命令;
  3. 项目构建步骤里加”Execute SonarQube Scanner”,指定 projectKey 和扫描目录。

有一个顺序问题必须注意:扫描步骤要放在打包 Shell 的前面。扫描失败(质量不达标)就不该打包分发——这个顺序错了,门禁就形同虚设,代码照样上线。

六、构建结果通知:企业微信

构建完了得让人知道结果,我们用的是企业微信应用消息:

  1. 注册企业微信,创建应用,拿到 AgentId 和 Secret,填入通知脚本;
  2. 通知脚本放到 Jenkins 服务器上(如 /server/scripts/jenkins_notify.py),依赖 requests 库;
  3. 本地先单独测一次脚本,确认能发出消息:
1
2
pip install requests
python jenkins_notify.py <构建URL> /tmp/changelog.log <项目名>
  1. Jenkins 侧安装通知插件,在项目里配置构建后步骤:
1
2
3
4
echo "==========Start Notify=============="
echo ${SCM_CHANGELOG} > /tmp/${JOB_NAME}_change.log
python /server/scripts/jenkins_notify.py ${BUILD_URL} /tmp/${JOB_NAME}_change.log ${JOB_NAME}
rm -fv /tmp/${JOB_NAME}_change.log

插件配置里 Entry Format 填 %3$s(at %4$s via %1$s)(提交信息、时间、提交人),Date Format 填 yyyy-MM-dd HH:mm:ss,通知里就能带上”谁、什么时候、改了什么”。

七、从自由风格到 Pipeline,再到版本发布

自由风格项目图形化配置,上手快,但流程一多就乱——构建步骤散在页面里,没法版本化,换台机器就要重新点一遍。Pipeline 的价值就是把流程写成代码,放进仓库跟代码一起管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pipeline {
agent any
stages {
stage('拉取代码') {
steps { checkout scm }
}
stage('代码扫描') {
steps {
sh 'sonar-scanner -Dsonar.projectKey=game -Dsonar.sources=.'
}
}
stage('打包分发') {
steps { sh 'bash /opt/scripts/deploy.sh' }
}
}
post {
success { echo '通知企业微信:构建成功' }
failure { echo '通知企业微信:构建失败' }
}
}

最后是版本发布环节。稳定版本打 tag,Jenkins 通过 Git Parameter 插件按标签拉取指定版本:

1
2
3
# 开发侧:给稳定版本打标签并推送
git tag -a v1.0.1 -m "v1.0.1"
git push origin v1.0.1

Jenkins 项目里装 Git Parameter 插件,构建时把”参数化构建”的变量换成 Git Parameter,类型选 Tag——之后每次构建都可以从版本列表里选一个 tag 拉取。发布、测试、回滚都能按版本精确操作,不再靠”最新代码碰运气”。

一点复盘

这套链路跑顺之后,发版从”我手动折腾十分钟”变成”开发推代码、两分钟后群里收到通知”。回看整个过程,最值钱的其实是三样东西:软链切换的发布方案、扫描前置的门禁顺序、tag + 参数化的版本管理。工具会换,这三个做法在哪套 CI 里都用得上。