jenkins通过pipeline部署springboot项目

news/2024/5/21 20:43:31

部署方案:
1、springboot项目不保存部署的pipeline或dockerfile构建脚本等与部署相关的问文件,业务项目只需关心业务,能够正常构建为jar包即可
2、新建一个代码仓库,用于保存项目需要构建的Jenkinsfile
3、jenkins配置pipeline地址,从仓库拉取要构建的项目进行构建和部署
构建文件仓库示例结构如下:
在这里插入图片描述
4、jenkins配置
在这里插入图片描述
5、springboot项目镜像构建文件

# 指定基础镜像,这是分阶段构建的前期阶段
FROM eclipse-temurin:21-jre-alpine as builder# 设定时区、中文
ENV TZ=Asia/Shanghai
# 安装chrony包
RUN apk add --no-cache chrony# 配置chrony
RUN echo "server 0.pool.ntp.org iburst" >> /etc/chrony/chrony.conf
RUN echo "server 1.pool.ntp.org iburst" >> /etc/chrony/chrony.conf
RUN echo "server 2.pool.ntp.org iburst" >> /etc/chrony/chrony.conf
RUN echo "server 3.pool.ntp.org iburst" >> /etc/chrony/chrony.conf# 执行工作目录
WORKDIR application
# 配置参数
ARG JAR_FILE=target/*.jar
# 将编译构建得到的jar文件复制到镜像空间中
COPY ${JAR_FILE} application.jar
# 通过工具spring-boot-jarmode-layertools从application.jar中提取拆分后的构建结果
RUN java -Djarmode=layertools -jar application.jar extract
# 启动chronyd服务
CMD ["chronyd"]# 正式构建镜像
FROM builder
WORKDIR application
# 前一阶段从jar中提取除了多个文件,这里分别执行COPY命令复制到镜像空间中,每次COPY都是一个layer
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
# ENTRYPOINT  ["java", "org.springframework.boot.loader.JarLauncher"]
# 分层构建传递参数写法
ENTRYPOINT  ["sh","-c","java  $JAVA_OPTS org.springframework.boot.loader.JarLauncher $PARAMS"]# 新新
# 例如: docker run -d -p 21991:2199 --name demo3 -e JAVA_OPTS="-Xmx128m"  -e PARAMS="--spring.application.name=test-demo" docker-demo:1.3
#镜像放在最后,所传的java参数和覆盖配置文件参数写在docker镜像之前不然会导致传递失败

基础镜像可选择:

eclipse-temurin:21-jre-alpine
eclipse-temurin:21-jdk-alpine
openjdk:21
openjdk:21-slim
# 基于dibian构建bitnami/minidebdebian:bullseye-slim

在这里插入图片描述

6、demo项目docker-compose.yml文件

services:demo:#  启动时传入镜像tag示例:BUILD_TAG=20240406-57 docker-compose up -dimage: registry.cn-guangzhou.aliyuncs.com/lyr-test/demo:${BUILD_TAG}container_name: demorestart: alwaysnetwork_mode: hostdeploy:resources:limits:cpus: '1.00'memory: 1Greservations:cpus: '0.10'memory: 256Menvironment:- JAVA_OPTS= -XX:+UseContainerSupport -XX:InitialRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0 -XX:MinRAMPercentage=75.0# 当network_mode使用hots模式时,端口号设置不生效- PARAMS = --server.port=8080

7、Jenkinsfile构建文件

// 获取当前日期
def current_date = new Date().format('yyyyMMdd')
// 获取当前构建号
def build_number = env.BUILD_NUMBER.toInteger()
// 服务器集合
def server_list = []
// 所有的脚本命令放在pipeline中
pipeline {// 指定任务在哪个集群节点中执行,any表示任意节点agent anyparameters {string(description: '代码分支', name: 'CODE_BRANCH_PARAM', defaultValue: 'master', trim: true)// 这在Jenkins的凭据里设置的待部署服务器的名称就是服务器的ip;用docker-compose部署一般只会部署几台服务器,如果量大,建议上k8sbooleanParam defaultValue: true, description: '10.0.24.8', name: 'SERVER_1'booleanParam description: '10.0.24.3', name: 'SERVER_2'}tools {git 'Default'}// 声明全局变量,方便后面修改使用environment {GIT_CONFIG_BRANCH = "master"GIT_CONFIG_ADDRESS = "https://*******/demo-jenkins.git"CODE_ADDRESS = "https://********/demo.git"// jenkins中创建的代码仓库密钥idCREDENTIALS_ID = 'git-credentials-id'IMG_REPO_CREDENTIALS_ID = 'img-repo-credentials-id'IMG_REPO = "registry.cn-guangzhou.aliyuncs.com"REPO_NAMESPACE = 'lyr-test'DEFAULT_BUILD_TAG = "${current_date}-${build_number}"}stages {stage('环境检测') {steps {// 构建环境检测sh '''cat /proc/versionfree -mdf -hdocker -vgit -vmvn -vjava -version'''echo '环境检测完成'}}stage('拉取配置文件') {steps {echo "拉取配置文件代码分支:${GIT_CONFIG_BRANCH}"sh "pwd"dir('/var/jenkins_home/workspace/pipeline/') {sh "pwd"echo "${CREDENTIALS_ID}"checkout scmGit(branches: [[name: "${GIT_CONFIG_BRANCH}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${CREDENTIALS_ID}", url: "${GIT_CONFIG_ADDRESS}"]])}sh "pwd"}}stage('拉取代码') {steps {echo pwd// BRANCH为构建分支参数git branch: "${CODE_BRANCH_PARAM}", credentialsId: "${CREDENTIALS_ID}", url: "${CODE_ADDRESS}"}}stage('maven构建') {steps {echo pwdsh """mvn clean package -U -Dmaven.test.skip=true"""}}stage('生成镜像') {steps {echo pwd// JOB_NAME为项目名变量(内置的环境变量) TAG为设置的变量标签sh '''cp /var/jenkins_home/workspace/pipeline/${JOB_NAME}/Dockerfile /var/jenkins_home/workspace/${JOB_NAME}'''script {echo "当前镜像tag:${DEFAULT_BUILD_TAG}"sh "docker build -f Dockerfile  -t ${IMG_REPO}/${REPO_NAMESPACE}/${JOB_NAME}:${DEFAULT_BUILD_TAG} ."}}}stage('推送镜像') {steps {withCredentials([usernamePassword(credentialsId: 'img-repo-credentials-id', passwordVariable: 'IMG_PWD', usernameVariable: 'IMG_USER')]) {sh '''echo "${IMG_PWD}" | docker login --username ${IMG_USER} --password-stdin ${IMG_REPO}docker image prune -fdocker push ${IMG_REPO}/${REPO_NAMESPACE}/${JOB_NAME}:${DEFAULT_BUILD_TAG}'''}}}stage('清理') {steps {sh '''# 退出镜像仓库# docker logout ${IMG_REPO}# 清理前镜像# docker images# 删除指定镜像# docker rmi ${IMG_REPO}/${REPO_NAMESPACE}/${JOB_NAME}:${PRE_BUILD_TAG}# 命令删除,删除最早一个# docker images | grep "demo" | sort -r | tail -n 1 | awk '{print $3}'  | xargs docker rmi# 清理后镜像docker images'''}}stage('部署至服务器') {steps {script {script {echo "SERVER_1:" + SERVER_1if (SERVER_1=="true") {server_list.add('10.0.24.8')}echo "SERVER_2:" + SERVER_2if (SERVER_2=="true") {server_list.add('10.0.24.3')}for (server_ip in server_list) {echo "当前部署的服务器id:${server_ip}"withCredentials([usernamePassword(credentialsId: server_ip, passwordVariable: 'SERVER_PWD', usernameVariable: 'SERVER_USER')]) {node {def remote = [:]remote.name = "deploy"remote.host = server_ipremote.user = "${SERVER_USER}"remote.password = "${SERVER_PWD}"remote.allowAnyHosts = truestage('远程ssh部署') {echo "当前远程ssh部署的项目名:${JOB_NAME}"sshCommand remote: remote, command: "mkdir -p /data/${JOB_NAME}"sshPut remote: remote, from: """/var/jenkins_home/workspace/pipeline/${JOB_NAME}/docker-compose.yaml""", into: """/data/${JOB_NAME}"""sshCommand remote: remote, command: """cd /data/${JOB_NAME}/BUILD_TAG=${DEFAULT_BUILD_TAG} docker-compose up -ddocker-compose ps"""echo "ssh部署脚本执行完成"}}}}}}}}}// 通知内容post {success {//成功通知echo "成功通知"}failure {// 失败通知echo "失败通知"}}
}

