3321 字
17 分钟
Jenkins (4):企业实战篇 —— 版本控制+多环境部署+容器化交付

Jenkins 基础(4):企业实战篇 —— 版本控制+多环境部署+容器化交付#

在前三篇教程中,我们从 Jenkins 的安装部署一路走到了声明式 Pipeline 的语法深水区。你可能已经掌握了如何在 Jenkins 里写 Shell 脚本、如何分配节点、如何控制阶段流转。但在真实的企业生产环境中,我们极少会去手动点击“Build Now”来触发部署。

真实的业务场景是:开发人员提交代码到 Git 仓库,自动触发测试和打包;根据分支的不同,自动部署到开发、测试或生产环境;而在云原生时代,最终的交付物往往不再是一个 Jar 包或一个 ZIP 压缩包,而是一个 Docker 镜像。

本文作为本系列的“实战收官之作”,将带你把前面的散落的知识点串联起来,落地到真实的业务场景中。我们将深度集成版本控制系统,分别演示后端(Java)和前端(Vue/React)项目的自动化部署,最后完成 Jenkins 与 Docker 的深度整合,打造一套真正达到企业生产标准的 CI/CD 交付流程!

一、开篇:落地真实业务场景,打造可用的CI/CD流程#

一个成熟的企业级 CI/CD 流程,通常需要满足以下几个核心诉求:

  1. 全自动化触发:消除人工干预,通过 WebHook 监听代码库的 Push 或 Merge Request 动作。
  2. 多环境隔离适配:同一套代码,dev 分支部署到开发服务器,main 分支发布到生产服务器,配置与凭证必须严格隔离。
  3. 安全与合规:代码拉取、服务器登录、镜像仓库推送,涉及的大量密码和私钥必须安全存储,禁止硬编码。
  4. 标准化交付:通过容器化技术(Docker),实现“构建一次,到处运行”,消灭环境不一致导致的玄学 Bug。

接下来,我们就一步步将这些诉求变成现实。

二、版本控制系统深度集成#

要让自动化的齿轮转动起来,第一步就是让 Jenkins 和你的代码仓库(如 GitLab、GitHub、Gitee)建立深度的连接。

2.1 WebHook 触发:提交代码自动触发构建#

WebHook(网络钩子) 是实现自动化触发的核心机制。简单来说:当你在 GitLab 上执行了 git push 后,GitLab 会自动向 Jenkins 预先配置好的一个 URL 发送一个 HTTP 请求(通知),Jenkins 收到通知后立即拉起对应的流水线。

