Jenkins入门(二):流水线方式部署多模块Springboot项目

目录

一、环境准备

1. 搭建配置Jenkins  (在上一篇基础上进行)

2. 安装mysql

3. 安装redis

4. 配置docker-componse

 5. 启动docker-componse

二、脚本准备

1. Jenkinsfile

2. deploy.sh

3. Dockerfile

三、Jenkins流水线配置

新增版本号参数

流水线选择代码里面的Jenkinsfile相对路径

选择需要的分支构建任务

四、问题 

1. 多模块打包失败,不会自动打包依赖的其他模块

2. 华为云公网IP访问不通

参考:


一、环境准备

1. 搭建配置Jenkins  (在上一篇基础上进行)

Jenkins入门:从搭建到部署第一个Springboot项目(踩坑记录)-CSDN博客

2. 安装mysql

docker pull mysql:5.7

3. 安装redis

docker pull redis:5.0.14

4. 配置docker-componse

version: "3.8"
services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    restart: always
    privileged: true
    user: root
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/jenkins_home:/var/jenkins_home
      - /root/soft:/root/soft
      - /usr/bin/docker:/usr/bin/docker
      - /etc/docker/daemon.json:/etc/docker/daemon.json
    ports:
      - "8080:8080"
      - "50000:50000"
    environment:
      TZ: Asia/Shanghai
  mysql: # 服务名称
    image: mysql:5.7 # 或其它mysql版本
    container_name: mysql5.7 # 容器名称
    environment:
      - MYSQL_ROOT_PASSWORD=123456 # root用户密码
#      - TZ=Asia/Shanghai # 设置容器时区 我这里通过下面挂载方式同步的宿主机时区和时间了,这里忽略
    volumes:
      - /var/mysql5.7/log:/var/log/mysql # 映射日志目录,宿主机:容器
      - /var/mysql5.7/data:/var/lib/mysql # 映射数据目录,宿主机:容器
      - /var/mysql5.7/conf:/etc/mysql/conf.d # 映射配置目录,宿主机:容器
      - /etc/localtime:/etc/localtime:ro # 让容器的时钟与宿主机时钟同步,避免时间的问题,ro是read only的意思,就是只读。    ports:
      - 3306:3306 # 指定宿主机端口与容器端口映射关系,宿主机:容器
    restart: always # 容器随docker启动自启
  redis: # 服务名称
    image: redis:5.0.14 # redis镜像版本
    container_name: redis5 # 容器名称
    ports:
      - 6379:6379 # 指定宿主机端口与容器端口映射关系,宿主机:容器
    volumes:
      - /var/redis5/conf/redis.conf:/etc/redis/redis.conf # 映射配置文件目录,宿主机:容器
      - /var/redis5/data:/data # 映射数据目录,宿主机:容器
    restart: always # 容器开机自启
    privileged: true # 获取宿主机root权限
    command: ["redis-server","/etc/redis/redis.conf"] # 指定配置文件启动redis-server进程

 5. 启动docker-componse

docker-compose up -d

二、脚本准备

参考项目目录:

1. Jenkinsfile

#!groovy
pipeline {

	agent any

	environment {
		// 应用名称
		APP_NAME = 'xxx-server'
		// 应用部署路径(注意些自己的jenkins挂载目录)
		APP_DEPLOY_BASE_DIR = '/var/jenkins_home/workspace/'
		MODULE_NAME = "$project_name";
	}


	stages {
		stage('打印信息') {      //打印信息
		steps {
			echo '变量打印信息'
			echo "Project_Pipeline_name: $JOB_NAME"
			echo "workspace: $WORKSPACE"
			echo "branch: $branch_name"           //gitlab分支名
			echo "build_id: $BUILD_ID"
		}
	}
	stage('检出') {
		steps {
			git credentialsId: '0d104c96-f1bf-4992-97b2-6b70d6c938e4', url: 'https://gitee.com/xxx/xxx-framework.git',
			branch: "$branch_name"
		}
	}

	stage('构建') {
		steps {
			sh 'mvn clean package -Dmaven.test.skip=true'
		}
	}

	stage('部署') {
		steps {
			sh 'cp -f ' + ' script/shell/deploy.sh ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}"+'/'
			sh 'cp -f ' + "${env.APP_NAME}" + '/target/*.jar ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" +'/build/'
			archiveArtifacts "${env.APP_NAME}" + '/target/*.jar'
			sh 'chmod +x ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + '/deploy.sh'
			sh 'bash ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + '/deploy.sh'
		}
	}
}
}

