Files
timeline-server/Jenkinsfile
jiangh277 b3f8aa6eb7
Some checks failed
test/timeline-server/pipeline/head There was a failure building this commit
build file
2025-12-24 16:05:59 +08:00

314 lines
10 KiB
Groovy
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
pipeline {
agent any
tools {
maven 'maven 3.9.12' // 修正Maven工具名称
jdk 'openjdk21' // 修正JDK工具名称使用Jenkins中实际配置的名称
}
environment {
REGISTRY = 'timeline-registry:5000'
PROJECT_NAME = 'timeline-server'
DOCKER_REGISTRY = 'timeline-registry:5000'
}
parameters {
choice(
name: 'DEPLOY_ENV',
choices: ['dev', 'staging', 'prod'],
description: '选择部署环境'
)
string(
name: 'BRANCH_NAME',
defaultValue: 'main',
description: '构建分支'
)
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
echo "当前分支: ${params.BRANCH_NAME}"
}
}
}
stage('Build') {
steps {
script {
echo '开始构建项目'
sh 'mvn clean compile -DskipTests'
}
}
}
stage('Test') {
steps {
script {
echo '运行单元测试'
sh 'mvn test'
}
}
post {
always {
script {
// 检查测试报告文件是否存在
def reportFiles = findFiles(glob: 'target/surefire-reports/TEST-*.xml')
if (reportFiles.length > 0) {
echo "找到 ${reportFiles.length} 个测试报告文件"
junit testResults: 'target/surefire-reports/TEST-*.xml'
} else {
echo "未找到测试报告文件跳过JUnit发布"
}
}
}
}
}
stage('Package') {
steps {
script {
echo '打包项目'
sh 'mvn package -DskipTests'
// 保存构建产物
archiveArtifacts artifacts: 'timeline-gateway-service/target/*.jar, timeline-user-service/target/*.jar, timeline-story-service/target/*.jar, timeline-file-service/target/*.jar', fingerprint: true
}
}
}
stage('Build Docker Images') {
steps {
script {
def services = ['gateway', 'user', 'story', 'file']
def imageTags = [:]
for (service in services) {
def serviceDir = "timeline-${service}-service"
def imageName = "${REGISTRY}/timeline-${service}-service:${BUILD_NUMBER}"
def latestImageName = "${REGISTRY}/timeline-${service}-service:latest"
// 检查Dockerfile是否存在如果不存在则创建
if (!fileExists("${serviceDir}/Dockerfile")) {
writeFile file: "${serviceDir}/Dockerfile", text: getDockerfileContent(serviceDir)
}
// 构建镜像
sh "docker build -t ${imageName} -t ${latestImageName} ${serviceDir}/."
imageTags[service] = imageName
}
env.IMAGE_TAGS = writeJSON returnText: imageTags
}
}
}
stage('Push Images') {
steps {
script {
def imageTags = readJSON text: env.IMAGE_TAGS
def services = ['gateway', 'user', 'story', 'file']
for (service in services) {
def imageName = imageTags[service]
sh "docker push ${imageName}"
// 也推送latest标签
def latestImageName = imageName.replace(BUILD_NUMBER, "latest")
sh "docker push ${latestImageName}"
}
}
}
}
stage('Deploy') {
steps {
script {
// 创建或更新docker-compose文件
def composeContent = getComposeFileContent(BUILD_NUMBER)
writeFile file: 'docker-compose.yml', text: composeContent
// 拉取最新镜像
sh 'docker-compose pull'
// 停止旧容器
sh 'docker-compose down || true'
// 启动新容器
sh 'docker-compose up -d'
echo "所有服务已部署完成"
}
}
}
}
post {
success {
script {
sh 'echo "构建和部署成功完成"'
// 发送成功通知
emailext (
subject: "构建成功: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "构建成功: ${env.BUILD_URL}",
to: "332515344@qq.com"
)
}
}
failure {
script {
sh 'echo "构建或部署失败"'
// 发送失败通知
emailext (
subject: "构建失败: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "构建失败: ${env.BUILD_URL}",
to: "332515344@qq.com"
)
}
}
always {
cleanWs()
}
}
}
// 生成Dockerfile内容的函数
def getDockerfileContent(serviceDir) {
return """FROM openjdk:21-jdk-slim
VOLUME /tmp
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
"""
}
// 生成docker-compose文件内容的函数
def getComposeFileContent(buildNumber) {
return """version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: timeline-mysql
ports:
- "33306:33306"
environment:
MYSQL_ROOT_PASSWORD: WoCloud@9ol7uj
MYSQL_DATABASE: timeline
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:7-alpine
container_name: timeline-redis
ports:
- "36379:6379"
command: redis-server --requirepass 123456
minio:
image: minio/minio:latest
container_name: timeline-minio
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: 9ttSGjvQxek2uKKlhpqI
MINIO_ROOT_PASSWORD: 12CaKew53tu94tgyDLoqAwAq32iDuz3SWW0O1hex
command: server /data --console-address ":9001"
volumes:
- minio_data:/data
timeline-story-service:
image: timeline-registry:5000/timeline-story-service:${buildNumber}
container_name: timeline-story-service
ports:
- "30001:30001"
environment:
- server.port=30001
- spring.datasource.url=jdbc:mysql://mysql:3306/timeline?serverTimezone=UTC&allowPublicKeyRetrieval=true
- spring.datasource.username=root
- spring.datasource.password=WoCloud@9ol7uj
- spring.data.redis.host=redis
- spring.data.redis.port=6379
- spring.data.redis.password=123456
- file.service.url=http://timeline-file-service:30002/file/
- user.service.url=http://timeline-user-service:30003/user/
depends_on:
- mysql
- redis
timeline-file-service:
image: timeline-registry:5000/timeline-file-service:${buildNumber}
container_name: timeline-file-service
ports:
- "30002:30002"
environment:
- server.port=30002
- spring.datasource.url=jdbc:mysql://mysql:3306/timeline?serverTimezone=UTC&allowPublicKeyRetrieval=true
- spring.datasource.username=root
- spring.datasource.password=WoCloud@9ol7uj
- minio.endpoint=http://minio:9000
- minio.accessKey=9ttSGjvQxek2uKKlhpqI
- minio.secretKey=12CaKew53tu94tgyDLoqAwAq32iDuz3SWW0O1hex
- minio.bucketName=timeline-test
depends_on:
- mysql
- minio
timeline-user-service:
image: timeline-registry:5000/timeline-user-service:${buildNumber}
container_name: timeline-user-service
ports:
- "30003:30003"
environment:
- server.port=30003
- spring.datasource.url=jdbc:mysql://mysql:3306/timeline?serverTimezone=UTC&allowPublicKeyRetrieval=true
- spring.datasource.username=root
- spring.datasource.password=WoCloud@9ol7uj
- spring.data.redis.host=redis
- spring.data.redis.port=6379
- spring.data.redis.password=123456
depends_on:
- mysql
- redis
timeline-gateway-service:
image: timeline-registry:5000/timeline-gateway-service:${buildNumber}
container_name: timeline-gateway-service
ports:
- "30000:30000"
environment:
- server.port=30000
- spring.cloud.gateway.routes[0].id=story-service
- spring.cloud.gateway.routes[0].uri=http://timeline-story-service:30001
- spring.cloud.gateway.routes[0].predicates[0]=Path=/story/**
- spring.cloud.gateway.routes[0].filters[0]=StripPrefix=0
- spring.cloud.gateway.routes[1].id=file-service
- spring.cloud.gateway.routes[1].uri=http://timeline-file-service:30002
- spring.cloud.gateway.routes[1].predicates[0]=Path=/file/**
- spring.cloud.gateway.routes[1].filters[0]=StripPrefix=0
- spring.cloud.gateway.routes[2].id=user-service
- spring.cloud.gateway.routes[2].uri=http://timeline-user-service:30003
- spring.cloud.gateway.routes[2].predicates[0]=Path=/user/**
- spring.cloud.gateway.routes[2].filters[0]=StripPrefix=0
- spring.cloud.gateway.routes[3].id=user-service-ws
- spring.cloud.gateway.routes[3].uri=http://timeline-user-service:30003
- spring.cloud.gateway.routes[3].predicates[0]=Path=/user/ws/**
- spring.cloud.gateway.routes[3].filters[0]=StripPrefix=0
- spring.datasource.url=jdbc:mysql://mysql:3306/timeline?serverTimezone=UTC&allowPublicKeyRetrieval=true
- spring.datasource.username=root
- spring.datasource.password=WoCloud@9ol7uj
depends_on:
- timeline-story-service
- timeline-file-service
- timeline-user-service
volumes:
mysql_data:
minio_data:
"""
}