Jenkins自动化部署

一、介绍

Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,广泛用于项目开发,具有自动化构建、测试和部署等功能。Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。

因为开发部门同时维护多个版本,多个版本的发布,测试需要大量人力,所以要有一个专业的持续集成工具来管理持续重复的工作。

个人理解,说白了就是把代码测试、打包、发布等工作交给一些工具来自动完成。这样可以提高效率,减少失误,开发人员只需要关心开发和提交代码到Git就可以了。

二、安装前资源准备(jenkins.war包、配套jdk、maven、离线插件、启动脚本等)

下载地址:https://download.csdn.net/download/weixin_39393393/93166322

资源详情:

三、安装部署

1、安装JDK

将JDK上传到指定目录并安装:

bash 复制代码
rpm -ivh jdk-17.0.2_linux-x64_bin.rpm

查看安装位置(Oracle JDK rpm 默认安装rpm安装位置:/usr/java/jdk-17.0.2)

配置环境变量

bash 复制代码
vim /etc/profile

最后追加:

bash 复制代码
export JAVA_HOME=/usr/java/jdk-17.0.2
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib

让配置生效并验证:

bash 复制代码
source /etc/profile

2、安装maven

将Maven压缩包上传到指定目录并解压:

配置maven找到配置文件修改内容如下:

bash 复制代码
vim apache-maven-3.6.3/conf/settings.xml 

修改仓库地址,指定自己的仓库目录:

bash 复制代码
<localRepository>/services/maven/repository</localRepository>
bash 复制代码
<mirror>
	<id>alimaven</id>
	<name>aliyun maven</name>
	<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
	<mirrorOf>central</mirrorOf>
 </mirror>

配置环境变量并检查

bash 复制代码
export MAVEN_HOME=/services/maven/apache-maven-3.6.3
export PATH=$MAVEN_HOME/bin:$PATH

3、安装Jenkins并启动服务

将资源包中的 jenkins.war 包和启动脚本上传到指定目录:

修改启动脚本中的文件目录:

bash 复制代码
#!/bin/bash

# 设置 JDK 路
export JAVA_HOME=/usr/java/jdk-17.0.2
export PATH=$JAVA_HOME/bin:$PATH

# 设置 Jenkins 数据目录(任务、插件、配置等都会保存在这里)
export JENKINS_HOME=/services/jenkins/data

# 启动 Jenkins,后台运行
# -Djenkins.install.runSetupWizard=false  跳过安装向导
# -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true   禁用 Jenkins 的 CSRF(Crumb)安全校验
# -Dhudson.model.UpdateCenter.updateCenterUrl=file:///dev/null \    禁止 Jenkins 检查插件和版本更新
# -Dhudson.model.UpdateCenter.updateCenterUrl=https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/  将 Jenkins 更新源修改为国内镜像(如清华镜像)
nohup $JAVA_HOME/bin/java \
  -Djenkins.install.runSetupWizard=false \
  -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true \
  -jar /services/jenkins/jenkins.war \
  --prefix=/jenkins \
  --httpPort=8777 \
  --httpListenAddress=0.0.0.0 \
  > /services/jenkins/jenkins.log 2>&1 &

创建data目录并赋予权限,对jenkins-start.sh文件赋予执行权限

执行启动脚本,通过浏览器访问jenkins(端口号必须为8777)

bash 复制代码
http://你的IP地址:8777/jenkins

四、配置Jenkins

1、Jenkins中的插件(不在线下载可以使用上述的离线插件包)

将资源包中的plugins 覆盖 /services/jenkins/data/plugins 文件夹,并重启服务

可以看到中文插件已生效:

禁用插件升级:

2、Jenkins中全局工具配置,配置JDK、maven、git等

如果让Jenkins发布前端的话,需要配置nodejs:

3、Jenkins中全局安全配置

五、构建maven项目

1、新建任务并规划视图分组

任务视图分组:

将任务划分为该视图分组

2、任务配置

任务源码管理配置

添加全局凭证

添加完成后再 系统管理>凭据管理里可以看到

在前置步骤中使用maven命令构建程序包

bash 复制代码
clean package -DskipTests

前置步骤执行成功后可以在Jenkins 数据目录看到构建的项目工程target。

/services/jenkins/data/workspace 固定目录

services/jenkins/data/workspace/data-gateway 固定目录 + Jenkins任务名称

/services/jenkins/data/workspace/data-gateway/data-gateway 固定目录 + Jenkins任务名称 + 模块项目工程目录

在后置步骤中编写shell脚本让其执行:

2.1 、Jenkins发布脚本

下面附上脚本代码(根据个人使用情况修改关键参数即可)

由于jenkins构建消耗内存极大,一般jenkins是一台单独的工具机器,Java项目一般在其他的机器上,这里Jenkins服务部署在192.168.15.57虚拟服务器上,下面应用服务器192.168.15.58是java项目部署的虚拟服务器。

应用部署目录:指的是java项目应用程序部署的服务器jar包所在目录(包括启动脚本start和停止服务脚本stop都在该目录下)