8、jenkins中配置Jenkinsfile中使用到的代码仓库凭据,镜像仓库凭据和服务器密码凭据
在这里插入图片描述
9、配置完成后,点击构建就行
在这里插入图片描述
10、当首次部署到新服务器时,需要登录镜像仓库,可以手动登录,也可以在jenkins中进行配置,每次发布都要登录,不然会拉取镜像错误

// 服务器集合
def server_list = []
// 所有的脚本命令放在pipeline中
pipeline {// 指定任务在哪个集群节点中执行,any表示任意节点agent anyparameters {choice(description: '服务名', name: 'SERVICE_NAME', choices: ["demo"])string(description: '镜像tag', name: 'BUILD_TAG_PARAM', defaultValue: '20240405-01', trim: true)booleanParam defaultValue: true, description: '10.0.24.8', name: 'SERVER_1'booleanParam description: '10.0.24.3', name: 'SERVER_2'}tools {git 'Default'}// 声明全局变量,方便后面修改使用environment {GIT_CONFIG_BRANCH = "master"GIT_CONFIG_ADDRESS = "https://******/demo-jenkins.git"// jenkins中创建的代码仓库密钥idCREDENTIALS_ID = 'git-credentials-id'IMG_REPO_CREDENTIALS_ID = 'img-repo-credentials-id'IMG_REPO = "registry.cn-guangzhou.aliyuncs.com"REPO_NAMESPACE = 'lyr-test'}stages {stage('环境检测') {steps {// 构建环境检测sh '''cat /proc/versionfree -mdf -hdocker -vgit -vmvn -vjava -version'''echo '环境检测完成'}}stage('拉取配置文件') {steps {echo "拉取配置文件代码分支:${GIT_CONFIG_BRANCH}"sh "pwd"dir('/var/jenkins_home/workspace/pipeline/') {sh "pwd"echo "${CREDENTIALS_ID}"checkout scmGit(branches: [[name: "${GIT_CONFIG_BRANCH}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${CREDENTIALS_ID}", url: "${GIT_CONFIG_ADDRESS}"]])}sh "pwd"}}stage('登录镜像') {steps {withCredentials([usernamePassword(credentialsId: 'img-repo-credentials-id', passwordVariable: 'IMG_PWD', usernameVariable: 'IMG_USER')]) {script {echo "SERVER_1:" + SERVER_1if (SERVER_1=="true") {server_list.add('10.0.24.8')}echo "SERVER_2:" + SERVER_2if (SERVER_2=="true") {server_list.add('10.0.24.3')}for (server_ip in server_list) {echo "当前部署的服务器id:${server_ip}"withCredentials([usernamePassword(credentialsId: server_ip, passwordVariable: 'SERVER_PWD', usernameVariable: 'SERVER_USER')]) {node {def remote = [:]remote.name = "deploy"remote.host = server_ipremote.user = "${SERVER_USER}"remote.password = "${SERVER_PWD}"remote.allowAnyHosts = truestage('远程ssh部署') {echo "当前远程ssh登录的服务器ip:${server_ip}"sshCommand remote: remote, command: """echo "${IMG_PWD}" | docker login --username ${IMG_USER} --password-stdin ${IMG_REPO}"""echo "镜像ssh部署脚本执行完成"}}}}}}}}stage('部署至服务器') {steps {script {script {echo "SERVER_1:" + SERVER_1if (SERVER_1=="true") {server_list.add('10.0.24.8')}echo "SERVER_2:" + SERVER_2if (SERVER_2=="true") {server_list.add('10.0.24.3')}for (server_ip in server_list) {echo "当前部署的服务器id:${server_ip}"withCredentials([usernamePassword(credentialsId: server_ip, passwordVariable: 'SERVER_PWD', usernameVariable: 'SERVER_USER')]) {node {def remote = [:]remote.name = "deploy"remote.host = server_ipremote.user = "${SERVER_USER}"remote.password = "${SERVER_PWD}"remote.allowAnyHosts = truestage('远程ssh部署') {echo "当前远程ssh部署的项目名:${SERVICE_NAME}"sshCommand remote: remote, command: "mkdir -p /data/${SERVICE_NAME}"sshPut remote: remote, from: """/var/jenkins_home/workspace/pipeline/${SERVICE_NAME}/docker-compose.yaml""", into: """/data/${SERVICE_NAME}"""sshCommand remote: remote, command: """cd /data/${SERVICE_NAME}/BUILD_TAG=${BUILD_TAG_PARAM} docker-compose up -ddocker-compose ps"""echo "ssh部署脚本执行完成"}}}}}}}}}// 通知内容post {success {//成功通知echo "成功通知"}failure {// 失败通知echo "失败通知"}}
}

