[笔记] 使用 Jenkins 实现 CI/CD :从 GitLab 拉取 Java 项目并部署至 Windows Server

随着软件开发节奏的加快,持续集成(CI)和持续部署(CD)已经成为确保软件质量和加速产品发布的不可或缺的部分。Jenkins作为一款广泛使用的开源自动化服务器,为开发者提供了一个强大的平台来实施这些实践。然而,在实际操作中,尤其是在需要跨越不同操作系统边界时——例如将基于Linux的构建服务器上的Java应用程序部署到Windows Server环境中——可能会遇到一系列挑战。本文聚焦于这一特定场景,详细介绍如何使用Jenkins来创建和管理Jobs,以便从GitLab仓库中拉取最新的Java项目源码,经过自动化的构建过程,最终将其部署到Windows Server上运行。

jenkins 部署 : [笔记] Jenkins 安装与配置全攻略:Ubuntu 从零开始搭建持续集成环境
前端项目部署 :[笔记] 使用 Jenkins 和 Nginx 实现前端项目的持续集成与部署 (CICD) : 从 GitLab 拉取 前端项目并部署至 Windows Server


一. 安装 jenkins 插件

1. GitLab 相关插件

用于与 GitLab 仓库集成,支持拉取代码、触发构建等。

  • GitLab
    提供 GitLab 与 Jenkins 的集成,支持 GitLab Webhook、MR 触发构建等功能。

  • Git Plugin
    用于从 Git 仓库(包括 GitLab)拉取代码。

  • GitLab API
    提供与 GitLab API 的交互支持(可选,根据需求安装)。

2. 构建工具插件

用于构建 Java 项目。

  • Maven Integration Plugin
    如果使用 Maven 构建 Java 项目,需要安装此插件。

  • Gradle Plugin
    如果使用 Gradle 构建 Java 项目,需要安装此插件。

3. SSH 相关插件

用于通过 SSH 连接到 Windows Server 2019 并部署应用。

  • SSH Build Agents Plugin
    允许 Jenkins 使用 SSH 密钥进行身份验证。

  • Publish Over SSH
    支持通过 SSH 将构建产物传输到远程服务器(Windows Server 2019)。

在这里插入图片描述


二. 全局工具配置

在这里插入图片描述

1. Maven 配置

在这里插入图片描述

2. Maven 安装

在这里插入图片描述


三. 配置代码仓库

我的代码仓库是使用的 极狐 gitlab

1. 获取 gitlab 的访问令牌(Access tokens)

在这里插入图片描述

期间 read_repository 必须勾选

  • 仅需拉取代码:
    如果 Jenkins 只需要从 GitLab 拉取代码(例如通过 Git-over-HTTP 或 Repository Files API),那么只需授予 read_repository 权限即可。
  • 需要与 GitLab API 交互:
    如果 Jenkins 需要调用 GitLab API 来进行其他操作(比如获取项目详细信息、触发构建、管理合并请求等),你将需要授予 read_api 权限。这包括对所有群组和项目的读访问权、容器镜像库和软件包库的访问权等。
  • 高级集成:
    在某些情况下,你可能还需要更多的权限,例如推送代码、创建标签或分支等。这些情况通常需要更高的权限级别,如 write_repository 或自定义权限设置。

在这里插入图片描述

2. 配置 jenkins 凭证

  • 进入凭证管理
    在这里插入图片描述
  • 配置全局凭证

在这里插入图片描述

  • 添加凭证
    在这里插入图片描述
  • 选择类型 Username with password
    在这里插入图片描述

三. (win服务器使用) Windows Server 2019 启动 OpenSSH Server

1. 安装 OpenSSH Server

# 以管理员身份运行 PowerShell# 安装 OpenSSH Server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0# 设置自动启动
Set-Service sshd -StartupType Automatic
Set-Service ssh-agent -StartupType Automatic# 启动 SSH 服务
Start-Service sshd
Start-Service ssh-agent# 确认服务状态
Get-Service sshd

