
知识是人生的灯塔,只有不断学习,才能照亮前行的道路
📢 大家好,我是 WeiyiGeek,一个正在向全栈工程师(SecDevOps)前进的计算机技术爱好者,欢迎各位道友一起学习交流、一起进步 🚀,若此文有帮助请点个关注,后续追番不迷路 ❤️。
解锁 Jenkins Agent 技巧,容器化轻松实现分布式构建节点扩展
描述:Jenkins 是一个开源的自动化构建工具,广泛用于持续集成和持续部署(CI/CD),它通过插件支持多种编程语言和构建工具,所以其功能非常的强大。为了处理大规模的项目或高并发场景,Jenkins 支持分布式构建架构,允许将任务分散到多个节点上执行。Jenkins Agent 是 Jenkins 实现分布式构建的关键组件,通过将任务分发到不同节点,显著提升了 CI/CD 的效率和灵活性。合理使用固定 Agent 和动态 Agent,可以平衡稳定性和成本。此处 Jenkins 介绍安装就不在累述,不了解的童鞋 推荐参考作者以前发布的【Jenkins】专栏。
本文将介绍 Jenkins Agent 使用技巧,作者从实践视角出发,通过使用 Docker 搭建部署 Jenkins Agent 容器环境,并通过 SSH 方式快速接入,从而轻松实现分布式构建节点,最后使用加入的Agent节点,用于构建作者以 Golang 开发的运维Api接口项目。