应用服务器目录结构如下:

bash 复制代码
#!/bin/bash

###############################################
# Jenkins发布脚本
#
# 功能:
# 1. 找到当前构建jar
# 2. 上传应用服务器
# 3. 备份旧jar
# 4. 调用远程stop/start
###############################################

# 应用服务器
SERVER_IP="192.168.15.58"

# SSH用户
REMOTE_USER="root"

# 应用部署目录
APP_HOME="/services/app"

# jar工程目录
APP_NAME="data-gateway"
# jar名称配置
APP_JAR_NAME="data-gateway.jar"
echo "JenkinsJob名称:"
echo ${JOB_NAME}
echo "jar工程目录:"
echo ${APP_NAME}
echo "jar名称:"
echo ${APP_JAR_NAME}

#==========================
# 查找jar ${WORKSPACE}包含${JOB_NAME}例如:/services/jenkins/data/workspace/${JOB_NAME}
# ==========================
JAR_FILE=$(find ${WORKSPACE}/${APP_NAME}/target \
-name "*.jar" \
-not -path "*original*" \
| head -1)

if [ ! -f "${JAR_FILE}" ];then
 echo "没有找到jar"
 exit 1
fi

echo "找到jar:"
echo ${JAR_FILE}

#==========================
# 上传
#==========================
echo "开始发布 ${APP_NAME}"

ssh \
-o StrictHostKeyChecking=no \
${REMOTE_USER}@${SERVER_IP} <<EOF

mkdir -p ${APP_HOME}/${APP_NAME}/backup
mkdir -p ${APP_HOME}/${APP_NAME}/logs

EOF

#停止服务
ssh \
-o StrictHostKeyChecking=no \
${REMOTE_USER}@${SERVER_IP} \
"${APP_HOME}/${APP_NAME}/stop.sh"

#==========================
# 备份旧jar
# <<EOF ... EOF 多行输入命令
#==========================
ssh \
-o StrictHostKeyChecking=no \
${REMOTE_USER}@${SERVER_IP} <<EOF

if [ -f ${APP_HOME}/${APP_NAME}/${APP_JAR_NAME} ]
then
mv ${APP_HOME}/${APP_NAME}/${APP_JAR_NAME} \
${APP_HOME}/${APP_NAME}/backup/${APP_JAR_NAME}-$(date +%Y%m%d_%H%M%S)
fi

EOF

#==========================
# 上传新jar
#==========================
scp \
-o StrictHostKeyChecking=no \
${JAR_FILE} \
${REMOTE_USER}@${SERVER_IP}:${APP_HOME}/${APP_NAME}/${APP_JAR_NAME}

#==========================
# 启动
#==========================
ssh \
-o StrictHostKeyChecking=no \
${REMOTE_USER}@${SERVER_IP} \
"${APP_HOME}/${APP_NAME}/start.sh"

echo "================================"
echo "${APP_NAME} 发布完成"
echo "================================"

Jenkins发布脚本,是在192.168.15.57虚拟服务器上因为涉及到上传应用服务到java项目部署的虚拟服务器192.168.15.58上、还有备份、远程执行启停脚本等操作。所以这里先需要配置两台服务器的SSH免密登录

3、开启SSH免密登录

在192.168.15.57机器上使用root用户生成秘钥注意此处是root用户

bash 复制代码
$ ssh-keygen -t rsa
# 3次回车

运行后会在当前用户的根目录生成一个.ssh文件夹

.ssh文件夹中的文件描述(.ssh目录的权限必须是700)

  • id_rsa : 生成的私钥文件
  • id_rsa.pub : 生成的公钥文件

接下来需要将公钥导入到认证文件中

bash 复制代码
# .ssh/authorized_keys文件权限必须是600
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

给对应文件授权

bash 复制代码
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys

接下来将authorized_keys文件拷贝到另一台应用服务器的root用户.ssh目录下即可

bash 复制代码
scp -p ~/.ssh/id_rsa.pub root@192.168.15.58:/root/.ssh/authorized_keys

最后在jenkins192.168.15.57服务器上进行免密连接测试

bash 复制代码
ssh root@192.168.15.58
3.1 、应用服务器上的start.sh启动脚本

start.sh 脚本内容如下:

bash 复制代码
#!/bin/bash

############################################
# Java服务启动脚本
############################################

JAVA_HOME=/www/server/java/jdk-17.0.8

JAVA_BIN=${JAVA_HOME}/bin/java

# 当前应用目录
APP_HOME=$(cd $(dirname $0); pwd)

# 日志文件(带启动时间)
LOG_FILE=${APP_HOME}/logs/app-$(date "+%Y%m%d_%H%M%S").log

# 判断jar数量是否为1
JAR_COUNT=$(find ${APP_HOME} -maxdepth 1 -name "*.jar" -type f | wc -l)
if [ ${JAR_COUNT} -ne 1 ];then
    echo "错误: 当前目录jar数量异常:${JAR_COUNT}"
    exit 1
