jenkins如何通過pipeline部署springboot項目
jenkins通過pipeline部署springboot項目
部署方案
1、springboot項目不保存部署的pipeline或dockerfile構(gòu)建腳本等與部署相關(guān)的問文件,業(yè)務(wù)項目只需關(guān)心業(yè)務(wù),能夠正常構(gòu)建為jar包即可
2、新建一個代碼倉庫,用于保存項目需要構(gòu)建的Jenkinsfile
3、jenkins配置pipeline地址,從倉庫拉取要構(gòu)建的項目進行構(gòu)建和部署
構(gòu)建文件倉庫示例結(jié)構(gòu)如下:
4、jenkins配置
5、springboot項目鏡像構(gòu)建文件
# 指定基礎(chǔ)鏡像,這是分階段構(gòu)建的前期階段 FROM eclipse-temurin:21-jre-alpine as builder # 設(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 # 通過工具spring-boot-jarmode-layertools從application.jar中提取拆分后的構(gòu)建結(jié)果 RUN java -Djarmode=layertools -jar application.jar extract # 啟動chronyd服務(wù) CMD ["chronyd"] # 正式構(gòu)建鏡像 FROM builder WORKDIR application # 前一階段從jar中提取除了多個文件,這里分別執(zhí)行COPY命令復(fù)制到鏡像空間中,每次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"] # 分層構(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鏡像之前不然會導(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項目docker-compose.yml文件
services: demo: # 啟動時傳入鏡像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 # 當network_mode使用hots模式時,端口號設(shè)置不生效 - PARAMS = --server.port=8080
7、Jenkinsfile構(gòu)建文件
// 獲取當前日期 def current_date = new Date().format('yyyyMMdd') // 獲取當前構(gòu)建號 def build_number = env.BUILD_NUMBER.toInteger() // 服務(wù)器集合 def server_list = [] // 所有的腳本命令放在pipeline中 pipeline { // 指定任務(wù)在哪個集群節(jié)點中執(zhí)行,any表示任意節(jié)點 agent any parameters { string(description: '代碼分支', name: 'CODE_BRANCH_PARAM', defaultValue: 'master', trim: true) // 這在Jenkins的憑據(jù)里設(shè)置的待部署服務(wù)器的名稱就是服務(wù)器的ip;用docker-compose部署一般只會部署幾臺服務(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)建的代碼倉庫密鑰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)境檢測') { steps { // 構(gòu)建環(huán)境檢測 sh ''' cat /proc/version free -m df -h docker -v git -v mvn -v java -version ''' echo '環(huán)境檢測完成' } } 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為項目名變量(內(nèi)置的環(huán)境變量) TAG為設(shè)置的變量標簽 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 -f docker 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('部署至服務(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 "當前部署的服務(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('遠程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 -d docker-compose ps """ echo "ssh部署腳本執(zhí)行完成" } } } } } } } } } // 通知內(nèi)容 post { success { //成功通知 echo "成功通知" } failure { // 失敗通知 echo "失敗通知" } } }
8、jenkins中配置Jenkinsfile中使用到的代碼倉庫憑據(jù),鏡像倉庫憑據(jù)和服務(wù)器密碼憑據(jù)
9、配置完成后,點擊構(gòu)建就行
10、當首次部署到新服務(wù)器時,需要登錄鏡像倉庫,可以手動登錄,也可以在jenkins中進行配置,每次發(fā)布都要登錄,不然會拉取鏡像錯誤
// 服務(wù)器集合 def server_list = [] // 所有的腳本命令放在pipeline中 pipeline { // 指定任務(wù)在哪個集群節(jié)點中執(zhí)行,any表示任意節(jié)點 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)建的代碼倉庫密鑰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)境檢測') { steps { // 構(gòu)建環(huán)境檢測 sh ''' cat /proc/version free -m df -h docker -v git -v mvn -v java -version ''' echo '環(huán)境檢測完成' } } 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 "當前部署的服務(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('遠程ssh部署') { echo "當前遠程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 "當前部署的服務(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('遠程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 -d docker-compose ps """ echo "ssh部署腳本執(zhí)行完成" } } } } } } } } } // 通知內(nèi)容 post { success { //成功通知 echo "成功通知" } failure { // 失敗通知 echo "失敗通知" } } }
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java編寫算法時如何加快讀寫數(shù)據(jù)速度
這篇文章主要為大家詳細介紹了Java在編寫算法時如何加快讀寫數(shù)據(jù)速度,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03Spring4下validation數(shù)據(jù)校驗無效(maven)的解決
這篇文章主要介紹了Spring4下validation數(shù)據(jù)校驗無效(maven)的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Java技能點之SimpleDateFormat進行日期格式化問題
這篇文章主要介紹了Java技能點之SimpleDateFormat進行日期格式化問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04