2. deploy.sh

注意:docker run -d -p 48080:48080 -v /root/soft/logs:/user/logs $SERVER_NAME,log目录挂载,否则日志无法保存到宿主机

#!/bin/bash
set -e

DATE=$(date +%Y%m%d%H%M)
# 基础路径
BASE_PATH=/var/jenkins_home/workspace/hbintrade-server
# 编译后 jar 的地址。部署时,Jenkins 会上传 jar 包到该目录下
SOURCE_PATH=$BASE_PATH/build
# 服务名称。同时约定部署服务的 jar 包名字也为它。
SERVER_NAME=hbintrade-server
# 环境
PROFILES_ACTIVE=dev
# 健康检查 URL
HEALTH_CHECK_URL=http://xxxx:48080/actuator/health/

# heapError 存放路径
HEAP_ERROR_PATH=$BASE_PATH/heapError
# JVM 参数
JAVA_OPS="-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HEAP_ERROR_PATH"

# SkyWalking Agent 配置
#export SW_AGENT_NAME=$SERVER_NAME
#export SW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.84:11800
#export SW_GRPC_LOG_SERVER_HOST=192.168.0.84
#export SW_AGENT_TRACE_IGNORE_PATH="Redisson/PING,/actuator/**,/admin/**"
#export JAVA_AGENT=-javaagent:/work/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar

# 备份
function backup() {
    # 如果不存在,则无需备份
    if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
        echo "[backup] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过备份"
    # 如果存在,则备份到 backup 目录下,使用时间作为后缀
    else
        echo "[backup] 开始备份 $SERVER_NAME ..."
        cp $BASE_PATH/$SERVER_NAME.jar $BASE_PATH/backup/$SERVER_NAME-$DATE.jar
        echo "[backup] 备份 $SERVER_NAME 完成"
    fi
}

# 最新构建代码 移动到项目环境
function transfer() {
    echo "[transfer] 开始转移 $SERVER_NAME.jar"

    # 删除原 jar 包
    if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
        echo "[transfer] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过删除"
    else
        echo "[transfer] 移除 $BASE_PATH/$SERVER_NAME.jar 完成"
        rm $BASE_PATH/$SERVER_NAME.jar
    fi

    # 复制新 jar 包
    echo "[transfer] 从 $SOURCE_PATH 中获取 $SERVER_NAME.jar 并迁移至 $BASE_PATH ...."
    cp $SOURCE_PATH/$SERVER_NAME.jar $BASE_PATH

    echo "[transfer] 转移 $SERVER_NAME.jar 完成"
}

# 停止:优雅关闭之前已经启动的服务
function stop() {
    echo "[stop] 开始停止 $BASE_PATH/$SERVER_NAME"
    PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}')
    # 如果 Java 服务启动中,则进行关闭
    if [ -n "$PID" ]; then
        # 正常关闭
        echo "[stop] $BASE_PATH/$SERVER_NAME 运行中,开始 kill [$PID]"
        kill -15 $PID
        # 等待最大 120 秒,直到关闭完成。
        for ((i = 0; i < 120; i++))
            do
                sleep 1
                PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}')
                if [ -n "$PID" ]; then
                    echo -e ".\c"
                else
                    echo "[stop] 停止 $BASE_PATH/$SERVER_NAME 成功"
                    break
                fi
		    done

        # 如果正常关闭失败,那么进行强制 kill -9 进行关闭
        if [ -n "$PID" ]; then
            echo "[stop] $BASE_PATH/$SERVER_NAME 失败,强制 kill -9 $PID"
            kill -9 $PID
        fi
    # 如果 Java 服务未启动,则无需关闭
    else
        echo "[stop] $BASE_PATH/$SERVER_NAME 未启动,无需停止"
    fi
}

