feat: 添加 Jenkins CI/CD 配置和部署脚本
- 添加 Jenkinsfile 支持智能增量构建 - 添加 Docker 多阶段构建模板 - 添加 Docker Compose 配置(连接 1Panel 中间件) - 添加部署、回滚、清理脚本 - 添加环境变量配置模板
This commit is contained in:
282
Jenkinsfile
vendored
Normal file
282
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
// ============================================
|
||||
// AIOT Platform - Jenkins Pipeline
|
||||
// 智能增量构建 + Docker 容器化部署
|
||||
// ============================================
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
// 保留最近 10 次构建
|
||||
buildDiscarder(logRotator(numToKeepStr: '10'))
|
||||
// 禁止并发构建
|
||||
disableConcurrentBuilds()
|
||||
// 超时设置
|
||||
timeout(time: 60, unit: 'MINUTES')
|
||||
}
|
||||
|
||||
environment {
|
||||
// Gitea 仓库配置
|
||||
GIT_REPO = 'http://124.221.55.225:3000/XW-AIOT/aiot-platform-cloud.git'
|
||||
|
||||
// Docker Registry 配置
|
||||
REGISTRY = 'localhost:5000'
|
||||
|
||||
// Maven 配置
|
||||
MAVEN_OPTS = '-Xmx2048m -Dmaven.repo.local=.m2/repository'
|
||||
|
||||
// 镜像标签
|
||||
IMAGE_TAG = "${env.BRANCH_NAME}-${env.BUILD_NUMBER}-${env.GIT_COMMIT?.take(8)}"
|
||||
|
||||
// 服务列表(核心服务)
|
||||
CORE_SERVICES = 'viewsh-gateway,viewsh-module-system-server,viewsh-module-infra-server,viewsh-module-iot-server,viewsh-module-iot-gateway,viewsh-module-ops-server'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
script {
|
||||
echo "=== 检出代码 ==="
|
||||
checkout scm
|
||||
|
||||
// 获取 Git 提交信息
|
||||
env.GIT_COMMIT_MSG = sh(
|
||||
script: 'git log -1 --pretty=%B',
|
||||
returnStdout: true
|
||||
).trim()
|
||||
|
||||
echo "Commit: ${env.GIT_COMMIT}"
|
||||
echo "Message: ${env.GIT_COMMIT_MSG}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Detect Changes') {
|
||||
steps {
|
||||
script {
|
||||
echo "=== 检测变更的服务 ==="
|
||||
|
||||
// 获取变更的文件列表
|
||||
def changedFiles = sh(
|
||||
script: '''
|
||||
if [ "${GIT_PREVIOUS_COMMIT}" = "" ]; then
|
||||
# 首次构建,构建所有核心服务
|
||||
echo "all"
|
||||
else
|
||||
# 检测变更的文件
|
||||
git diff --name-only ${GIT_PREVIOUS_COMMIT} ${GIT_COMMIT}
|
||||
fi
|
||||
''',
|
||||
returnStdout: true
|
||||
).trim()
|
||||
|
||||
echo "Changed files:\n${changedFiles}"
|
||||
|
||||
// 分析需要构建的服务
|
||||
def servicesToBuild = []
|
||||
|
||||
if (changedFiles == 'all') {
|
||||
// 首次构建或强制全量构建
|
||||
servicesToBuild = CORE_SERVICES.split(',')
|
||||
} else {
|
||||
// 检测每个服务是否有变更
|
||||
CORE_SERVICES.split(',').each { service ->
|
||||
def modulePath = service.replace('-server', '').replace('viewsh-module-', 'viewsh-module-').replace('viewsh-', '')
|
||||
|
||||
if (changedFiles.contains(modulePath) ||
|
||||
changedFiles.contains('pom.xml') ||
|
||||
changedFiles.contains('viewsh-framework') ||
|
||||
changedFiles.contains('viewsh-dependencies')) {
|
||||
servicesToBuild.add(service)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有检测到变更,但有代码提交,构建所有服务
|
||||
if (servicesToBuild.isEmpty() && !changedFiles.isEmpty()) {
|
||||
servicesToBuild = CORE_SERVICES.split(',')
|
||||
}
|
||||
}
|
||||
|
||||
env.SERVICES_TO_BUILD = servicesToBuild.join(',')
|
||||
echo "Services to build: ${env.SERVICES_TO_BUILD}"
|
||||
|
||||
if (servicesToBuild.isEmpty()) {
|
||||
echo "No services need to be built. Skipping build."
|
||||
currentBuild.result = 'SUCCESS'
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Maven Build') {
|
||||
when {
|
||||
expression { env.SERVICES_TO_BUILD != '' }
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
echo "=== Maven 构建 ==="
|
||||
|
||||
def services = env.SERVICES_TO_BUILD.split(',')
|
||||
|
||||
// 并行构建(最多 3 个并行,避免内存溢出)
|
||||
def parallelBuilds = [:]
|
||||
def batchSize = 3
|
||||
|
||||
for (int i = 0; i < services.size(); i += batchSize) {
|
||||
def batch = services[i..Math.min(i + batchSize - 1, services.size() - 1)]
|
||||
|
||||
batch.each { service ->
|
||||
def modulePath = getModulePath(service)
|
||||
|
||||
parallelBuilds["Build ${service}"] = {
|
||||
stage("Build ${service}") {
|
||||
echo "Building ${service}..."
|
||||
sh """
|
||||
mvn clean package -pl ${modulePath} -am -DskipTests -B
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行当前批次
|
||||
parallel parallelBuilds
|
||||
parallelBuilds = [:]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Docker Build & Push') {
|
||||
when {
|
||||
expression { env.SERVICES_TO_BUILD != '' }
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
echo "=== Docker 镜像构建与推送 ==="
|
||||
|
||||
def services = env.SERVICES_TO_BUILD.split(',')
|
||||
def parallelBuilds = [:]
|
||||
|
||||
services.each { service ->
|
||||
parallelBuilds["Docker ${service}"] = {
|
||||
stage("Docker ${service}") {
|
||||
def modulePath = getModulePath(service)
|
||||
def jarName = service
|
||||
|
||||
echo "Building Docker image for ${service}..."
|
||||
|
||||
sh """
|
||||
docker build \
|
||||
-f docker/Dockerfile.template \
|
||||
--build-arg MODULE_NAME=${modulePath} \
|
||||
--build-arg JAR_NAME=${jarName} \
|
||||
--build-arg SKIP_TESTS=true \
|
||||
-t ${REGISTRY}/${service}:${IMAGE_TAG} \
|
||||
-t ${REGISTRY}/${service}:latest \
|
||||
.
|
||||
"""
|
||||
|
||||
echo "Pushing Docker image for ${service}..."
|
||||
sh """
|
||||
docker push ${REGISTRY}/${service}:${IMAGE_TAG}
|
||||
docker push ${REGISTRY}/${service}:latest
|
||||
"""
|
||||
|
||||
echo "Cleaning up old images for ${service}..."
|
||||
sh """
|
||||
docker images ${REGISTRY}/${service} --format '{{.ID}} {{.Tag}}' | \
|
||||
grep -v '${IMAGE_TAG}' | grep -v 'latest' | \
|
||||
awk '{print \$1}' | head -n -2 | xargs -r docker rmi -f || true
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 并行构建镜像(最多 3 个并行)
|
||||
def batchSize = 3
|
||||
for (int i = 0; i < services.size(); i += batchSize) {
|
||||
def batch = services[i..Math.min(i + batchSize - 1, services.size() - 1)]
|
||||
def batchBuilds = [:]
|
||||
|
||||
batch.each { service ->
|
||||
batchBuilds["Docker ${service}"] = parallelBuilds["Docker ${service}"]
|
||||
}
|
||||
|
||||
parallel batchBuilds
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy') {
|
||||
when {
|
||||
expression { env.SERVICES_TO_BUILD != '' && env.BRANCH_NAME == 'master' }
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
echo "=== 部署到生产环境 ==="
|
||||
|
||||
def services = env.SERVICES_TO_BUILD.split(',')
|
||||
|
||||
services.each { service ->
|
||||
echo "Deploying ${service}..."
|
||||
|
||||
sh """
|
||||
docker-compose -f docker-compose.core.yml pull ${service}
|
||||
docker-compose -f docker-compose.core.yml up -d ${service}
|
||||
"""
|
||||
|
||||
// 等待服务健康检查
|
||||
echo "Waiting for ${service} to be healthy..."
|
||||
sh """
|
||||
timeout 120 sh -c 'until docker inspect --format="{{.State.Health.Status}}" aiot-${service} 2>/dev/null | grep -q healthy; do sleep 5; done' || true
|
||||
"""
|
||||
}
|
||||
|
||||
echo "Deployment completed!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
echo "=== 构建成功 ==="
|
||||
echo "Built services: ${env.SERVICES_TO_BUILD}"
|
||||
echo "Image tag: ${IMAGE_TAG}"
|
||||
}
|
||||
|
||||
failure {
|
||||
echo "=== 构建失败 ==="
|
||||
echo "Please check the logs for details."
|
||||
}
|
||||
|
||||
always {
|
||||
// 清理工作空间(可选)
|
||||
// cleanWs()
|
||||
|
||||
// 显示磁盘使用情况
|
||||
sh 'df -h'
|
||||
sh 'docker system df'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 辅助函数
|
||||
// ============================================
|
||||
|
||||
def getModulePath(String service) {
|
||||
// 根据服务名获取 Maven 模块路径
|
||||
def moduleMap = [
|
||||
'viewsh-gateway': 'viewsh-gateway',
|
||||
'viewsh-module-system-server': 'viewsh-module-system/viewsh-module-system-server',
|
||||
'viewsh-module-infra-server': 'viewsh-module-infra/viewsh-module-infra-server',
|
||||
'viewsh-module-iot-server': 'viewsh-module-iot/viewsh-module-iot-server',
|
||||
'viewsh-module-iot-gateway': 'viewsh-module-iot/viewsh-module-iot-gateway',
|
||||
'viewsh-module-ops-server': 'viewsh-module-ops/viewsh-module-ops-server'
|
||||
]
|
||||
|
||||
return moduleMap[service] ?: service
|
||||
}
|
||||
Reference in New Issue
Block a user