2. 配置 SSH 服务

编辑 C:\ProgramData\ssh\sshd_config 文件,添加或修改以下内容:

# 编辑 C:\ProgramData\ssh\sshd_config 文件,添加或修改以下内容:
PasswordAuthentication yes
PermitRootLogin yes
Subsystem powershell c:/progra~1/powershell/7/pwsh.exe
KexAlgorithms diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,ecdh-sha2-nistp256
HostKeyAlgorithms ssh-rsa,rsa-sha2-512,rsa-sha2-256

3. 重启 SSH 服务

Restart-Service sshd

4. 配置防火墙

# 添加防火墙规则
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

四. 配置 SSH Servers

在这里插入图片描述

1. 使用账号密码

注意 : windows 服务器的配置 Remote Directory 只能使用基础目录 , 不可修改

在这里插入图片描述

2. 使用秘钥

a. 生成SSH密钥对

  • 打开终端或命令提示符。
  • 运行以下命令生成SSH密钥对:
# 生成 RSA 密钥对
ssh-keygen -t rsa -b 4096 -C "jenkins@example.com"# 密钥默认保存在:
# - 私钥:C:\Users\jenkins\.ssh\id_rsa
# - 公钥:C:\Users\jenkins\.ssh\id_rsa.pub
  • ssh-keygen : 用于生成、管理和转换认证密钥对的命令行工具,主要用于SSH协议。通常位于 /usr/bin/ssh-keygen/usr/local/bin/ssh-keygen
  • -t rsa-t 指定要生成的密钥类型。rsa 表示生成RSA类型的密钥。RSA是一种非对称加密算法,广泛用于SSH连接。其他常见的密钥类型包括 dsa(较少使用)、ecdsaed25519
  • -b 4096-b 指定密钥的位数。4096 表示生成的RSA密钥长度为4096位。默认情况下,ssh-keygen 生成的RSA密钥长度为2048位。增加密钥长度可以提高安全性,但也会稍微增加计算开销。4096位是一个常用的、安全的选择。
  • -C "your_email@example.com" : -C 添加一个注释(comment)到生成的公钥中。"your_email@example.com" 是你提供的注释内容,通常是你的电子邮件地址。
  • 按照提示操作,可以接受默认路径和文件名(通常是 ~/.ssh/id_rsa~/.ssh/id_rsa.pub)。
    在这里插入图片描述

  • Enter passphrase (empty for no passphrase):系统会提示你输入一个密码短语(passphrase)。如果你设置了密码短语,每次使用私钥时都需要输入它。这增加了安全性,但也增加了使用的复杂性。(如果你不希望设置密码短语,直接按回车键即可。)
    在这里插入图片描述
    在这里插入图片描述

b. 将公钥复制到 Windows Server

  • 将生成的公钥文件(通常是 ~/.ssh/id_rsa.pub)的内容复制到剪贴板。
  • 将公钥内容添加到 authorized_keys 文件
# 创建 authorized_keys 文件并添加公钥内容
# 将 Jenkins 服务器上 id_rsa.pub 的内容复制到这个文件
Add-Content -Path C:\Users\Administrator\.ssh\authorized_keys -Value "ssh-rsa AAAA..."

-Value 是你的 ~/.ssh/id_rsa.pub 的内容

在这里插入图片描述

c. 编辑 C:\ProgramData\ssh\sshd_config

# 启用公钥认证
PubkeyAuthentication yes# 指定授权密钥文件位置
AuthorizedKeysFile .ssh/authorized_keys# 可选:禁用密码认证(更安全)
PasswordAuthentication no

在这里插入图片描述

d. 设置文件权限