前置知识
什么是 Jenkins Agent?
Jenkins Agent(也称为 Jenkins 节点或从节点)是 Jenkins 分布式构建架构中的工作节点,用于执行主节点(Master)分发的任务(如代码构建、测试、部署等)。它允许将工作负载分散到多台机器上,提高并发处理能力和资源利用率。
什么是主节点(Master)、代理节点(Agent)
描述:在 Jenkins 中,主节点(Master
,实际上就是部署的 jekins 服务那台主机就是主节点)是控制中心,负责管理任务、插件配置和用户界面
,通常不直接执行耗时任务。代理节点(Agent
)也称工作节点,它是执行实际构建任务的机器
,可以是固定节点也可是动态扩展,支持不同操作系统和环境,可以是物理机、虚拟机、容器或 Kubernetes Pod。
Jenkins Agent 的类型
-
固定 Agent:常驻节点,手动配置(如专用服务器、虚拟服务器、容器)。
-
动态 Agent:按需创建(如通过 Kubernetes/Docker 临时启动,任务完成后销毁)。
-
云 Agent:集成云平台(AWS、Azure 等)自动扩缩容。
Jenkins Agent 核心功能
-
任务执行: 运行 Jenkins 分发的构建任务(如编译代码、运行测试)。
-
环境隔离: 不同 Agent 可以配置不同的工具链(JDK、Node.js 等),适配多项目需求。
-
负载均衡: 多个 Agent 并行处理任务,加快流水线速度。
-
资源扩展: 动态 Agent 在任务高峰期自动扩容,空闲时释放资源。
Jenkins Agent 的通信方式
-
SSH:通过 SSH 协议连接 Linux/Unix 节点,本文将使用Docker容器方式部署,传统物理机、虚拟机方式请参考:https://mp.weixin.qq.com/s/0w20D2Gs8JRK6Kb7lnTAhg
-
JNLP(Java Web Start):Agent 主动连接 Master(适用于防火墙限制场景),实践文章:https://mp.weixin.qq.com/s/0w20D2Gs8JRK6Kb7lnTAhg
-
Kubernetes:动态创建 Pod 作为临时 Agent(需安装 Kubernetes 插件),实践文章:https://mp.weixin.qq.com/s/EI0qd0YsyRyIbkS4msWAVQ
实践之路
环境介绍
go
# Docker 20.10.12 部署 Jenkins 2.387.3 (需要 JDK 11+)
$ docker ps | grep jenkins_server
d6b80d5b2fb6 jenkins/jenkins:2.387.3-alpine "/sbin/tini -- /usr/..." 13 months ago Up 1 months (healthy) 0.0.0.0:8080->8080/tcp, 0.0.0.0:8443->8443/tcp, 0.0.0.0:50000->50000/tcp jenkins_server
# Docker 20.10.12 部署 jenkins/ssh-agent:jdk11
$ docker ps | grep jenkins-ssh-agent
242249caaea6 jenkins/ssh-agent:jdk11 "setup-sshd" 8 days ago Up 8 days 0.0.0.0:2222->22/tcp jenkins-ssh-agent
操作步骤
1.首先,进入到 Jenkins Server 容器中,并且在 Jenkins 主节点上生成 SSH 密钥对。
go
$ docker exec -it jenkins_server bash
d6b80d5b2fb6:/$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file inwhich to save the key (/var/jenkins_home/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/jenkins_home/.ssh/id_rsa
Your public key has been saved in /var/jenkins_home/.ssh/id_rsa.pub
...
$ ls ~/.ssh/id_rsa*
/var/jenkins_home/.ssh/id_rsa /var/jenkins_home/.ssh/id_rsa.pub
# 分别打开两个文件,复制公钥、密钥内容
cat ~/.ssh/id_rsa -> Jenkins 凭据
cat ~/.ssh/id_rsa.pub -> Jenkins Agent 镜像所需瓶颈
2.然后,在 Jenkins 网页界面上,进入系统管理,选择 Credentials 管理,添加新的凭据,类型选择 SSH Username With Private Key 私钥,粘贴刚才生成的私钥内容,配置如下图所示。
weiyigeek.top-Jenkins中添加SSH凭据图
3.其次,在安装有 Docker 环境的的主机上,拉取并运行 Jenkins SSH Agent 镜像,直接一梭子搞定
go
# 创建jenkins-ssh-agent目录,用于持久化数据存储
mkdir -p /data/jenkins
chown -R 1000:1000 /data/jenkins
# 拉取 jenkins-ssh-agent 镜像,由于 Jenkins 2.387.3 中 agent.jar 运行环境最低需要 JDK 11+,所以这里选择 jdk11 版本镜像
docker pull jenkins/ssh-agent:jdk11
# 运行 jenkins-ssh-agent 容器,映射端口2222到宿主机,挂载密钥文件和 Docker socket,此处重点是JENKINS_AGENT_SSH_PUBKEY填写前面在控制节点生成的公钥。
docker run -d --name=jenkins-ssh-agent \
-p 2222:22 \
-v /data/jenkins:/home/jenkins \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-e "JENKINS_AGENT_SSH_PUBKEY=ssh-rsa AAAAB3NzaC1yc2EAAAADAQ*************注释****************sp4Uij6ykY0bd8= jenkins@d6b80d5b2fb6" jenkins/ssh-agent:jdk11
# 特别注意:此处有可能在构建上传镜像时出现权限不足的问题,这是由于我们在容器中直接使用了宿主机上的 /var/run/docker.sock ,而容器中使用的是 jenkins 用户所以导致权限不足,解决办法如下,宿主机中运行
$ chmod +666 /var/run/docker.sock
4.然后,在 jenkins 上添加 slave,返回到 Jenkins 网页界面上,进入系统管理,选择节点管理选项卡,点击 New Node 选择 SSH 方式添加 Agent,输入节点名称自定义即可,选择类型为固定节点
,然后按照如下图进行配置,特别注意红色圈中选项即可,需更加你实际配置进行填写,特别是设置标签以空格进行分割。
weiyigeek.top-Jenkins添加agent工作节点图
5.最后,点击保存,Jenkins 会自动通过 SSH 连接到 Jenkins Agent 容器并自动拉取 remoting.jar 文件,并且其容器中运行,可通过节点日志查看连接过程,当日志中出现 Agent successfully connected and online 则表示连接成功。
weiyigeek.top-查看节点连接日志图
6.至此,Jenkins Agent 已经成功添加到 Jenkins 主节点中,接下来就可以在 Jenkins 项目中使用该 Agent 进行 golang 项目构建工作了。
weiyigeek.top-节点列举图
7.构建 golang 项目之前,需要先准备 Dockerfile 我已经放在项目中,并上传到私有的Gitlab仓库中,若还没搭建过Gitlab代码仓库的同学可参考作者此篇【GitOps实践 | 快速在银河麒麟KylinOS国产系统部署最新Gitlab-CE企业私有代码仓库】文章。
go
# Dockerfile 内容如下,采用多阶段构建,先编译项目生成二进制文件,再拷贝到 alpine 镜像中运行。
FROM golang:1.20.4-alpine3.18 AS gin-build
MAINTAINER DevOpsApi Application v1.1.3 - <[email protected]> - WeiyiGeek
ENV GO111MODULE="on" GOPROXY="https://goproxy.cn,direct"
WORKDIR /app
COPY . "/app"
RUN GOOS=linux GOARCH=amd64 && go mod download && go mod verify && go build -v -o /app/devopsapi
FROM alpine:3.21.3
WORKDIR /app
COPY --from=gin-build /app/devopsapi /app/devopsapi
COPY --from=gin-build /app/configs /app/configs
COPY --from=gin-build /app/docs /app/docs
COPY --from=gin-build /app/static /app/static
COPY --from=gin-build /app/templates /app/templates
COPY ./setup.sh /app
RUN sed -i 's/dl-cdn.alpinelinux.org/mirror.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& apk update \
&& apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo"export LANG=zh_CN.UTF-8" > /etc/profile.d/locale.sh \
&& chmod +x /app/devopsapi /app/setup.sh
EXPOSE 8080
ENTRYPOINT ["/app/setup.sh"]
weiyigeek.top-基于Golang的API运维接口构建文件图
8.接下来,在 Jenkins 项目中配置构建流水线,名称为 itops-api
,采用流水线
方式,点击配置流水线,选择Pipeline script
方式,如下所示。
go
// 作者抽取了部分关键代码片段
// [ 全局变量]
def PRJECT = "ssh://[email protected]/devops/itops-api.git"
def PUBKEY = "5e2f46d9-6725-4988-847f-dafb3f29d0ce"
// [ 全局函数]
def ENV_TEST() {
def config = [:]
config.HARBOR_URL = "harbor.weiyiggek.top/app"
config.HARBOR_AUTH = "d0ce1239-c4bf-1256-a4c6-660ab70d9b47"
return config
}
// 任务名称、任务工作空间POD名称
def JOB_NAME = "${env.JOB_NAME}-${env.BUILD_NUMBER}"
def JOB_WORKSPACE = "${env.WORKSPACE}"
// 获取真实项目路径
def GET_REAL_PROJECT(){
def PROJECT = [:]
PROJECT.name="itops-api"
PROJECT.version="v1.1.8"
PROJECT.path=sh label:'pom_path',returnStdout:true, script:"""
find ${env.WORKSPACE} -name main.go | head -n 1 | tr -d '\n' | sed 's/main.go//g'
"""
PROJECT.commitmsg=sh label:'git_commitmsg',returnStdout:true, script:"""
git show --oneline --ignore-all-space --text | head -n 1 |tr -d '\\n'
"""
PROJECT.commitid=sh label:'git_commitid',returnStdout:true, script:"""
git show --oneline --ignore-all-space --text | head -n 1 | cut -d ' ' -f 1 |tr -d '\\n'
"""
PROJECT.imagename=sh label:'imagename',returnStdout:true, script:"""
echo \${JOB_NAME#*-} |tr -d '\\n'
"""
return PROJECT
}
// [ 流水线代码 ]
pipeline {
agent {
// 通过标签选择构建节点,此处选择就是就是 jenkins-ssh-agent节点
label 'ssh-agent'
}
options {
timeout(time:30, unit:'MINUTES')
}
// 自定义环境变量, 通过 env.变量名访问
environment {
// 代码仓库地址与认证地址
GITLAB_URL = "${PRJECT}"
GITLAB_PUB = "${PUBKEY}"
}
// 自定义选择参数,在 sh 中可通过变量名访问,而在 script pipeline 脚本中通过 params.参数名称 访问
parameters {
gitParameter branch:'', branchFilter:'origin/(.*)', defaultValue:'origin/master', description:'查看构建部署可用的Tag或Branch名称?', name:'TagBranchName', quickFilterEnabled:false, selectedValue:'NONE', sortMode:'DESCENDING_SMART', tagFilter:'*', type:'GitParameterDefinition'
string(name:'RELEASE_VERSION', defaultValue:"master", description:'Message: 请选择构建部署的Tag或Branch名称?', trim:'True')
choice(name:'PREJECT_ENVIRONMENT', choices: ['Test','Prod'], description:'Message: 选择项目部署环境?')
choice(name:'PREJECT_OPERATION', choices: ['None', 'deploy', 'rollback', 'redeploy','deployTest'], description:'Message: 选择项目操作方式?')
choice(name:'IS_IMAGEBUILD', choices: ['True','False'], description:'Message: 是否进行镜像构建操作?')
choice(name:'IS_RELEASE', choices: ['False','True'], description:'Message: 是否进行编译成品发布?')
}
// 主要阶段以及子阶段流程
stages {
// [ 阶段1.项目代码拉取 ]
stage ('代码拉取') {
steps {
// 1.构建信息输出
echo "任务名称: ${JOB_NAME}, 项目地址: ${env.GITLAB_URL}, 构建版本: ${params.RELEASE_VERSION}, 部署环境: ${params.PREJECT_ENVIRONMENT} \n 构建操作: ${params.PREJECT_OPERATION}, 镜像构建: ${params.IS_IMAGEBUILD} , 成品发布: ${params.IS_RELEASE},"
// 2.超时时间设置5分钟
timeout(time:5, unit:'MINUTES') {
script {
try {
checkout([$class:'GitSCM', branches: [[name:"${params.RELEASE_VERSION}"]], doGenerateSubmoduleConfigurations:false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId:"${env.GITLAB_PUB}", url:"${env.GITLAB_URL}"]]])
} catch(Exception err) {
echo err.toString()
error "[-Error] : 代码拉取失败\n [-Msg] : ${err.getMessage()} "
}
// .......此处省略部分代码...........
// 6.利用GET_REAL_PROJECT函数获取JAVA项目真实的构建空间路径以及获取pom.xml项目文件信息
project = GET_REAL_PROJECT()
// 7.验证部署环境进行预设环境参数值
if ( "${params.PREJECT_ENVIRONMENT}" == "Prod" ) {
config = ENV_PROD()
print "${params.PREJECT_ENVIRONMENT}"
} else {
config = ENV_TEST()
print "${params.PREJECT_ENVIRONMENT}"
}
// 8.通过企业微信进行构建通知
echo "项目真实路径: ${project.path} \n项目信息: ${project.name} ${project.version}\nCommit信息:${project.commitmsg} \n镜像仓库与名称:${config.HARBOR_URL}/${project.imagename}"
// .......此处省略部分代码...........
}
}
}
}
stage ("项目构建") {
steps {
script {
//仓库认证
withCredentials([usernamePassword(credentialsId:"${config.HARBOR_AUTH}", passwordVariable:'HARBOR_PWD', usernameVariable:'HARBOR_USR')]) {
sh """
docker login -u ${HARBOR_USR} -p ${HARBOR_PWD} ${config.HARBOR_URL}
"""
}
sh """
cd ${project.path} \
&& cat Dockerfile \
&& echo "${config.HARBOR_URL}/${project.imagename}:${params.PREJECT_ENVIRONMENT}" \
&& docker build -t ${config.HARBOR_URL}/${project.imagename}:${params.PREJECT_ENVIRONMENT} -t ${config.HARBOR_URL}/${project.imagename}:${project.version}-${params.PREJECT_ENVIRONMENT} . \
&& docker push ${config.HARBOR_URL}/${project.imagename}:${project.version}-${params.PREJECT_ENVIRONMENT}
"""
}
}
}
// .......此处省略部分代码...........
}
}
weiyigeek.top-Pipeline Script图
9.最后,点击保存,回到流水线列表界面,点击 Build with Parameters 按钮,选择合适的参数进行构建,测试效果如下:
weiyigeek.top-流水线构建图
若文章写得不错,不要吝惜手中转发,点赞、在看,若有疑问的小伙伴,可在评论区留言你想法哟💬!
欢迎各位看友加入到『 全栈工程师修炼指南』知识星球中,学习更多技能!
温馨提示:作者最近10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者账号[WeiyiGeeker],当前价格¥199,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!

学习推荐 往期文章
-
💡【相关】GitOps实践 | 企业生产环境Jenkins流水线分享,从Gitlab到镜像构建到部署测试以及企业微信消息通知
-
💡【相关】持续集成案例之使用Docker运行自构建Jenkins的Agent镜像固定工作节点实践(分享企业项目流水线代码)
如果此篇文章对你有帮助,请你将它转发给更多的人!