实战配置步骤(以 GitLab 为例):

  1. Jenkins 端准备:

    • 安装插件:GitLab Plugin 和 Generic Webhook Trigger Plugin。
    • 在你的 Pipeline 任务配置页面,勾选 Build when a change is pushed to GitLab。
    • 记录下该选项旁边提示的 Jenkins WebHook URL(通常为 http://JENKINS_IP:8080/project/YOUR_PROJECT_NAME)。
    • 点击 Advanced (高级),点击 Generate 生成一个 Secret token(用于身份校验)。
  2. GitLab 端配置:

    • 进入你的代码仓库 -> Settings (设置) -> Webhooks。
    • URL 填入上面记录的 Jenkins WebHook URL。
    • Secret Token 填入生成的 Token。
    • Trigger (触发器) 勾选 Push events 和 Merge request events。
    • 取消勾选 Enable SSL verification(如果你的 Jenkins 是内网 HTTP 的话)。
    • 点击 Add webhook。
WebHook 测试

添加完成后,在 GitLab 页面点击底部的 Test -> Push events。如果页面顶部提示 Hook executed successfully: HTTP 200,说明打通成功!此时切回 Jenkins,你会发现流水线已经被自动触发了。

2.2 多分支流水线(Multibranch Pipeline)#

在传统的 Pipeline 项目中,一个任务通常只能固定拉取一个分支。如果公司有 dev、test、main 三个分支,难道要建三个一模一样的 Jenkins 任务吗?

Multibranch Pipeline(多分支流水线) 完美解决了这个问题。

  1. 在新建任务时,选择 Multibranch Pipeline。
  2. 在 Branch Sources 中选择 Git,填入仓库地址和凭证。
  3. Jenkins 会自动扫描该仓库下所有包含 Jenkinsfile 的分支,并为每个分支自动创建一个子任务!
多分支策略下的环境动态路由示例
pipeline {
agent any
environment {
// 根据内置变量 env.BRANCH_NAME 动态决定部署环境
DEPLOY_ENV = "${env.BRANCH_NAME == 'main' ? 'prod' : env.BRANCH_NAME}"
}
stages {
stage('Deploy') {
steps {
echo "当前分支为 ${env.BRANCH_NAME},准备发布到 ${DEPLOY_ENV} 环境..."
// 后续可根据 DEPLOY_ENV 加载不同的配置
}
}
}
}

2.3 凭证安全管理:SSH 密钥与账号密码规范#

在自动化部署中,Jenkins 需要频繁登录各种外部系统(拉取代码、推送镜像、SSH 登录服务器)。

安全红线

绝对禁止在 Jenkinsfile 或 Shell 脚本中明文写死密码(硬编码)!这不仅容易泄露,而且一旦密码修改,你需要去改几十个仓库的脚本。

正确的做法:统一在 Manage Jenkins -> Credentials 中管理。

  • Git 仓库拉取:创建 SSH Username with private key 凭证,填入具有仓库只读权限的私钥。
  • Docker 镜像仓库登录:创建 Username with password 凭证。
  • 目标服务器部署:在 Pipeline 中使用 withCredentials 指令安全调用。

三、后端项目实战:Java 服务自动化打包部署#

我们以一个典型的 Spring Boot 项目为例,演示如何使用 Maven 打包,并通过 SSH 将产物发送到目标服务器执行部署。

3.1 场景与插件准备#

  • 需求:将打出的 .jar 包上传到应用服务器的 /opt/apps/ 目录,并执行重启脚本。
  • 插件推荐:安装 Publish Over SSH 插件,它极大地简化了向远程服务器传文件和执行命令的配置。

在 Manage Jenkins -> System -> Publish over SSH 中,提前配置好你的目标服务器(如 app-server-dev 和 app-server-prod),填入 IP、用户名和 SSH 私钥。

3.2 Java 自动化部署 Pipeline#

Spring Boot 自动化构建与 SSH 部署流水线
pipeline {
agent any
tools {
maven 'maven-3.8.8' // 引用系统配置中定义的 Maven 工具
jdk 'jdk-17'
}
options {
timestamps()
disableConcurrentBuilds()
}
environment {
APP_NAME = 'user-service'
}
stages {
stage('1. Maven Build') {
steps {
echo "开始编译打包..."
// 执行 Maven 编译,跳过单元测试加快打包速度
sh "mvn clean package -DskipTests"
}
}
stage('2. Deploy via SSH') {
steps {
echo "开始部署到目标服务器..."
// 使用 Publish Over SSH 插件的 sshPublisher 语法
// 注意:这里 configName 的值需与系统设置中配置的服务器名称完全一致
sshPublisher(publishers: [
sshPublisherDesc(
configName: 'app-server-dev',
transfers: [
sshTransfer(
sourceFiles: 'target/*.jar',
removePrefix: 'target/',
remoteDirectory: '/opt/apps/user-service/',
// 传输完成后在目标服务器执行的重启命令
execCommand: '''
cd /opt/apps/user-service
# 优雅停机并备份
ps -ef | grep user-service.jar | grep -v grep | awk '{print $2}' | xargs -r kill -9
mv user-service.jar user-service-$(date +%Y%m%d%H%M%S).jar.bak || true
# 启动新版本
mv *.jar user-service.jar
nohup java -jar -Xms512m -Xmx512m user-service.jar > app.log 2>&1 &
echo "服务已成功启动!"
'''
)
]
)
])
}
}
}
}

四、前端项目实战:Vue/React 项目自动化构建部署#

前端项目的部署逻辑通常比后端简单,本质上就是编译出静态文件(HTML/CSS/JS),然后放到 Nginx 等 Web 服务器的静态目录中。

4.1 Node 环境全局配置#

前端打包强依赖 Node.js。推荐安装 NodeJS Plugin。 在 Manage Jenkins -> Global Tool Configuration 中配置好 Node.js 版本(如 node-18)。

4.2 前端自动化部署 Pipeline#

为了提升传输效率,前端动辄成千上万个碎文件的 dist 目录,必须先压缩成一个包,传输到服务器后再解压。

Vue/React 静态资产构建与分发
pipeline {
agent any
tools {
nodejs 'node-18' // 自动注入 node 和 npm 命令
}
stages {
stage('1. Install Dependencies') {
steps {
echo "安装前端依赖..."
sh 'npm config set registry https://registry.npmmirror.com'
sh 'npm install'
}
}
stage('2. Build Project') {
steps {
echo "开始前端打包..."
sh 'npm run build'
// 将打包产物 dist 目录压缩,极大加快网络传输速度
sh 'tar -zcvf dist.tar.gz dist/'
}
}
stage('3. Sync to Nginx') {
steps {
// 这里演示另一种部署方式:直接使用 ssh 命令行配合 credentials
withCredentials([sshUserPrivateKey(credentialsId: 'nginx-server-key', keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
sh '''
echo "上传压缩包到 Nginx 服务器..."
scp -i $SSH_KEY -o StrictHostKeyChecking=no dist.tar.gz $SSH_USER@192.168.1.100:/tmp/
echo "在远程执行解压和替换操作..."
ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SSH_USER@192.168.1.100 "
cd /usr/share/nginx/html &&
rm -rf ./my-web-app/* &&
tar -zxvf /tmp/dist.tar.gz -C ./my-web-app --strip-components=1 &&
rm -f /tmp/dist.tar.gz
"
'''
}
}
}
}
}

五、容器化集成:Jenkins + Docker 镜像构建与推送#

前面讲的直接传 Jar 包或静态文件的方式,属于传统的物理机/虚拟机部署模式。在云原生时代,我们更推荐容器化交付。

Jenkins 的职责变为:拉取代码 -> 编译产物 -> 打包成 Docker 镜像 -> 推送到私有镜像仓库 -> 通知目标服务器拉取新镜像并启动。

5.1 Docker Pipeline 插件用法#

请确保 Jenkins 宿主机已安装 Docker,且赋予了 jenkins 用户执行 docker 命令的权限(将 jenkins 用户加入 docker 用户组:usermod -aG docker jenkins)。

安装 Docker Pipeline 插件,它提供了极其优雅的内置语法来处理镜像构建与推送。

5.2 容器化部署完整 Pipeline#

我们需要在代码仓库根目录准备好 Dockerfile。以下是一套极其标准的企业级容器化发布流程:

Jenkins + Docker 容器化交付全流程
pipeline {
agent any
environment {
// 定义镜像相关信息
IMAGE_NAME = "my-registry.com/my-group/api-service"
// 使用 Jenkins 的构建号作为镜像的 Tag,实现版本可追溯
IMAGE_TAG = "v1.0.${env.BUILD_NUMBER}"
REGISTRY_CRED_ID = "harbor-auth-cred"
}
stages {
stage('1. Compile Code') {
steps {
// 此处省略 Maven/Node 编译步骤,假设已生成可执行文件到 target/ 目录
echo "代码编译完成"
}
}
stage('2. Build Docker Image') {
steps {
echo "开始构建 Docker 镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
script {
// 使用 docker 插件内置方法构建镜像
// 会自动寻找当前目录下的 Dockerfile
dockerImage = docker.build("${IMAGE_NAME}:${IMAGE_TAG}")
}
}
}
stage('3. Push to Registry') {
steps {
echo "推送镜像到私有仓库..."
script {
// 使用 withRegistry 自动处理 docker login
// 第一个参数是仓库 URL,第二个是凭证 ID
docker.withRegistry('https://my-registry.com', REGISTRY_CRED_ID) {
dockerImage.push()
// 顺便打一个 latest 标签并推送
dockerImage.push('latest')
}
}
}
}
stage('4. Clean Local Image') {
steps {
echo "清理 Jenkins 本地的废弃镜像,防止磁盘空间耗尽..."
sh "docker rmi ${IMAGE_NAME}:${IMAGE_TAG} || true"
}
}
stage('5. Trigger Remote Deployment') {
steps {
// 通知目标服务器拉取新镜像并重启容器
withCredentials([sshUserPrivateKey(credentialsId: 'prod-server-key', keyFileVariable: 'SSH_KEY')]) {
sh """
ssh -i \$SSH_KEY -o StrictHostKeyChecking=no root@192.168.1.200 '
# 登录镜像仓库
docker login -u "\$REGISTRY_USER" -p "\$REGISTRY_PWD" my-registry.com
# 拉取最新镜像
docker pull ${IMAGE_NAME}:${IMAGE_TAG}
# 重启服务 (假设使用 docker-compose)
cd /opt/deploy/api-service
# 修改 .env 文件中的镜像 TAG
sed -i "s/IMAGE_VERSION=.*/IMAGE_VERSION=${IMAGE_TAG}/g" .env
docker-compose up -d
'
"""
}
}
}
}
}
容器化交付的巨大优势

仔细观察上述流程,你会发现目标服务器上不再需要安装 Java、Node.js 甚至不需要 Nginx。只要目标服务器有 Docker 环境,它就能跑起来。所有的环境依赖都被封印在了 Docker 镜像中,彻底消灭了“依赖地狱”。

六、自动化测试集成:单元测试报告接入与结果联动#

CI/CD 中的 CI(持续集成)最重要的环节就是测试。代码不仅要能编译通过,更要保证功能逻辑的正确性。

如果测试框架(如 Java 的 JUnit,前端的 Jest)生成了 XML 格式的测试报告,我们可以将其无缝集成到 Jenkins 的面板中直观展示。

集成 JUnit 测试报告示例:

集成单元测试报告
stage('Test') {
steps {
echo "执行单元测试..."
// 即使测试失败,也允许执行后续的报告解析动作
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh "mvn test"
}
}
post {
always {
echo "收集并解析 JUnit 测试报告..."
// junit 指令会自动解析 target/surefire-reports 下的 xml 文件
// 并在 Jenkins 任务面板生成一个漂亮的测试趋势图
junit 'target/surefire-reports/*.xml'
}
}
}

当单元测试失败时,Jenkins 会将构建状态标记为黄色的 UNSTABLE(不稳定状态),你可以据此在 Pipeline 中中断后续的部署环节,防止带着 Bug 的代码上线。

七、本篇核心知识点复盘#

到此为止,我们已经搭建出了一套具备企业级水准的自动化流水线,实现了从代码提交到容器部署的完整闭环。本篇重点复盘如下:

  1. 自动化触发的核心:通过 WebHook,将 GitLab/GitHub 的代码事件与 Jenkins 构建无缝桥接,真正解放了开发人员的双手。
  2. 多分支策略的优雅:使用 Multibranch Pipeline,一个配置搞定所有分支,配合环境变量动态路由部署目标。
  3. 安全底线:全程使用 Credentials 插件与 withCredentials 指令处理所有敏感信息。
  4. 后端与前端交付模型:
    • 后端传统模型:Maven 构建 -> Jar包提取 -> SSH 传输 -> 重启进程。
    • 前端传统模型:Node 编译 -> 目录压缩 -> SSH 传输解压 -> 覆盖 Nginx 根目录。
  5. 容器化交付的终极形态:依托 Docker Pipeline 插件,实现了 构建镜像 -> 登录推库 -> 远程拉库重启 的现代云原生交付流程。

系列结语: 从手写 Shell 脚本到编写优雅的 Groovy 流水线,从繁琐的手工配置到全自动的容器化交付,Jenkins 依然以其无与伦比的灵活性统治着 CI/CD 领域。掌握了本系列这四大篇章,你不仅跨过了 DevOps 的门槛,更具备了在绝大多数中小型企业主导自动化工程的能力。

未来的路还很长,例如与 K8s (Kubernetes) 的动态 Agent 调度、集成 SonarQube 代码质量门禁、结合 Ansible 批量配置等。继续折腾,让自动化的齿轮为你打工吧!

Jenkins (4):企业实战篇 —— 版本控制+多环境部署+容器化交付
https://www.6ixblog.site/posts/jenkins-4/
作者
Licwic
发布于
2026-08-10
许可协议
CC BY-NC-SA 4.0