# 设置 .ssh 目录的权限
icacls "C:\Users\Administrator\.ssh" /inheritance:r
icacls "C:\Users\Administrator\.ssh" /grant "SYSTEM:(F)"
icacls "C:\Users\Administrator\.ssh" /grant "ADMINISTRATORS:(F)"
icacls "C:\Users\Administrator\.ssh" /grant "Administrator:(F)"# 设置 authorized_keys 文件的权限
icacls "C:\Users\Administrator\.ssh\authorized_keys" /inheritance:r
icacls "C:\Users\Administrator\.ssh\authorized_keys" /grant "SYSTEM:(F)"
icacls "C:\Users\Administrator\.ssh\authorized_keys" /grant "ADMINISTRATORS:(F)"
icacls "C:\Users\Administrator\.ssh\authorized_keys" /grant "Administrator:(F)"

e. 重启 SSH 服务

# 重启 SSH 服务
Restart-Service sshd

f. 在 Jenkins 中配置 SSH Publisher:

path to key 与 key 只需要配置一个就可以

在这里插入图片描述

3. 测试连接

在这里插入图片描述


四. 编写 jobs

在这里插入图片描述
在这里插入图片描述

1. 配置源码管理

在这里插入图片描述

2. 配置 构建完成后 上传产物与运行脚本

注意:

  1. 可以选择 构建环境中的 Send files or execute commands over SSH after the build runs 也可以选择 构建后操作中的Send build artifacts over SSH
  2. Remote directory : 我使用的是环境参数,在 Jenkins 中使用环境参数使用 必须是 ${FOLDER_NAME} 的格式。
  3. windows 服务器 运行脚本的话,只能运行服务器上的脚本。
> Exec command : 
> ${DEPLOY_BAT_PATH} "${FOLDER_NAME}" "${DEPLOY_LOG_PATH}" "${BASE_SOURCE_PATH}" "${BASE_TARGET_PATH}" "${JAR_NAME}"

在这里插入图片描述

3. 配置环境变量

在 Jenkins 中使用环境参数使用 必须是 ${FOLDER_NAME} 的格式。

