Files
aiot-platform-cloud/Jenkinsfile
lzh beabec5fb3
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
fix: 修正宿主机 SSH 地址为 172.19.0.1
- Jenkins 容器在 1panel-network 网络中
- 网关地址是 172.19.0.1 而不是 172.17.0.1
- Jenkins 负责指挥,实际部署在宿主机执行
2026-01-13 15:13:49 +08:00

251 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.

// ============================================
// 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://172.17.16.14: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)}"
// 服务列表(核心服务 - 不包括开发中的 ops-server
CORE_SERVICES = 'viewsh-gateway,viewsh-module-system-server,viewsh-module-infra-server,viewsh-module-iot-server,viewsh-module-iot-gateway'
}
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: '''
# 获取上一次成功构建的提交
PREV_COMMIT=$(git rev-parse HEAD~1 2>/dev/null || echo "")
if [ -z "$PREV_COMMIT" ]; then
# 首次构建或只有一个提交,构建所有核心服务
echo "all"
else
# 检测变更的文件
git diff --name-only $PREV_COMMIT HEAD
fi
''',
returnStdout: true
).trim()
echo "Changed files:\n${changedFiles}"
// 分析需要构建的服务
def servicesToBuild = []
if (changedFiles == 'all' || changedFiles.isEmpty()) {
// 首次构建或强制全量构建
echo "首次构建或无法检测变更,构建所有核心服务"
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') ||
changedFiles.contains('Jenkinsfile') ||
changedFiles.contains('docker/')) {
servicesToBuild.add(service)
}
}
// 如果没有检测到变更,但有代码提交,构建所有服务
if (servicesToBuild.isEmpty() && !changedFiles.isEmpty()) {
echo "检测到代码变更但未匹配到具体服务,构建所有服务"
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'
error("No changes detected, skipping build")
}
}
}
}
stage('Docker Build & Push') {
when {
expression { env.SERVICES_TO_BUILD != '' }
}
steps {
script {
echo "=== Docker 镜像构建与推送 ==="
echo "使用 Docker 多阶段构建(包含 Maven 编译)"
def services = env.SERVICES_TO_BUILD.split(',')
// 串行构建,避免内存溢出
services.each { service ->
def modulePath = getModulePath(service)
def jarName = service
echo "========================================="
echo "构建服务: ${service}"
echo "模块路径: ${modulePath}"
echo "========================================="
try {
// Docker 多阶段构建(包含 Maven 编译和镜像打包)
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 "推送镜像: ${service}"
sh """
docker push ${REGISTRY}/${service}:${IMAGE_TAG}
docker push ${REGISTRY}/${service}:latest
"""
echo "✓ ${service} 构建成功"
} catch (Exception e) {
echo "✗ ${service} 构建失败: ${e.message}"
throw e
}
}
// 清理悬空镜像
echo "清理悬空镜像..."
sh "docker image prune -f || true"
}
}
}
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}..."
// 通过 SSH 在宿主机上执行部署命令
// Jenkins 容器网络: 1panel-network, Gateway: 172.19.0.1
sh """
ssh -o StrictHostKeyChecking=no root@172.19.0.1 '
cd /opt/aiot-platform-cloud
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 """
ssh -o StrictHostKeyChecking=no root@172.19.0.1 '
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 暂未合并到 master待开发完成后添加
]
return moduleMap[service] ?: service
}