jenkins如何通過(guò)pipeline部署springboot項(xiàng)目
jenkins通過(guò)pipeline部署springboot項(xiàng)目
部署方案
1、springboot項(xiàng)目不保存部署的pipeline或dockerfile構(gòu)建腳本等與部署相關(guān)的問(wèn)文件,業(yè)務(wù)項(xiàng)目只需關(guān)心業(yè)務(wù),能夠正常構(gòu)建為jar包即可
2、新建一個(gè)代碼倉(cāng)庫(kù),用于保存項(xiàng)目需要構(gòu)建的Jenkinsfile
3、jenkins配置pipeline地址,從倉(cāng)庫(kù)拉取要構(gòu)建的項(xiàng)目進(jìn)行構(gòu)建和部署
構(gòu)建文件倉(cāng)庫(kù)示例結(jié)構(gòu)如下:

4、jenkins配置

5、springboot項(xiàng)目鏡像構(gòu)建文件
# 指定基礎(chǔ)鏡像,這是分階段構(gòu)建的前期階段
FROM eclipse-temurin:21-jre-alpine as builder
# 設(shè)定時(shí)區(qū)、中文
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
# 執(zhí)行工作目錄
WORKDIR application
# 配置參數(shù)
ARG JAR_FILE=target/*.jar
# 將編譯構(gòu)建得到的jar文件復(fù)制到鏡像空間中
COPY ${JAR_FILE} application.jar
# 通過(guò)工具spring-boot-jarmode-layertools從application.jar中提取拆分后的構(gòu)建結(jié)果
RUN java -Djarmode=layertools -jar application.jar extract
# 啟動(dòng)chronyd服務(wù)
CMD ["chronyd"]
# 正式構(gòu)建鏡像
FROM builder
WORKDIR application
# 前一階段從jar中提取除了多個(gè)文件,這里分別執(zhí)行COPY命令復(fù)制到鏡像空間中,每次COPY都是一個(gè)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"]
# 分層構(gòu)建傳遞參數(shù)寫法
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參數(shù)和覆蓋配置文件參數(shù)寫在docker鏡像之前不然會(huì)導(dǎo)致傳遞失敗
基礎(chǔ)鏡像可選擇:
eclipse-temurin:21-jre-alpine eclipse-temurin:21-jdk-alpine openjdk:21 openjdk:21-slim # 基于dibian構(gòu)建 bitnami/minideb debian:bullseye-slim

6、demo項(xiàng)目docker-compose.yml文件
services:
demo:
# 啟動(dòng)時(shí)傳入鏡像tag示例:BUILD_TAG=20240406-57 docker-compose up -d
image: registry.cn-guangzhou.aliyuncs.com/lyr-test/demo:${BUILD_TAG}
container_name: demo
restart: always
network_mode: host
deploy:
resources:
limits:
cpus: '1.00'
memory: 1G
reservations:
cpus: '0.10'
memory: 256M
environment:
- JAVA_OPTS= -XX:+UseContainerSupport -XX:InitialRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0 -XX:MinRAMPercentage=75.0
# 當(dāng)network_mode使用hots模式時(shí),端口號(hào)設(shè)置不生效
- PARAMS = --server.port=80807、Jenkinsfile構(gòu)建文件
// 獲取當(dāng)前日期
def current_date = new Date().format('yyyyMMdd')
// 獲取當(dāng)前構(gòu)建號(hào)
def build_number = env.BUILD_NUMBER.toInteger()
// 服務(wù)器集合
def server_list = []
// 所有的腳本命令放在pipeline中
pipeline {
// 指定任務(wù)在哪個(gè)集群節(jié)點(diǎn)中執(zhí)行,any表示任意節(jié)點(diǎn)
agent any
parameters {
string(description: '代碼分支', name: 'CODE_BRANCH_PARAM', defaultValue: 'master', trim: true)
// 這在Jenkins的憑據(jù)里設(shè)置的待部署服務(wù)器的名稱就是服務(wù)器的ip;用docker-compose部署一般只會(huì)部署幾臺(tái)服務(wù)器,如果量大,建議上k8s
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"
CODE_ADDRESS = "https://********/demo.git"
// jenkins中創(chuàng)建的代碼倉(cāng)庫(kù)密鑰id
CREDENTIALS_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('環(huán)境檢測(cè)') {
steps {
// 構(gòu)建環(huán)境檢測(cè)
sh '''
cat /proc/version
free -m
df -h
docker -v
git -v
mvn -v
java -version
'''
echo '環(huán)境檢測(cè)完成'
}
}
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為構(gòu)建分支參數(shù)
git branch: "${CODE_BRANCH_PARAM}", credentialsId: "${CREDENTIALS_ID}", url: "${CODE_ADDRESS}"
}
}
stage('maven構(gòu)建') {
steps {
echo pwd
sh """
mvn clean package -U -Dmaven.test.skip=true
"""
}
}
stage('生成鏡像') {
steps {
echo pwd
// JOB_NAME為項(xiàng)目名變量(內(nèi)置的環(huán)境變量) TAG為設(shè)置的變量標(biāo)簽
sh '''
cp /var/jenkins_home/workspace/pipeline/${JOB_NAME}/Dockerfile /var/jenkins_home/workspace/${JOB_NAME}
'''
script {
echo "當(dāng)前鏡像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 -f
docker push ${IMG_REPO}/${REPO_NAMESPACE}/${JOB_NAME}:${DEFAULT_BUILD_TAG}
'''
}
}
}
stage('清理') {
steps {
sh '''
# 退出鏡像倉(cāng)庫(kù)
# docker logout ${IMG_REPO}
# 清理前鏡像
# docker images
# 刪除指定鏡像
# docker rmi ${IMG_REPO}/${REPO_NAMESPACE}/${JOB_NAME}:${PRE_BUILD_TAG}
# 命令刪除,刪除最早一個(gè)
# docker images | grep "demo" | sort -r | tail -n 1 | awk '{print $3}' | xargs docker rmi
# 清理后鏡像
docker images
'''
}
}
stage('部署至服務(wù)器') {
steps {
script {
script {
echo "SERVER_1:" + SERVER_1
if (SERVER_1=="true") {
server_list.add('10.0.24.8')
}
echo "SERVER_2:" + SERVER_2
if (SERVER_2=="true") {
server_list.add('10.0.24.3')
}
for (server_ip in server_list) {
echo "當(dāng)前部署的服務(wù)器id:${server_ip}"
withCredentials([usernamePassword(credentialsId: server_ip, passwordVariable: 'SERVER_PWD', usernameVariable: 'SERVER_USER')]) {
node {
def remote = [:]
remote.name = "deploy"
remote.host = server_ip
remote.user = "${SERVER_USER}"
remote.password = "${SERVER_PWD}"
remote.allowAnyHosts = true
stage('遠(yuǎn)程ssh部署') {
echo "當(dāng)前遠(yuǎn)程ssh部署的項(xiàng)目名:${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 -d
docker-compose ps
"""
echo "ssh部署腳本執(zhí)行完成"
}
}
}
}
}
}
}
}
}
// 通知內(nèi)容
post {
success {
//成功通知
echo "成功通知"
}
failure {
// 失敗通知
echo "失敗通知"
}
}
}8、jenkins中配置Jenkinsfile中使用到的代碼倉(cāng)庫(kù)憑據(jù),鏡像倉(cāng)庫(kù)憑據(jù)和服務(wù)器密碼憑據(jù)

9、配置完成后,點(diǎn)擊構(gòu)建就行

10、當(dāng)首次部署到新服務(wù)器時(shí),需要登錄鏡像倉(cāng)庫(kù),可以手動(dòng)登錄,也可以在jenkins中進(jìn)行配置,每次發(fā)布都要登錄,不然會(huì)拉取鏡像錯(cuò)誤
// 服務(wù)器集合
def server_list = []
// 所有的腳本命令放在pipeline中
pipeline {
// 指定任務(wù)在哪個(gè)集群節(jié)點(diǎn)中執(zhí)行,any表示任意節(jié)點(diǎn)
agent any
parameters {
choice(description: '服務(wù)名', 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中創(chuàng)建的代碼倉(cāng)庫(kù)密鑰id
CREDENTIALS_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('環(huán)境檢測(cè)') {
steps {
// 構(gòu)建環(huán)境檢測(cè)
sh '''
cat /proc/version
free -m
df -h
docker -v
git -v
mvn -v
java -version
'''
echo '環(huán)境檢測(cè)完成'
}
}
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_1
if (SERVER_1=="true") {
server_list.add('10.0.24.8')
}
echo "SERVER_2:" + SERVER_2
if (SERVER_2=="true") {
server_list.add('10.0.24.3')
}
for (server_ip in server_list) {
echo "當(dāng)前部署的服務(wù)器id:${server_ip}"
withCredentials([usernamePassword(credentialsId: server_ip, passwordVariable: 'SERVER_PWD', usernameVariable: 'SERVER_USER')]) {
node {
def remote = [:]
remote.name = "deploy"
remote.host = server_ip
remote.user = "${SERVER_USER}"
remote.password = "${SERVER_PWD}"
remote.allowAnyHosts = true
stage('遠(yuǎn)程ssh部署') {
echo "當(dāng)前遠(yuǎn)程ssh登錄的服務(wù)器ip:${server_ip}"
sshCommand remote: remote, command: """
echo "${IMG_PWD}" | docker login --username ${IMG_USER} --password-stdin ${IMG_REPO}
"""
echo "鏡像ssh部署腳本執(zhí)行完成"
}
}
}
}
}
}
}
}
stage('部署至服務(wù)器') {
steps {
script {
script {
echo "SERVER_1:" + SERVER_1
if (SERVER_1=="true") {
server_list.add('10.0.24.8')
}
echo "SERVER_2:" + SERVER_2
if (SERVER_2=="true") {
server_list.add('10.0.24.3')
}
for (server_ip in server_list) {
echo "當(dāng)前部署的服務(wù)器id:${server_ip}"
withCredentials([usernamePassword(credentialsId: server_ip, passwordVariable: 'SERVER_PWD', usernameVariable: 'SERVER_USER')]) {
node {
def remote = [:]
remote.name = "deploy"
remote.host = server_ip
remote.user = "${SERVER_USER}"
remote.password = "${SERVER_PWD}"
remote.allowAnyHosts = true
stage('遠(yuǎn)程ssh部署') {
echo "當(dāng)前遠(yuǎn)程ssh部署的項(xiàng)目名:${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 -d
docker-compose ps
"""
echo "ssh部署腳本執(zhí)行完成"
}
}
}
}
}
}
}
}
}
// 通知內(nèi)容
post {
success {
//成功通知
echo "成功通知"
}
failure {
// 失敗通知
echo "失敗通知"
}
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Jenkins Pipeline 部署 SpringBoot 應(yīng)用的教程詳解
- 使用Jenkins一鍵打包部署SpringBoot項(xiàng)目的步驟詳解
- Jenkins自動(dòng)化部署SpringBoot項(xiàng)目的實(shí)現(xiàn)
- Jenkins一鍵打包部署SpringBoot應(yīng)用
- Jenkins+Docker?一鍵自動(dòng)化部署?SpringBoot?項(xiàng)目的詳細(xì)步驟
- 阿里SpringBoot應(yīng)用自動(dòng)化部署實(shí)現(xiàn)IDEA版Jenkins
- Jenkins+Docker+Gitee+SpringBoot自動(dòng)化部署
相關(guān)文章
詳解Java編寫算法時(shí)如何加快讀寫數(shù)據(jù)速度
這篇文章主要為大家詳細(xì)介紹了Java在編寫算法時(shí)如何加快讀寫數(shù)據(jù)速度,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
Spring4下validation數(shù)據(jù)校驗(yàn)無(wú)效(maven)的解決
這篇文章主要介紹了Spring4下validation數(shù)據(jù)校驗(yàn)無(wú)效(maven)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java技能點(diǎn)之SimpleDateFormat進(jìn)行日期格式化問(wèn)題
這篇文章主要介紹了Java技能點(diǎn)之SimpleDateFormat進(jìn)行日期格式化問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
通過(guò)案例了解靜態(tài)修飾符static使用場(chǎng)景
這篇文章主要介紹了通過(guò)案例了解靜態(tài)修飾符static使用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
如何基于FTP4J實(shí)現(xiàn)FTPS連接過(guò)程解析
這篇文章主要介紹了如何基于FTP4J實(shí)現(xiàn)FTPS連接過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10