parameters {// 1. 部署文件夹名称string(name: 'FOLDER_NAME',defaultValue: 'sc-wms',description: '部署文件夹名称')// 2. 日志文件路径string(name: 'DEPLOY_LOG_PATH',defaultValue: 'D:\CICD\deploy\backend\deploy.log',description: '日志文件路径')// 3. 源代码基础路径string(name: 'BASE_SOURCE_PATH',defaultValue: 'C:\Users\Administrator',description: '源代码基础路径')// 4. 目标基础路径string(name: 'BASE_TARGET_PATH',defaultValue: 'D:\CICD\project\backend',description: '目标基础路径')// 5. JAR文件名称string(name: 'JAR_NAME',defaultValue: 'mada-admin.jar',description: 'JAR文件名称')// 6. 部署脚本路径string(name: 'DEPLOY_BAT_PATH',defaultValue: 'D:\CICD\deploy\backend\deploy.bat',description: '部署脚本路径')}

在这里插入图片描述

4. 服务器项目目录结构

D:\CICD\                            # Windows 服务器上的自动化部署目录
├── deploy/                         # 部署相关
│    ├── web/                       # 前端部署相关内容
│    │    ├── deploy.bat            # 前端部署脚本
│    │    └── nginx.conf.template   # 前端项目 Nginx 配置模板
│    └── backend/                   # 后端部署相关内容
│         └── deploy.bat            # 后端部署脚本
├── nginx/                          # nginx 安装目录
│    ├── conf/                      # nginx 配置目录
│    │    ├── mime.types            # MIME 类型配置
│    │    ├── nginx.conf            # nginx 主配置
│    │    └── project_conf/         # 项目配置目录
│    ├── contrib/                   # 第三方贡献
│    ├── docs/                      # 文档
│    ├── html/                      # 网站文件目录
│    │    └── sc-wms/               # sc-wms 前端文件
│    ├── logs/                      # 日志目录
│    │    ├── access.log            # 访问日志
│    │    └── error.log             # 错误日志
│    ├── temp/                      # 临时文件目录
│    │    ├── client_body_temp/     # 客户端请求体临时文件
│    │    ├── proxy_temp/           # 代理临时文件
│    │    ├── fastcgi_temp/         # FastCGI 临时文件
│    │    ├── uwsgi_temp/           # uWSGI 临时文件
│    │    └── scgi_temp/            # SCGI 临时文件
│    └── nginx.exe                  # nginx 可执行文件
└── project/                        # 项目相关├── web/                       # 前端项目目录│    ├── sc-wms/               # sc-wms 前端项目│    │    └── dist/            # 前端构建文件│    ├── other-project/        # 其他前端项目│    └── ...                   # 更多前端项目└── backend/                   # 后端项目目录├── sc-wms/               # sc-wms 后端项目│    ├── sc-wms.jar       # 后端 jar 包│    └── start.bat        # 启动脚本├── other-project/        # 后端其他项目└── ...                   # 更多后端项目

5. 编写脚本

部分内容声明 :

# 因为一些要求 , 要生成启动的脚本 , java -jar 换成 javaw -jar 也是一样的
echo Creating start script... >> %DEPLOY_LOG%
(echo @echo offecho cd /d "%TARGET_PATH%"echo java -jar "%JAR_NAME%" ^> "%TARGET_PATH%\app.log" 2^>^&1
) > "%TARGET_PATH%\start.bat"# 这里因为...用的盗版系统,环境变量被魔改过,start不会起作用.所以用 call 了,如果可以用start用start,call会等待。导致Jenkins超时
if exist "%TARGET_PATH%\%JAR_NAME%" (:: 启动应用cd /d "%TARGET_PATH%"call start.batecho Application started successfully >> %DEPLOY_LOG%
) else (echo WARNING: JAR file not found after deployment >> %DEPLOY_LOG%
)

完整脚本:

@echo off
setlocal EnableDelayedExpansion:: 检查参数
if "%~1"=="" (echo Error: folder_name parameter is missinggoto :usage
)
if "%~2"=="" (echo Error: deploy_log_path parameter is missinggoto :usage
)
if "%~3"=="" (echo Error: base_source_path parameter is missinggoto :usage
)
if "%~4"=="" (echo Error: base_target_path parameter is missinggoto :usage
)
if "%~5"=="" (echo Error: jar_name parameter is missinggoto :usage
):: 检查并创建日志文件目录
for %%I in ("%~2") do set "LOG_DIR=%%~dpI"
if not exist "!LOG_DIR!" (echo Creating log directory: !LOG_DIR!md "!LOG_DIR!" 2>nulif errorlevel 1 (echo Error: Failed to create log directorygoto :usage)
):: 设置日志文件和基础变量
set "FOLDER_NAME=%~1"
set "DEPLOY_LOG=%~2"
set "SOURCE_PATH=%~3\%FOLDER_NAME%"
set "TARGET_PATH=%~4\%FOLDER_NAME%"
set "JAR_NAME=%~5":: 记录部署开始
echo %date% %time% - Starting Jenkins deployment > %DEPLOY_LOG%
echo Configuration: >> %DEPLOY_LOG%
echo SOURCE_PATH=%SOURCE_PATH% >> %DEPLOY_LOG%
echo TARGET_PATH=%TARGET_PATH% >> %DEPLOY_LOG%
echo JAR_NAME=%JAR_NAME% >> %DEPLOY_LOG%:: 停止现有进程
echo %date% %time% - Attempting to stop existing process... >> %DEPLOY_LOG%
taskkill /F /IM java.exe /T >> %DEPLOY_LOG% 2>&1 || echo No Java processes found >> %DEPLOY_LOG%
echo %date% %time% - Process stop attempt completed >> %DEPLOY_LOG%:: 等待进程完全停止
echo %date% %time% - Waiting for processes to stop... >> %DEPLOY_LOG%
ping -n 11 127.0.0.1 > nul
echo %date% %time% - Wait completed >> %DEPLOY_LOG%:: 清理目标目录 - 即使失败也继续
echo Cleaning target directory... >> %DEPLOY_LOG%
if exist "%TARGET_PATH%" (rd /s /q "%TARGET_PATH%" >> %DEPLOY_LOG% 2>&1
):: 创建必要目录
md "%~4" 2>nul
md "%TARGET_PATH%" 2>nul:: 复制文件
echo Moving files... >> %DEPLOY_LOG%
robocopy "%SOURCE_PATH%" "%TARGET_PATH%" /E /MOVE /R:1 /W:1 >> %DEPLOY_LOG% 2>&1:: 创建启动脚本
echo Creating start script... >> %DEPLOY_LOG%
(echo @echo offecho cd /d "%TARGET_PATH%"echo java -jar "%JAR_NAME%" ^> "%TARGET_PATH%\app.log" 2^>^&1
) > "%TARGET_PATH%\start.bat":: 验证部署
if exist "%TARGET_PATH%\%JAR_NAME%" (:: 启动应用cd /d "%TARGET_PATH%"call start.batecho Application started successfully >> %DEPLOY_LOG%
) else (echo WARNING: JAR file not found after deployment >> %DEPLOY_LOG%
)echo Deployment completed at %date% %time% >> %DEPLOY_LOG%endlocal
exit /b 0:usage
echo Usage: deploy.bat [folder_name] [deploy_log_path] [base_source_path] [base_target_path] [jar_name]
echo Example: %%FOLDER_NAME%% %%DEPLOY_LOG_PATH%% %%BASE_SOURCE_PATH%% %%BASE_TARGET_PATH%% %%JAR_NAME%%
exit /b 1

五. 运行 jobs

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68061.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt QPainter setViewport setWindow viewport window

使用qt版本5.15.2 引入viewport和window目的是用于实现QPainter画出来的内容随着窗体伸缩与不伸缩两种情况,以及让QPainter在widget上指定的区域(viewport)进行绘制/渲染(分别对应下方demo1,demo2,demo3)。 setViewpo…

likeshop同城跑腿系统likeshop回收租赁系统likeshop多商户商城安装及小程序对接方法

前言:首先likeshop是一个开发平台,是一个独创的平台就像TP内核平台一样,你可以在这个平台上开发和衍生出很多伟大的产品,以likeshop为例,他们开发出商城系统,团购系统,外卖点餐系统,…

继续以“实用”指导Pythonic编码(re通配表达式)(2024年终总结②)

弃现成工具手剥任务🧐,我哈哈滴就像笨笨的傻大个儿😋。 (笔记模板由python脚本于2025年01月12日 23:29:33创建,本篇笔记适合熟悉正则表达式的coder翻阅) 【学习的细节是欢悦的历程】 Python官网:https://www.python.or…

相机和激光雷达的外参标定 - 无标定板版本

1. 实现的效果 通过本软件实现求解相机和LiDAR的外参,即2个传感器之间的三维平移[x, y, z]和三维旋转[roll, pitch, yaw]。完成标定后,可将点云投影到图像,效果图如下: 本软件的优势:(1)无需特…

WPF系列九:图形控件EllipseGeometry

简介 EllipseGeometry用于绘制一个椭圆的形状。它通常与其他图形元素结合使用,比如 Path 或者作为剪切区域来定义其他元素的外形。 定义椭圆:EllipseGeometry 用来定义一个椭圆或者圆的几何形状。参与绘制:可以被用作 Path 元素的数据&…

qt设置qwidget背景色无效

最近在做一个界面,有三个子窗体,于是就把各个子窗体分别做成了三个UI,再将3个UI,放到1个UI,再将那一个UI在其他窗体上进行提升。 最后就发现怎么设置qwidget的背景都没有效果。 在Qt中,如果是给Qwidget的…

【Rust学习笔记】Rust 的所有权介绍

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 博客内容主要围绕: 5G/6G协议讲解 高级C语言讲解 Rust语言讲解 文章目录 Rust中的所有权介绍1.1 一个简单的例子1.2 一个稍微复杂的例…

CentOS7下Hadoop集群分布式安装详细图文教程

1、集群规划 主机 角色 DSS20 NameNode DataNode ResourceManager NodeManager DSS21 SecondaryNameNode NameNode NodeManager DSS22 DataNode NodeManager 1.1、环境准备 1.1.1 关闭防火墙 #查看防火墙状态 firewall-cmd --state #停止…

在 Vue 项目中使用地区级联选

在 Vue 项目中使用地区级联选择的完整流程: 1.安装依赖包,这个包提供了中国省市区的完整数据。 npm install element-china-area-data --save 2.导入数据 import { regionData } from element-china-area-data 这个包提供了几种不同的数据格式&#…

基于改进粒子群优化的无人机最优能耗路径规划

目录 1. Introduction2. Preliminaries2.1. Particle Swarm Optimization Algorithm2.2. Deep Deterministic Policy Gradient2.3. Calculation of the Total Output Power of the Quadcopter Battery 3.OptimalEnergyConsumptionPathPlanningBasedonPSO-DDPG3.1.ProblemModell…

Redis为 List/Set/Hash 的元素设置单独的过期时间

一.业务简介 我们知道,Redis 里面暂时没有接口给 List、Set 或者 Hash 的 field 单独设置过期时间,只能给整个列表、集合或者 Hash 设置过期时间。 这样,当 List/Set/Hash 过期时,里面的所有 field 元素就全部过期了。但这样并不…

【51单片机】03 蜂鸣器-播放音乐

蜂鸣器-播放音乐 一、原理介绍1.硬件电路 二、练习1.让蜂鸣器发声2.尝试演奏小星星 一、原理介绍 蜂鸣器分为有源蜂鸣器、无源蜂鸣器两种。 有源蜂鸣器:施加合适的电压之后就会发出特定频率的声音 无源蜂鸣器:需要提供特定频率的声音信号,才能…

30_Redis哨兵模式

在Redis主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性…

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图)

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图) 前面的两篇博文简述了AutoSAR CP分层架构的概念,下面我们来具体到每一层的具体内容进行讲解,每一层的每一个功能块力求用一个总览图,外加一个例子的图给大家进…

