简单使用jenkins学习CI/CD工作流

简单使用jenkins学习CI/CD工作流

TangSong404 Lv3

据粗略感受, jenkins是一个比gitlab功能更强大、可自定义化更高的持续集成工具
它可以简单的通过webhook被触发(本质上是对它的一个网址进行POST),然后通过pipeline来执行一系列的操作,可以说它允许安装的插件有多少,可执行的操作就有多少。

测试配置

由于手上暂时没有公网ip,所以gitlab,jenkins,服务器都跑在本地

部署gitlab

在你打算存储gitlab配置文件的路径下,执行

1
docker run -itd -p 9980:80 -p 9922:22 -v ./etc:/etc/gitlab -v ./log:/var/log/gitlab -v ./opt:/var/opt/gitlab --restart always --privileged=true --name gitlab gitlab/gitlab-ce

运行docker exec -it gitlab bash进入终端
编辑配置文件/# vi /etc/gitlab/gitlab.rb
在文件开头稍微往下的地方找到external_url的注释
在其下方添加

1
2
external_url 'http://192.168.8.246:9980'                                                           
nginx['listen_port'] = 80

不然的话,可能无法正常git仓库操作(因为会将ip识别为容器ip)
在保存后重新载入配置gitlab-ctl reconfigure

启动后访问http://localhost:9980,管理员用户名是root
初始密码通过docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password获得
在管理员面板找到’网络’,然后找到一个设置,大概是允许本机访问,否则无法与jenkins通信

部署jenkins

1.不建议安装最新版,下面的镜像比较稳定

1
docker run -u root -d -p 8080:8080 -p 50000:50000 -v jenkins-data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock --name jenkins jenkins/jenkins:2.479.3-lts

进入localhost:8080,初始密钥通过docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword获得
先选择安装推荐的插件,进入dashboard

2.安装完成后,点击系统管理-系统设置,定位到Jenkins Location
Jenkins URLlocalhost:8080修改为本机ip,例如http://192.168.1.100:8080

测试一:GitLab新推送邮件通知

这个测试实现了GitLab在新推送代码时,通过jenkins发送邮件通知
该测试需要有一个SMTP服务器,这里推荐免费的https://www.mailersend.com/

GitLab推送触发jenkins任务

1.首先在jenkins系统管理-插件管理中安装generic-webhook-trigger插件并重启
新建任务-构建一个自由风格的软件项目,暂且命名为jenkins_test_smtp
进入任务点击配置,在构建触发器下选择Generic Webhook Trigger
找到Token,随便填入一个字符串,建议用任务名jenkins_test_smtp
再找到Build Steps,添加一个Execute shell,内容如下

1
echo "new commit..."

这可以确保在新推送时,jenkins会执行这个shell脚本,就算不发送邮件我们也能在任务的控制台看到输出,这一步好了记得保存

2.在gitlab上打开你的项目,在设置中找到Webhooks,添加一个webhook
名称随便取一个jenkins_test_smtp
URL填写http://<Jenkins URL>:8080/generic-webhook-trigger/invoke?token=<你刚刚填的Token>
Trigger选择推送事件
可以点击下方的“测试”按钮测试是否能触发jenkins任务,如果提示“Hook executed successfully: HTTP 200”则说明配置成功
image11.png
这时候来到jenkins任务的控制台,观察是否有new commit...的输出
image12.png

jenkins自动发送邮件

1.首先在jenkins系统管理-插件管理中安装Email Extension插件并重启
先要预先配置好smtp的凭证,打开系统管理-凭据管理,添加一个全局凭据
类型是"Username with password",用户名和密码填写你自己的smtp账号和密码,
随便设一个id后面要用smtp-id
image13.png
点开系统管理-系统设置,定位到Jenkins Location系统管理员邮件地址设为你的smtp账号
同样的页面定位到Extended E-mail Notification
SMTP服务器设为你自己的smtp服务器厂商,例如smtp.mailersend.net
SMTP端口设为你的smtp端口,例如587
点开高级SMTP凭证设为你之前创建的凭证smtp-id
注意根据你的smtp服务商的协议具体选择’SSL’或’TLS’或’OAuth2’
image14.png

2.让我们重新回到jenkins_test_smtp任务的配置
找到构建后操作,添加一个Editable Email Notification
Project From设置为你的smtp账号
Project Recipient List填入收信人邮箱,多个中间用英文逗号分隔
Content Type看你发送什么内容而定
Default Subject标题
Default Content内容
Advanced Settings打开,找到Trigger,里面新增触发器,一般测试选择Success,这会在构建任务成功后发送邮件,注意Send To设为Recipient List
保存后现在就可以推送一次看看效果

webhook读取变量填充到邮件

重新定位回构建触发器Generic Webhook Trigger下方
我们可以依次添加Variable-Expression如下,这能从githab的请求中读取到值并存到当前变量中
project_name-$.project.name
branch-$.ref
user_name-$.user_name
commit_msg-$.commits[0].message
然后修改邮件的标题