fi

# 自动获取jar包全路径(只查当前目录下的jar包文件,只取第一个)
JAR_FILE=$(find ${APP_HOME} \
-maxdepth 1 \
-name "*.jar" \
-type f \
| head -1)

# 日志目录
LOG_DIR="${APP_HOME}/logs"
mkdir -p ${LOG_DIR}

# JVM参数
JAVA_OPTS="
-Xms512m
-Xmx1024m
"

echo "================================"
echo "启动服务"
echo "目录:${APP_HOME}"
echo "Jar路径:${JAR_FILE}"
echo "日志:${LOG_DIR}"
echo "================================"

# 判断jar是否存在
if [ ! -f "${JAR_FILE}" ];then
echo "错误: jar不存在"
echo "${JAR_FILE}"
exit 1
fi

# 启动 --spring.profiles.active=dev \  --config.nacos.server-addr=localhost:8848 \ --server.port=40009 \
echo "启动命令:"
echo "nohup ${JAVA_BIN} ${JAVA_OPTS} -jar ${JAR_FILE} > ${LOG_FILE} 2>&1 &"
nohup ${JAVA_BIN} ${JAVA_OPTS} \
-jar ${JAR_FILE} \
> ${LOG_FILE} 2>&1 &
PID=$!
echo "启动PID=${PID}"

sleep 20

# 检查进程
if ps -p ${PID} >/dev/null
then
 echo "Java进程存在"
else
 echo "启动失败"
 exit 1
fi
3.2 、应用服务器上的stop.sh停止脚本

stop.sh 脚本内容如下:

bash 复制代码
############################################
# Java服务停止脚本
# 功能:
# 1. 根据jar名称查找Java进程
# 2. 发送SIGTERM优雅停止
# 3. 等待应用释放资源
# 4. 超时后强制kill
############################################

# 当前应用目录
APP_HOME=$(cd $(dirname $0); pwd)

# 判断jar数量是否为1
JAR_COUNT=$(find ${APP_HOME} -maxdepth 1 -name "*.jar" -type f | wc -l)
if [ ${JAR_COUNT} -ne 1 ];then
    echo "错误: 当前目录jar数量异常:${JAR_COUNT}"
    exit 1
fi

# 自动获取jar包全路径(只查当前目录下的jar包文件,只取第一个)
JAR_FILE=$(find ${APP_HOME} \
-maxdepth 1 \
-name "*.jar" \
-type f \
| head -1)

# 获取jar名称
JAR_NAME=$(basename ${JAR_FILE})

echo "================================"
echo "准备停止Java服务"
echo "应用目录:${APP_HOME}"
echo "Jar路径:${JAR_FILE}"
echo "Jar名称:${JAR_NAME}"
echo "================================"

# 根据jar名称查询PID
PID=$(ps -ef \
| grep "${JAR_NAME}" \
| grep -v grep \
| awk '{print $2}')

# 没有运行中的服务
if [ -z "${PID}" ];then
    echo "当前没有运行中的服务"
    exit 0
fi

echo "发现运行PID:${PID}"
echo "发送停止信号..."

# 发送SIGTERM信号
kill -15 ${PID}

# 等待服务停止 最大等待30秒
for i in {1..30}
do

sleep 1

PID_CHECK=$(ps -ef \
| grep "${JAR_NAME}" \
| grep -v grep \
| awk '{print $2}')

# 没有运行中的服务
if [ -z "${PID_CHECK}" ];then
    echo "================================"
    echo "服务停止成功"
    echo "================================"
    exit 0
fi
echo "等待服务关闭 ${i}s"

done

#===========================================
# 超时强制关闭
#===========================================

echo "执行强制kill"
kill -9 ${PID}
echo "服务已强制停止"

4、一键构建发版

可以在控制台输出看到上述的脚本执行详细过程,如下图:

相关推荐
snow@li1 小时前
Kibana:功能全景梳理/Elastic Stack可视化管理平台
运维
AC赳赳老秦1 小时前
官方技术文档聚合实践:用 OpenClaw 批量抓取开源项目文档,构建离线可检索技术知识库
java·运维·服务器·python·信息可视化·deepseek·openclaw
fengkai45451 小时前
Linux服务--5.Nginx 服务
linux·运维·服务器
牛肉胡辣汤1 小时前
开源模型落地实战|开发、运维、安全各岗位 AI 应用经验分享
运维·安全·开源
布局呆星10 小时前
云服务器上部署单项目/多项目
运维·服务器
盐焗鹌鹑蛋10 小时前
【Linux】缓冲区
linux·运维·服务器
祈禾10 小时前
Redis三大缓存问题与分布式锁
运维·数据库·redis·笔记·分布式·缓存
ltl12 小时前
可观测性存储与成本:采样、下采样、冷热分层
运维
学代码的CJY13 小时前
Linux 库制作与原理:静态库、动态库、ELF 与动态链接完全指南
linux·运维·服务器