http://www.mrgr.cn/p/12017107

相关文章

异常体系

java中有许多异常: 异常捕获: 小例子: 灵魂一问: 灵魂二问: 当在try中出现异常,会new一个异常对象去与catch的异常对比,若可以接收new出来的异常对象那么就执行该catch中的内容 灵魂三问: 灵魂四问:抛出异常: 总结: throw写在方法内,try catch写在调用方法处 …

C++进阶——继承

前言:从这篇文章开始,我们进入C进阶知识的分享,在此之前,我们需要先来回顾一个知识: C语言有三大特性,分别是封装、继承和多态,而我们前边所分享的各种容器类,迭代器等,…

团队博客

项目原型展示说明 “冀网社区聘”——社区招聘项目 是否为日常生活问题感到困扰?是否在因不熟悉的工作愁眉苦脸?我们“冀网社区聘”平台致力于为客户提供快捷,直接的服务。在我们的“冀网社区聘”平台上,雇主可以轻松发布社区内或者跨社区招聘需求,而相应的求职者则可以浏…

JS混淆代码数据集构建方法

数据获取(1)公开JS数据集,比如CodeSearchNet; (2)自行构建JS数据集,爬取Github开源前端项目;数据描述Github中采集前端项目文件分类如下,从中提取JS文件数据预处理其中比较重要的步骤:(1)代码混淆:使用现有工具,如UglifyJS、Terser、babel-minify、JS-Obfuscator…

Java API之查询文档

1、查询指定id文档import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.client.RequestOptions; import org.util.ConnectElasticsearch;public class GetDoc {public static void main(String[] arg…

基于STM32智能垃圾桶系统设计(论文)_kaic

摘 要 城市的不断扩张建设,生活中产生了大量垃圾,垃圾桶现在是非常多的在我们生活中是不可或缺的一部分,环卫工人每天都是在整理收拾垃圾,会造成很多的麻烦,为了解决这个问题我们研究出了基于STM32智能垃圾桶系统设计…

[9] UE C++ Snake

思维导图背景地图制作 创建瓦片集角色素材GameMode功能 游戏开始控制食物的生成食物生成池(性能优化) /**形参如果是一个引用,且没有添加const关键字,代表实参想要借助形参修改值* param 是否指定生成时候的地址*/ void ASnakeGameModeBase::SpawnFood(FVector& SpawnLoc…

服务器raid卡,守护数据安全,赋能新质生产力

RAID卡,全称为独立冗余磁盘阵列卡,在数据中心、服务器、网络存储等领域得到广泛应用,RAID卡通过不同的RAID级别实现数据容错和冗余。例如,RAID 0主要适用于需要高速数据传输但对数据安全要求不高的场景,如数据的缓存;RAID 1使用镜像备份确保数据不因硬盘故障而丢失。然而…

Spring Boot 拦截器

拦截器是Spring 框架提供的核心功能之一,主要用于拦截用户的请求,在指定方法的前后根据业务需要执行代码。 例如登录场景,有可能我们访问一个网页时,我们的登录信息过期了,就需要重新登录,那么就可使用拦截…

夜莺监控 V7 第二个 beta 版本发布,内置集成故障自愈能力,简化部署

经过一个半月的打磨改进,夜莺监控 V7 第二个 beta 版本发布了,本次发布的主要亮点是内置集成故障自愈能力,简化架构,同时做了其他 19 项改进。一些重要的改进如下:feat: 集成故障自愈的能力,不需要再单独部署 ibex 模块了 refactor: 内置仪表盘和内置规则页面重构 refact…

cowa新的数据筛选代码

cowa新的数据筛选代码 代码地址: https://git.cowarobot.com/lhb/data_extracting 一阶段筛选 修改配置文件 config/common_stage.yamlversion: 3 services:de:image: harbor.cowarobot.cn/lhb/data:crpilot2.5-torch2.2environment:- CRPILOT_INSTALL_VERSIONx86…

JavaFx项目打包成exe,并集成Jre,使Java项目在任意机器运行

1.关键点:通过springboot打包插件,将项目依赖都打到一个jar包内。 以下是pom配置文件:<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1…

每天学点儿Python(6) -- 列表和枚举

列表是Python中内置的可变序列&#xff0c;类使用C/C中的数组&#xff0c;使用 [ ] 定义列表&#xff0c;列表中的元素与元素之间用英文逗号&#xff08; , &#xff09;分隔&#xff0c; 但是Python中列表可以存储任意类型的数据&#xff0c;且可以混存&#xff08;即类型可以…

react17 + antd4 如何实现Card组件与左侧内容对齐并撑满高度

在使用antd进行页面布局时&#xff0c;经常会遇到需要将内容区域进行左右分栏&#xff0c;并在右侧区域内放置一个或多个Card组件的情况。然而&#xff0c;有时我们会发现右侧的Card组件并不能与左侧的栏目对齐&#xff0c;尤其是当左侧栏目高度动态变化时。本文将介绍如何使用…

vue简单使用三(class样式绑定)

目录 对象的形式绑定&#xff1a; 数组的形式绑定&#xff1a; 内联样式Style 对象的形式绑定&#xff1a; 可以看到class中有两个值 数组的形式绑定&#xff1a; 可以看到也有两个值 内联样式Style style样式设置成功 完整代码&#xff1a; <!DOCTYPE html> <html…

小程序技术实现前端热更新的优势

小程序作为轻量级的移动应用形态,凭借其无需下载安装、即用即走的特性,迅速获得用户的青睐。同时,小程序技术也为前端热更新提供了天然的优势。通过 Service Worker 等机制,小程序可以拦截网络请求,动态更新前端代码,而无需用户重新下载应用。小程序技术是一种很有前景的…

互联网轻量级框架整合之MyBatis核心组件

在看本篇内容之前&#xff0c;最好先理解一下Hibernate和MyBatis的本质区别&#xff0c;这篇Hibernate和MyBatis使用对比实例做了实际的代码级对比&#xff0c;而MyBatis作为更适合互联网产品的持久层首选必定有必然的原因 MyBatis核心组件 MyBatis能够成为数据持久层首选框&a…

2024.4.16(周二)腾讯公益赛构思展示

团队成员:郑天羽 张晨旭 孙怡然产品介绍:

基于RAM的几何变换——镜像

基于RAM的几何变换——镜像 一、镜像基本概念 镜像变换可以分为水平镜像和竖直镜像,也就是我们所理解的x轴对称和y轴对称问题。可以预见的是,简单的打拍以及无法满足缓存了,要想实现水平镜像起码需要缓存一整行数据,要想实现垂直镜像起码要缓存一帧数据。这里我们可以直接思…

uniCloud云函数概述---公用模块

公用模块可以被普通云函数、云对象调用。它存放在cloudfunctions/comon文件夹内。一、创建公用模块 打开项目,右击cloudfunctions/comon文件夹,选择“新建公用模块”创建好的公共模块包含二个文件: index.js //公共模块文件 package.json //配置文件二、公用模块模板 A)公…