# 启动:启动后端项目
function start() {
    # 开启启动前,打印启动参数
    echo "[start] 开始启动 $BASE_PATH/$SERVER_NAME"
    echo "[start] JAVA_OPS: $JAVA_OPS"
    echo "[start] JAVA_AGENT: $JAVA_AGENT"
    echo "[start] PROFILES: $PROFILES_ACTIVE"

    echo "[docker] 构建镜像"
    docker stop $SERVER_NAME || true
    docker rm $SERVER_NAME || true
    docker rmi $SERVER_NAME || true
    docker build -t $SERVER_NAME:latest ./hbintrade-server/
    echo "[docker] 构建镜像完成"
    docker run -d -p 48080:48080 -v /root/soft/logs:/user/logs $SERVER_NAME

    echo "[docker] 项目启动完成"
    # 开始启动
#    echo "[start] 开始启动 BUILD_ID=dontKillMe nohup java -server $JAVA_OPS -jar $BASE_PATH/$SERVER_NAME.jar --spring.profiles.active=$PROFILES_ACTIVE &"
#    BUILD_ID=dontKillMe nohup java -server $JAVA_OPS -jar $BASE_PATH/$SERVER_NAME.jar --spring.profiles.active=$PROFILES_ACTIVE &
#    echo "[start] 启动 $BASE_PATH/$SERVER_NAME 完成"
}

# 健康检查:自动判断后端项目是否正常启动
function healthCheck() {
    # 如果配置健康检查,则进行健康检查
    if [ -n "$HEALTH_CHECK_URL" ]; then
        # 健康检查最大 120 秒,直到健康检查通过
        echo "[healthCheck] 开始通过 $HEALTH_CHECK_URL 地址,进行健康检查";
        for ((i = 0; i < 120; i++))
            do
                # 请求健康检查地址,只获取状态码。
                result=`curl -I -m 10 -o /dev/null -s -w %{http_code} $HEALTH_CHECK_URL || echo "000"`
                # 如果状态码为 200,则说明健康检查通过
                if [ "$result" == "200" ]; then
                    echo "[healthCheck] 健康检查通过";
                    break
                # 如果状态码非 200,则说明未通过。sleep 1 秒后,继续重试
                else
                    echo -e ".\c"
                    sleep 1
                fi
            done

        # 健康检查未通过,则异常退出 shell 脚本,不继续部署。
        if [ ! "$result" == "200" ]; then
            echo "[healthCheck] 健康检查不通过,可能部署失败。查看日志,自行判断是否启动成功";
            tail -n 10 nohup.out
            exit 1;
        # 健康检查通过,打印最后 10 行日志,可能部署的人想看下日志。
        else
            tail -n 10 nohup.out
        fi
    # 如果未配置健康检查,则 sleep 120 秒,人工看日志是否部署成功。
    else
        echo "[healthCheck] HEALTH_CHECK_URL 未配置,开始 sleep 120 秒";
        sleep 120
        echo "[healthCheck] sleep 120 秒完成,查看日志,自行判断是否启动成功";
        tail -n 50 nohup.out
    fi
}

# 部署
function deploy() {
    cd $BASE_PATH
    # 备份原 jar
#    backup
    # 停止 Java 服务
    stop
    # 部署新 jar
#    transfer
    # 启动 Java 服务
    start
    # 健康检查
    healthCheck
}

deploy

参考: 

Spring boot——Actuator 详解 - 曹伟雄 - 博客园 (cnblogs.com) 

3. Dockerfile

在server模块下

## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
## 感谢复旦核博士的建议!灰子哥,牛皮!
FROM eclipse-temurin:8-jre

## 创建目录,并使用它作为工作目录
RUN mkdir -p /hbintrade-server
WORKDIR /hbintrade-server
## 将后端项目的 Jar 文件,复制到镜像中
COPY ./target/hbintrade-server.jar app.jar

## 设置 TZ 时区
ENV TZ=Asia/Shanghai
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
ENV JAVA_OPTS="-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom"