1
仓库 ${project_name} 有新的推送消息

以及邮件的正文,注意Content Type设为HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html>
<head>
<style>
.card {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
max-width: 500px;
border: 1px solid #e1e4e8;
border-radius: 8px;
overflow: hidden;
color: #24292e;
}
.header {
background-color: #2f363d;
color: #ffffff;
padding: 15px;
font-size: 18px;
font-weight: bold;
}
.content {
padding: 20px;
line-height: 1.6;
}
.label {
color: #586069;
font-size: 12px;
text-transform: uppercase;
margin-bottom: 4px;
display: block;
}
.value {
font-size: 15px;
margin-bottom: 15px;
display: block;
font-weight: 500;
}
.commit-box {
background-color: #f6f8fa;
border-left: 4px solid #0366d6;
padding: 10px;
font-family: monospace;
white-space: pre-wrap;
}
.footer {
background-color: #f6f8fa;
padding: 10px 20px;
font-size: 12px;
color: #6a737d;
text-align: right;
}
</style>
</head>
<body>
<div class="card">
<div class="header">
🚀 Git 推送通知
</div>
<div class="content">
<span class="label">项目仓库</span>
<span class="value"><strong>${project_name}</strong></span>
<span class="label">推送分支</span>
<span class="value"><code>${branch}</code></span>
<span class="label">推送人员</span>
<span class="value">${user_name}</span>
<span class="label">提交信息</span>
<div class="commit-box">${commit_msg}</div>
</div>
<div class="footer">
来自 Jenkins 自动化系统
</div>
</div>
</body>
</html>

最后实现的效果如下
image15.png

测试二:GitLab推送同步到GitHub

获取凭证

1.首先需要获取与gitlab的凭证,我们进入jenkins的终端
docker exec -it jenkins bash
通过指令生成私钥与公钥
ssh-keygen -t rsa -b 4096 -C "jenkins-sync"
查看公钥,复制到gitlab个人设置的SSH Keys中
cat ~/.ssh/id_rsa.pub
image-30.png
然后先退出容器终端,并将私钥下载下来
docker cp jenkins:/root/.ssh/id_rsa ./id_rsa_backup

在jenkins系统管理-凭据管理中添加一个全局凭据,我命名它为gitlab-ssh-id
类型是"Secret file",文件上传你下载的私钥
这样我们就能正常对gitlab仓库进行git操作了

2.现在要获取与github的凭证,点击个人设置找到Developer settings
其中有Personal access tokens,点击生成一个新的token(classic),要选择repo权限
image-31.png

然后我们返回jenkins系统管理-凭据管理中添加一个全局凭据,我命名它为github-id
类型是"Username with password",用户名是你自己的github账号,密码就是你复制的token
这样我们就能正常对github仓库进行git操作了

配置同步任务

这次以流水线(pipeline)的方式创建任务,
依旧选择webhook触发,触发器的配置过程就不赘述了
但是触发器得配置这两个变量才能拿到仓库和分支的路径
gitlabSourceRepoHttpUrl-$.repository.git_http_url
ref-$ref

流水线的脚本定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
pipeline {
agent any

environment {
// 这里替换为你的gitlab ip
GL_HOST = "192.168.8.246"
// 这里替换为你的gitlab ssh端口(不是web端口)
GL_SSH_PORT = "9922"
// 这里替换为你的github仓库地址
GH_REPO_BASE = "github.com/SugarSong404/jenkins_test.git"
}

stages {
stage('同步仓库') {
steps {
withCredentials(
//这里的gitlab-ssh-id是我们之前添加的全局凭据
[file(credentialsId: 'gitlab-ssh-id', variable: 'SSH_KEY'),
//这里的github-id也是我们之前添加的全局凭据
usernamePassword(credentialsId: 'github-id', usernameVariable: 'GH_USER', passwordVariable: 'GH_TOKEN')]) {
sh """
mkdir -p ~/.ssh

ssh-keyscan -p ${env.GL_SSH_PORT} ${env.GL_HOST} >> ~/.ssh/known_hosts

chmod 400 \${SSH_KEY}

export GIT_SSH_COMMAND="ssh -i \${SSH_KEY} -o IdentitiesOnly=yes"

PROJECT_PATH=\$(echo "${gitlabSourceRepoHttpUrl}" | sed 's|http://[^/]*/||')

GL_SSH_URL="ssh://git@${GL_HOST}:${GL_SSH_PORT}/\${PROJECT_PATH}"

echo ">>> 开始从 GitLab 克隆 (SSH): \$GL_SSH_URL"

rm -rf sync_tmp.git
git clone --mirror \$GL_SSH_URL sync_tmp.git
cd sync_tmp.git

GH_PUSH_URL="https://${GH_USER}:${GH_TOKEN}@${GH_REPO_BASE}"

echo ">>> 正在推送到 GitHub (Token)..."
git push --mirror \$GH_PUSH_URL
"""
}
}
}
}

post {
always {
deleteDir()
}
success {
echo "同步成功!"
}
failure {
echo "同步失败,请检查 Jenkins 日志。"
}
}
}