51单片机——定时器中断(重点)

STC89C5X含有3个定时器:定时器0、定时器1、定时器2 注意:51系列单片机一定有基本的2个定时器(定时器0和定时器1),但不全有3个中断,需要查看芯片手册,通常我们使用的是基本的2个定时器&#xff…

LeetCode热题100-合并两个有序链表【JavaScript讲解】

题目: 题解: 我们目前已经知道两条链表都是有序链表,我们就可以通过迭代的方法实现上述问题。当list1和list2都不是空链表时,判断list1和list2哪个头节点的值更小,将较小的值添加到结果里,被添加到结果里的…

Artec Leo 3D扫描仪与Ray助力野生水生动物法医鉴定【沪敖3D】

挑战:捕获大型水生哺乳动物(如鲸鱼)的数据,搭建全彩3D模型,用于水生野生动物的法医鉴定、研究和保护工作。 解决方案:Artec Eva、Artec Space Spider、Artec Leo、Artec Ray、Artec Studio、CT scans 效果&…

HBuilderX打包ios保姆式教程

1、登录苹果开发者后台并登录已认证开发者账号ID Sign In - Apple 2、创建标识符(App ID)、证书,描述文件 3、首先创建标识符,用于新建App应用 3-1、App的话直接选择第一个App IDs,点击右上角继续 3-2、选择App&#x…

Android DataBinding 结合 ViewModel的使用

Android DataBinding 结合 ViewModel的使用 一、build.gradle引入对应的依赖 在build.gradle(app模块)里引入依赖,然后Sync Now一下: android {​viewBinding {enabled true}dataBinding {enabled true}} 完整的build.gradle代…

动植物基因表达调控

1, on and off状态 以及表达的量 2, 基因调控的生物学影响? 超过400多种细胞类型,数目上37万亿 不是所有的基因都表达 为什么多核真核细胞需要基因调控? 单个细胞往多个细胞逐渐进化的过程,形成复杂的…