## 应用参数
ENV ARGS=""

## 暴露后端项目的 48080 端口
EXPOSE 48080

## 启动后端项目
CMD java ${JAVA_OPTS} -jar app.jar $ARGS --spring.profiles.active=dev

三、Jenkins流水线配置

下载插件Extended Choice Parameter Plugin

新增版本号参数

流水线选择代码里面的Jenkinsfile相对路径

选择需要的分支构建任务

四、问题 

1. 多模块打包失败,不会自动打包依赖的其他模块

解决:flatten-maven-plugin统一版本打包失败问题记录-CSDN博客

2. 华为云公网IP访问不通

解决:华为云服务器公网ip访问不通解决-CSDN博客

参考:

  • Jenkins流水线--部署多模块maven项目(推荐) - 简书 (jianshu.com)
  • 使用docker-compose部署Redis(单机部署)_docker-compose redis单机-CSDN博客
  • 使用docker-compose 部署 MySQL(所有版本通用)_docker compose mysql-CSDN博客
  • 若依微服务集群搭建及jenkins自动化集群部署_若衣微服务版jekens-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python酷库之旅-第三方库Pandas(158)

目录 一、用法精讲 721、pandas.Timedelta.round方法 721-1、语法 721-2、参数 721-3、功能 721-4、返回值 721-5、说明 721-6、用法 721-6-1、数据准备 721-6-2、代码示例 721-6-3、结果输出 722、pandas.Timedelta.to_pytimedelta方法 722-1、语法 722-2、参数…

农作物苹果叶片病虫害识别数据集

农作物苹果叶片病虫害识别数据集 一、引言 农作物病虫害是影响农业生产的重要因素之一&#xff0c;其中苹果作为广泛种植的水果品种&#xff0c;其叶片病虫害问题尤为突出。为了有效应对苹果叶片病虫害&#xff0c;提高苹果产量和品质&#xff0c;农业科研机构和学者不断开展…

服务端负载均衡和客户端负载

负载均衡分为服务端负载均衡和客户端负载均衡&#xff0c;图解&#xff1a; 客户端的负载均衡还需要从注册中心获取集群部署的服务地址&#xff0c;其中客户的负载均衡器定时读取注册中心的IP和端口&#xff0c;然后缓存起来&#xff0c;这样以后可以先判断缓存IP和端口是否可用…

Java基于SSM微信小程序物流仓库管理系统设计与实现(源码+lw+数据库+讲解等)

选题背景 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…

#数据结构(二)

栈和队列 一.栈的顺序存储结构 特点&#xff1a;先进后出 栈是一种只能在一端进行插入或删除操作的线性表。 表中允许插入删除操作的一端为栈顶&#xff08;top&#xff09;&#xff0c;表的另一端为栈底&#xff08;bottom&#xff09;&#xff0c; 1 结构体的定义 #incl…

10月18日

二次型矩阵要是对称矩阵 通解要带入特解 集体化 逆反思维 先定特解&#xff0c;再求通解 反函数...我谢谢你 依旧是原函数

Vision China 2024 | 移远通信以一体化的AI训练及部署能力,引领3C电子制造智能升级

10月14日&#xff0c;由机器视觉产业联盟(CMVU)主办的中国机器视觉展(Vision China)在深圳国际会展中心盛大开幕。作为全球领先的物联网整体解决方案供应商&#xff0c;移远通信应邀参加展会首日举办的“智造引领数质并进”3C电子制造自动化与数字化论坛。 论坛上&#xff0c;移…

立仪科技:光谱共焦传感器精准测量玻璃

光谱共焦测量技术作为一种创新的光学检测方法&#xff0c;近年来在工业领域引起了广泛关注。 它以其高精度、非接触式的特点&#xff0c;特别适用于透明或半透明材料如玻璃的厚度和表面形貌测量。 接下来&#xff0c;立仪科技小编将深入探讨光谱共焦技术在玻璃测量上的应用及其…

火山引擎数智平台 VeDI:A/B 实验互斥域流量分配体系上线