其实就是在jenkins中先克隆gitlab仓库,然后原样推送到github仓库
运行的结果如下
image-32.png
现在每次推送到gitlab中的代码都会自动同步到github仓库中

测试三:对web代码进行测试的Agent

配置Agent

jenkins还可以将复杂的任务分布到多个node上进行分布式执行,这些node可以部署在不同的机器上,它们一般被称为slave(旧称)或agent


现在我们部署一个专门将仓库的推送进行测试的Agent(还是部署在本地)
具体操作是jenkins系统管理-节点和云管理中添加一个新的节点,
我命名它为agent-node,添加为固定节点
启动方式为"Launch agents via Java Web Start"
label(标签)是你Pipeline中使用这个agent的标签,我同样设为了agent-node
一般远程工作目录配置的是/home/jenkins/agent
image-40.png
保存后点进agent可以看到上图一些快捷启动指令,
我们不用这些指令启动而是用docker的jenkins/inbound-agent便捷部署
但是要记一下其中的一些字段
比如urlagent-nameagent-secretagent-dir


jenkins/inbound-agent不带有npm与node,所以需要自己写下dockerfile,可以换个源快一点

1
2
3
4
5
6
7
8
9
10
11
FROM jenkins/inbound-agent

USER root

RUN sed -i 's|http://deb.debian.org|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources \
&& sed -i 's|http://security.debian.org|https://mirrors.tuna.tsinghua.edu.cn/debian-security|g' /etc/apt/sources.list.d/debian.sources \
&& apt-get update \
&& apt-get install -y nodejs npm \
&& rm -rf /var/lib/apt/lists/*

USER jenkins

构建一下镜像
docker build -t jenkins-agent-node .
然后运行

1
2
3
4
5
6
7
8
docker run -d \
--name jenkins-agent-build \
-e JENKINS_URL=<url> \
-e JENKINS_AGENT_NAME=<agent-name> \
-e JENKINS_SECRET=<agent-secret> \
-e JENKINS_WEB_SOCKET=true \
-v jenkins-agent-build:<agent-dir> \
jenkins-agent-node

然后日志中就可以看到连接成功
image-41.png

简单测试项目以及Pipeline

1
2
3
4
5
6
7
8
9
10
11
//__test__/test.app.js
const request = require('supertest')
const app = require('../app')

describe('GET /', () => {
it('responds with 200 and correct message', async () => {
const res = await request(app).get('/')
expect(res.statusCode).toBe(200)
expect(res.text).toBe('Hello, Node.js CI/CD with Jest!')
})
})
1
2
3
4
5
6
7
8
9
//app.js
const express = require('express')
const app = express()

app.get('/', (req, res) => {
res.send('Hello, Node.js CI/CD with Jest!')
})

module.exports = app
1
2
3
4
5
6
//server.js
const app = require('./app')

app.listen(3000, () => {
console.log('Server running on port 3000')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//pacakge.json
{
"name": "jenkins_test_node",
"version": "1.0.0",
"description": "jenkins_test_node",
"main": "app.js",
"scripts": {
"start": "node app.js",
"test": "jest"
},
"dependencies": {
"express": "^4.18.2",
"pm2": "^6.0.14"
},
"devDependencies": {
"jest": "^29.6.1",
"supertest": "^6.3.3"
}
}

配置下方的pipline,建立好webhook,推送上方的项目,即可完成测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
pipeline {
// 切换为专门的Agent
agent { label 'agent-node' }
stages {
// 这种语法(来自Git Plugin)能从git仓库中自动检出代码到本机
// 这里我用了gitlab的access tokens来建立连接
stage('Checkout') {
steps {
echo 'Checking out code from GitLab...'
git url: 'http://tangsong404:glpat-lvSloDT6rtlX1Wr3hwYj4286MQp1OnkH.01.0w0fc114j@192.168.8.246:9980/tangsong404/test_jenkins.git', branch: 'master'
}
}
stage('Install') {
steps {
echo 'Installing dependencies...'
sh 'npm install'
}
}
stage('Test') {
steps {
echo 'Running tests...'
sh 'npm test'
}
}
}
post {
success {
echo '恭喜!流水线跑通了!'
}
failure {
echo '出错了,请检查上面的日志。'
}
}
}

image-42.png
和直接用一整套Stage相比,多 Agent Pipeline 的优势在于:不同 stage 可以跑在不同主机上,环境隔离、互不干扰;可以并行利用资源加快构建;支持不同语言和工具链分离;实现权限隔离和故障隔离;易于横向扩展,并能跨操作系统或动态创建临时 agent,使 CI 高效、安全且可扩展。

  • Title: 简单使用jenkins学习CI/CD工作流
  • Author: TangSong404
  • Created at : 2026-03-10 00:00:00
  • Updated at : 2026-03-10 06:30:46
  • Link: https://www.tangsong404.top/2026/03/10/work/ci_cd/jenkins_test/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments