jenkins通过pipeline部署springboot项目

部署方案:
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镜像之前不然会导致传递失败

基础镜像可选择:

openjdk:21-jdk
openjdk:21-slim
# 基于dibian构建bitnami/minideb

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.hqwc.cn/news/615809.html

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

相关文章

Pytorch导出FP16 ONNX模型

一般Pytorch导出ONNX时默认都是用的FP32,但有时需要导出FP16的ONNX模型,这样在部署时能够方便的将计算以及IO改成FP16,并且ONNX文件体积也会更小。想导出FP16的ONNX模型也比较简单,一般情况下只需要在导出FP32 ONNX的基础上调用下…

FebHost:给你注册法国.FR域名的8大理由

如果您的企业与法国有联系,或者您的目标受众是法国人,那么拥有 .fr 域名可以成为您的战略资产。以下是您可以考虑选择 .fr 域名的几个原因: 地理定位: 如果您的企业面向法国受众,或以与法国或法国境内某一特定地区的联…

每日一题---OJ题: 环形链表 II

片头 嗨! 小伙伴们,大家好! 我们又见面啦,在上一篇中,我们学习了环形链表I, 今天我们继续来打boss,准备好了吗? Ready Go ! ! ! emmm,同样都是环形链表,有什么不一样的地方呢? 肯定有, 要不然也不会一个标记为"简单" ,一个标记为"中等"了,哈哈哈哈哈 …

全新4.0版本圈子社交论坛系统 ,可打包小程序,于TP6+uni-app 全开源 可打包小程序app uniapp前端+全开源+独立版

简述 首先 圈子系统的核心是基于共同的兴趣或爱好将用户聚集在一起,这种设计使得用户能够迅速找到与自己有共同话题和兴趣的人。 其次 圈子系统提供了丰富的社交功能,如发帖、建圈子、发活动等,并且支持小程序授权登录、H5和APP等多种形式…

最齐全,最简单的免费SSL证书获取方法——实现HTTPS访问

一:阿里云 优势:大平台,在站长中知名度最高,提供20张免费单域名SSL证书 缺点:数量有限,并且只有单域名证书,通配符以及多域名没有免费版本。并且提供的单域名证书只有三个月的期限。 二&#…

【蓝桥杯】蓝桥杯算法复习(五)

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!&#x1f4…

Leetcode刷题之合并两个有序数组

Leetcode刷题之合并两个有序数组 一、题目描述二、题目解析 一、题目描述 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数…

使用Vivado Design Suite进行功率优化

功率优化是一个可选步骤,它通过使用时钟门控来优化动态功率。它既可以在Project模式下使用,也可以在Non-Project模式下使用,并且可以在逻辑优化之后或布局之后运行,以减少设计中的功率需求。功率优化包括Xilinx的智能时钟门控解决…

【零基础学数据结构】双向链表

1.双向链表的概念 1.1头节点 1.2带头双向循环链表 注意: 哨兵位创建后,首尾连接自己 1.3双链表的初始化 // 双向链表的初始化 void ListInit(ListNode** pphead) {// 给双链表创建一个哨兵位*pphead ListBuyNode(-1); } 2.双向链表的打印 // 双向…

HarmonyOS开发实例:【app帐号管理】

应用帐号管理 介绍 本示例选择应用进行注册/登录,并设置帐号相关信息,简要说明应用帐号管理相关功能。效果图如下: 效果预览 使用说明参考鸿蒙文档:qr23.cn/AKFP8k点击或者转到。 1.首页面选择想要进入的应用,首次进…

Redis 之集群模式

一 集群原理 集群,即Redis Cluster,是Redis 3.0开始引入的分布式存储方案。 集群由多个节点(Node)组成,Redis的数据分布在这些节点中。 集群中的节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护;从…

接口测试用例编写和接口测试模板

一、简介 接口测试区别于传统意义上的系统测试,下面介绍接口测试用例和接口测试报告。 二、接口测试用例模板 功能测试用例最重要的两个因素是测试步骤和预期结果,接口测试属于功能测试,所以同理。接口测试的步骤中,最重要的是将…