近日&#xff0c;火山引擎 A/B 测试平台(DataTester)完成了一次重要升级&#xff0c;推出互斥域流量分配体系&#xff0c;这一功能意味着企业在产品优化策略上有新的突破空间。此次升级的核心亮点是允许企业根据实际需求&#xff0c;灵活地将用户流量分割成多个独立的区块&…

探索 Jupyter 笔记本转换的无限可能:nbconvert 库的神秘面纱

文章目录 探索 Jupyter 笔记本转换的无限可能&#xff1a;nbconvert 库的神秘面纱背景&#xff1a;为何选择 nbconvert&#xff1f;库简介&#xff1a;nbconvert 是什么&#xff1f;安装指南&#xff1a;如何安装 nbconvert&#xff1f;函数用法&#xff1a;简单函数示例应用场…

简单概述Ton链开发路径

区块链开发领域发展迅速&#xff0c;各种平台为开发人员提供不同的生态系统。其中一个更有趣且越来越相关的区块链是TON&#xff08;开放网络&#xff09;区块链。TON 区块链最初由 Telegram 构思&#xff0c;旨在提供快速、安全且可扩展的去中心化应用程序 (dApp)。凭借其独特…

LangGraph - Hierarchical Agent Teams

本文翻译整理自 Hierarchical Agent Teams https://langchain-ai.github.io/langgraph/tutorials/multi_agent/hierarchical_agent_teams/ 文章目录 一、前言二、设置三、创建工具四、Helper Utilities五、定义代理 Team研究 Team文档写作Team 六、添加图层 一、前言 在前面的…

恋爱脑讲编程:Rust 的生命周期概念

从前有两个年轻人&#xff1a;Alice 和 Bob。他们的爱情故事有几个阶段&#xff0c;代表不同的生命周期。Rust 的生命周期规则在这个故事中可以形象地表现为“爱情的时间线”&#xff0c;其中每一段关系都有明确的起始和结束时机&#xff0c;避免“未定义的情感”。 第一个阶段…

学习中,师傅b站泷羽sec——xss挖掘过程

某职业技术学院网站xss挖掘&#xff1a; 资产归纳 例如&#xff1a;先把功能点都看一遍&#xff0c;大部分都是文章 根据信息搜集第一课学习到一般主站的防御力是比较强的&#xff0c;出现漏洞的点不是对新手不友好。 在资产验证过程中还是把主站看了一遍 没有发现有攻击的机会…

如何看一个flutter项目的具体flutter版本

查看pubspec.lock文件 这个项目实际运行的就是 flutter 3.16.6 版本的

试用cursor的简单的记录

快下班时又饿了&#xff0c;饿了几个小时了。中午那点饭&#xff0c;没够顶到下班。难怪店家说饭可以随便加。 所以不编码了&#xff0c;本周任务也超额完成了&#xff0c;这种状态再去编码调试&#xff0c;搞不好会写出自己不认识的代码。 本周工作中&#xff0c;新的事务是…

Flink有状态计算

前言 状态是什么&#xff1f;状态就是数据&#xff0c;准确点说&#xff0c;状态是指 Flink 作业计算时依赖的历史数据或中间数据。如果一个 Flink 作业计算依赖状态&#xff0c;那它就是有状态计算的作业&#xff0c;反之就是无状态计算的作业。 举个例子&#xff0c;服务端…

鸿蒙开发(NEXT/API 12)【公共事件订阅与取消】进程间通信

CES&#xff08;Common Event Service&#xff0c;公共事件服务&#xff09;为应用程序提供订阅、发布、退订公共事件的能力。 公共事件分类 公共事件从系统角度可分为&#xff1a;系统公共事件和自定义公共事件。 系统公共事件&#xff1a;CES内部定义的公共事件&#xff0…

【特赞-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

SpringCloud Alibaba-02 Nacos服务注册与配置中心

Nacos是一个服务发现和管理平台&#xff0c;用于动态服务配置和注册。它支持服务发现、配置管理、服务健康检查&#xff0c;适用于多种服务类型。与Consul功能基本类似。 D:\project\pro1\nacos-server2.2.3\bin目录下启动cmd 执行命令 startup.cmd -m standalone 即可启动 …