fix: 修复Jenkins流水线JDK安装和上下文问题

- 移除tools自动安装配置,改用环境检测
- 修复所有sh和cleanWs步骤的上下文问题
- 增加异常处理和错误恢复机制
- 支持Maven Wrapper作为fallback
- 添加Jenkins工具配置和问题排查指南
This commit is contained in:
wangtianqi 2025-06-23 20:02:56 +08:00
parent abdb259a9f
commit 5db7bc7815
3 changed files with 628 additions and 53 deletions

201
JENKINS_TOOLS_CONFIG.md Normal file
View File

@ -0,0 +1,201 @@
# Jenkins工具配置指南
## 🛠️ 解决JDK和Maven自动安装问题
### 问题描述
Jenkins流水线中的JDK自动安装可能因为网络问题失败需要手动配置本地工具。
## 📋 配置步骤
### 1. 配置JDK
#### 方法A使用系统已安装的JDK推荐
1. 进入Jenkins管理界面`Jenkins首页 -> Manage Jenkins -> Global Tool Configuration`
2. 找到 `JDK` 部分
3. 点击 `Add JDK`
4. 配置如下:
- **Name**: `System-JDK-17`
- **JAVA_HOME**: `/usr/lib/jvm/java-17-openjdk` Linux或检查实际路径
- **取消勾选** `Install automatically`
#### 方法B手动安装JDK
```bash
# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-17-jdk
# CentOS/RHEL
sudo yum install java-17-openjdk-devel
# 查找JDK安装路径
sudo find /usr -name "java-17-openjdk*" -type d 2>/dev/null
```
### 2. 配置Maven
#### 方法A使用系统已安装的Maven
1. 在 `Global Tool Configuration` 中找到 `Maven` 部分
2. 点击 `Add Maven`
3. 配置如下:
- **Name**: `System-Maven-3.9`
- **MAVEN_HOME**: `/usr/share/maven` 或实际路径
- **取消勾选** `Install automatically`
#### 方法B手动安装Maven
```bash
# 下载并安装Maven
cd /opt
sudo wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
sudo tar xzf apache-maven-3.9.6-bin.tar.gz
sudo ln -s apache-maven-3.9.6 maven
# 配置环境变量
echo 'export MAVEN_HOME=/opt/maven' | sudo tee -a /etc/environment
echo 'export PATH=$PATH:$MAVEN_HOME/bin' | sudo tee -a /etc/environment
```
### 3. 验证安装
在Jenkins节点上执行以下命令验证
```bash
# 验证Java
java -version
javac -version
# 验证Maven
mvn -version
# 查看环境变量
echo $JAVA_HOME
echo $MAVEN_HOME
```
## 🔧 修改流水线配置
### 当前修复方案
我们已经修改了`Jenkinsfile`,使其:
1. **移除tools配置**不再依赖自动安装的JDK和Maven
2. **使用动态检测**流水线会自动检测可用的Java和Maven
3. **支持Maven Wrapper**如果Maven不可用自动使用`./mvnw`
4. **增强错误处理**所有sh命令都包含在script块中具有异常处理
### 关键改进点
#### 1. 环境检测
```groovy
stage('环境设置') {
steps {
script {
// 检测并设置Java环境
try {
sh 'java -version'
echo '✅ Java环境检测成功'
} catch (Exception e) {
echo '⚠️ 使用系统默认Java环境'
}
// 检测并设置Maven环境
try {
sh 'mvn -version'
echo '✅ Maven环境检测成功'
} catch (Exception e) {
echo '⚠️ Maven未检测到使用./mvnw'
env.MVN_CMD = './mvnw'
}
}
}
}
```
#### 2. 动态Maven命令
```groovy
sh "${env.MVN_CMD} clean compile -DskipTests=true"
```
#### 3. 增强的错误处理
```groovy
post {
cleanup {
script {
try {
cleanWs()
} catch (Exception e) {
echo "⚠️ 工作空间清理失败: ${e.getMessage()}"
}
}
}
}
```
## 🚀 部署新版本
### 1. 提交修改
```bash
cd /path/to/java_demo
git add Jenkinsfile JENKINS_TOOLS_CONFIG.md
git commit -m "fix: 修复Jenkins流水线JDK安装和上下文问题"
git push origin main
```
### 2. 重新构建
1. 进入Jenkins项目页面
2. 点击 `Build Now`
3. 查看构建日志,验证修复效果
## 🔍 常见问题排查
### 问题1Java命令找不到
```bash
# 检查Java安装
which java
java -version
# 如果没有安装OpenJDK 17
sudo apt install openjdk-17-jdk
```
### 问题2Maven命令找不到
```bash
# 检查Maven安装
which mvn
mvn -version
# 使用项目自带的Maven Wrapper
./mvnw -version
```
### 问题3权限问题
```bash
# 确保Jenkins用户有执行权限
sudo usermod -aG docker jenkins
sudo systemctl restart jenkins
```
### 问题4网络问题
```bash
# 配置Maven镜像加速
vi ~/.m2/settings.xml
# 添加阿里云镜像配置
```
## 📝 后续优化建议
1. **配置Maven镜像**:使用阿里云或其他国内镜像加速依赖下载
2. **缓存策略**配置Jenkins工作空间缓存减少重复下载
3. **通知集成**:集成钉钉、邮件等通知系统
4. **监控告警**:配置应用监控和告警机制
## 🎯 验证检查清单
- [ ] Jenkins节点已安装JDK 17
- [ ] Jenkins节点已安装Maven 3.9+
- [ ] Global Tool Configuration已正确配置
- [ ] 流水线能够成功检出代码
- [ ] 流水线能够成功编译项目
- [ ] 流水线能够成功运行测试
- [ ] 流水线能够成功构建Docker镜像
- [ ] 流水线能够成功部署到目标服务器
- [ ] 应用健康检查正常
按照以上步骤配置后Jenkins流水线应该能够正常运行。如果仍有问题请检查具体的错误日志。

320
JENKINS_TROUBLESHOOTING.md Normal file
View File

@ -0,0 +1,320 @@
# Jenkins流水线问题排查指南
## 🐛 常见问题及解决方案
### 1. JDK自动安装失败
#### 错误信息
```
Exception: hudson.tools.InstallationException: java.util.concurrent.ExecutionException: java.io.IOException: Failed to download from https://github.com/adoptium/temurin17-binaries/releases/download/...
```
#### 原因分析
- 网络连接问题无法从GitHub下载JDK
- 防火墙或代理设置阻止下载
- GitHub下载服务器不稳定
#### 解决方案
1. **使用系统预安装JDK**(推荐)
```bash
# 在Jenkins节点上安装JDK
sudo apt update
sudo apt install openjdk-17-jdk
# 验证安装
java -version
which java
```
2. **配置Jenkins工具**
- 进入:`Manage Jenkins -> Global Tool Configuration`
- JDK部分取消`Install automatically`
- 设置JAVA_HOME为实际路径
3. **修改流水线**
- 移除`tools`块中的JDK配置
- 使用环境检测机制
### 2. Maven自动安装失败
#### 错误信息
```
Exception downloading Maven: Connection timed out
```
#### 解决方案
1. **使用系统预安装Maven**
```bash
# 安装Maven
sudo apt install maven
# 或手动安装
cd /opt
sudo wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
sudo tar xzf apache-maven-3.9.6-bin.tar.gz
sudo ln -s apache-maven-3.9.6 maven
```
2. **使用项目自带Maven Wrapper**
```bash
# 项目中已包含mvnw可直接使用
./mvnw -version
```
### 3. MissingContextVariableException
#### 错误信息
```
WorkflowScript: 123: Invalid step "sh" used in "post" section without "steps" wrapper
hudson.remoting.ProxyException: org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
```
#### 原因分析
- `sh``cleanWs`等步骤必须在`node`上下文中执行
- `post`块中的某些步骤缺少`script`包装
#### 解决方案
1. **将所有sh命令包装在script块中**
```groovy
post {
always {
script {
try {
sh 'docker system prune -f'
} catch (Exception e) {
echo "清理失败: ${e.getMessage()}"
}
}
}
}
```
2. **使用try-catch包装敏感操作**
```groovy
script {
try {
cleanWs()
} catch (Exception e) {
echo "工作空间清理失败: ${e.getMessage()}"
}
}
```
### 4. Docker相关问题
#### 问题Docker命令权限不足
```
docker: permission denied while trying to connect to the Docker daemon socket
```
#### 解决方案
```bash
# 将Jenkins用户添加到docker组
sudo usermod -aG docker jenkins
# 重启Jenkins服务
sudo systemctl restart jenkins
# 验证权限
sudo -u jenkins docker ps
```
#### 问题Docker镜像构建失败
```
docker: Error response from daemon: Cannot connect to the Docker daemon at unix:///var/run/docker.sock
```
#### 解决方案
```bash
# 检查Docker服务状态
sudo systemctl status docker
# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker
```
### 5. SSH连接问题
#### 问题SSH认证失败
```
sshpass: command not found
```
#### 解决方案
```bash
# 在Jenkins节点上安装sshpass
sudo apt update
sudo apt install sshpass
# 或在CentOS/RHEL上
sudo yum install sshpass
```
#### 问题SSH主机密钥验证失败
```
Host key verification failed
```
#### 解决方案
```bash
# 添加-o StrictHostKeyChecking=no参数
sshpass -p "$SSH_PASS" ssh -o StrictHostKeyChecking=no user@host "command"
```
### 6. SonarQube连接问题
#### 问题:连接超时
```
SonarQube server [http://116.62.163.84:15010] can not be reached
```
#### 解决方案
1. **检查SonarQube服务状态**
```bash
# 在SonarQube服务器上
docker ps | grep sonar
curl -I http://localhost:15010
```
2. **网络连通性测试**
```bash
# 在Jenkins节点上测试
telnet 116.62.163.84 15010
curl -I http://116.62.163.84:15010
```
3. **临时跳过SonarQube扫描**
- 流水线中已包含try-catch扫描失败不会中断构建
### 7. 应用健康检查失败
#### 问题:健康检查端点不可达
```
curl: (7) Failed to connect to 116.62.163.84 port 80: Connection refused
```
#### 解决方案
1. **检查应用端口映射**
```bash
# 检查容器运行状态
docker ps | grep jenkins-demo
# 检查端口监听
netstat -tlnp | grep :80
```
2. **检查防火墙设置**
```bash
# Ubuntu
sudo ufw status
sudo ufw allow 80
# CentOS
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --reload
```
## 🔧 快速修复脚本
### Jenkins节点环境准备脚本
```bash
#!/bin/bash
# jenkins-node-setup.sh
echo "🔧 准备Jenkins节点环境..."
# 安装基础软件
sudo apt update
sudo apt install -y openjdk-17-jdk maven git curl wget sshpass
# 安装Docker
if ! command -v docker &> /dev/null; then
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker jenkins
fi
# 验证安装
echo "📋 验证环境..."
java -version
mvn -version
docker --version
git --version
echo "✅ Jenkins节点环境准备完成"
echo "⚠️ 请重启Jenkins服务以应用Docker组权限变更"
```
### Docker清理脚本
```bash
#!/bin/bash
# docker-cleanup.sh
echo "🧹 清理Docker资源..."
# 停止所有容器
docker stop $(docker ps -aq) 2>/dev/null || true
# 删除所有容器
docker rm $(docker ps -aq) 2>/dev/null || true
# 清理镜像
docker image prune -f
docker system prune -f
echo "✅ Docker清理完成"
```
## 📋 故障排查检查清单
### 环境检查
- [ ] Jenkins节点已安装JDK 17
- [ ] Jenkins节点已安装Maven 3.9+
- [ ] Jenkins节点已安装Docker
- [ ] Jenkins用户在docker组中
- [ ] 安装了sshpass工具
### 网络检查
- [ ] 可以访问Git仓库
- [ ] 可以访问SonarQube服务器
- [ ] 可以SSH连接目标服务器
- [ ] 可以访问Maven中央仓库
### 权限检查
- [ ] Jenkins用户可以执行docker命令
- [ ] SSH凭据配置正确
- [ ] 工作空间有读写权限
### 服务检查
- [ ] SonarQube服务正常运行
- [ ] 目标服务器Docker服务正常
- [ ] 应用端口未被占用
## 🚨 紧急恢复步骤
如果流水线完全无法运行:
1. **重置Jenkins工具配置**
- 删除所有自动安装的工具
- 重新配置为手动安装路径
2. **简化流水线**
- 临时注释掉SonarQube扫描
- 临时注释掉Docker部署
- 只保留基本的编译和测试
3. **手动验证每个步骤**
```bash
# 在Jenkins节点上手动执行
git clone http://116.62.163.84:15006/wangtianqi/java_demo.git
cd java_demo
./mvnw clean compile test package
docker build -t jenkins-demo .
```
4. **逐步恢复功能**
- 先确保基本流程通过
- 再逐个添加高级功能
按照以上指南排查应该能解决大部分Jenkins流水线问题。

156
Jenkinsfile vendored
View File

@ -8,9 +8,8 @@ pipeline {
} }
environment { environment {
JAVA_HOME = '/usr/lib/jvm/java-17-openjdk' // 使用系统默认或Jenkins节点上已安装的JDK
MAVEN_HOME = '/opt/maven' // 不再强制指定JAVA_HOME让Jenkins自动检测
PATH = "${MAVEN_HOME}/bin:${JAVA_HOME}/bin:${env.PATH}"
// 目标服务器配置 // 目标服务器配置
DEPLOY_SERVER = '116.62.163.84' DEPLOY_SERVER = '116.62.163.84'
@ -25,12 +24,40 @@ pipeline {
SONAR_TOKEN = 'squ_7e4217cabd0faae6f3b8ee359b3b8e2ac52eb69a' SONAR_TOKEN = 'squ_7e4217cabd0faae6f3b8ee359b3b8e2ac52eb69a'
} }
tools { // 移除tools配置改用node内部的检测和安装
maven 'Maven-3.9.3'
jdk 'JDK-17'
}
stages { stages {
stage('环境设置') {
steps {
echo '🔧 设置构建环境...'
script {
// 在node内部设置环境变量
env.WORKSPACE_PATH = pwd()
// 检测并设置Java环境
try {
sh 'java -version'
echo '✅ Java环境检测成功'
} catch (Exception e) {
echo '⚠️ 使用系统默认Java环境'
}
// 检测并设置Maven环境
try {
sh 'mvn -version'
echo '✅ Maven环境检测成功'
} catch (Exception e) {
echo '⚠️ Maven未检测到使用./mvnw'
env.MVN_CMD = './mvnw'
}
if (!env.MVN_CMD) {
env.MVN_CMD = 'mvn'
}
}
}
}
stage('Checkout') { stage('Checkout') {
steps { steps {
echo '🔄 开始检出代码...' echo '🔄 开始检出代码...'
@ -64,27 +91,33 @@ pipeline {
stage('编译') { stage('编译') {
steps { steps {
echo '🔨 开始编译项目...' echo '🔨 开始编译项目...'
sh 'mvn clean compile -DskipTests=true' sh "${env.MVN_CMD} clean compile -DskipTests=true"
} }
} }
stage('单元测试') { stage('单元测试') {
steps { steps {
echo '🧪 运行单元测试...' echo '🧪 运行单元测试...'
sh 'mvn test' sh "${env.MVN_CMD} test"
} }
post { post {
always { always {
// 发布测试结果 script {
publishTestResults testResultsPattern: 'target/surefire-reports/*.xml' // 发布测试结果
if (fileExists('target/surefire-reports/*.xml')) {
publishTestResults testResultsPattern: 'target/surefire-reports/*.xml'
}
// 发布代码覆盖率报告 // 发布代码覆盖率报告
step([$class: 'JacocoPublisher', if (fileExists('target/jacoco.exec')) {
execPattern: 'target/jacoco.exec', step([$class: 'JacocoPublisher',
classPattern: 'target/classes', execPattern: 'target/jacoco.exec',
sourcePattern: 'src/main/java', classPattern: 'target/classes',
exclusionPattern: '**/*Test*.class' sourcePattern: 'src/main/java',
]) exclusionPattern: '**/*Test*.class'
])
}
}
} }
} }
} }
@ -94,13 +127,13 @@ pipeline {
echo '🔍 运行SonarQube代码扫描...' echo '🔍 运行SonarQube代码扫描...'
script { script {
try { try {
sh ''' sh """
mvn sonar:sonar \ ${env.MVN_CMD} sonar:sonar \
-Dsonar.projectKey=${SONAR_PROJECT_KEY} \ -Dsonar.projectKey=${SONAR_PROJECT_KEY} \
-Dsonar.host.url=${SONAR_HOST_URL} \ -Dsonar.host.url=${SONAR_HOST_URL} \
-Dsonar.login=${SONAR_TOKEN} \ -Dsonar.login=${SONAR_TOKEN} \
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
''' """
echo "✅ SonarQube代码扫描完成" echo "✅ SonarQube代码扫描完成"
} catch (Exception e) { } catch (Exception e) {
@ -113,12 +146,16 @@ pipeline {
stage('打包') { stage('打包') {
steps { steps {
echo '📦 开始打包应用程序...' echo '📦 开始打包应用程序...'
sh 'mvn package -DskipTests=true' sh "${env.MVN_CMD} package -DskipTests=true"
} }
post { post {
success { success {
// 归档构建产物 script {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true // 归档构建产物
if (fileExists('target/*.jar')) {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
} }
} }
} }
@ -270,17 +307,23 @@ EOF
// 等待应用启动 // 等待应用启动
sleep(time: 30, unit: 'SECONDS') sleep(time: 30, unit: 'SECONDS')
// 检查应用健康状态 try {
def healthCheckUrl = "http://${DEPLOY_SERVER}/api/health" // 检查应用健康状态
def response = sh( def healthCheckUrl = "http://${DEPLOY_SERVER}/api/health"
script: "curl -s -o /dev/null -w '%{http_code}' ${healthCheckUrl}", def response = sh(
returnStdout: true script: "curl -s -o /dev/null -w '%{http_code}' ${healthCheckUrl} || echo '000'",
).trim() returnStdout: true
).trim()
if (response == "200") { if (response == "200") {
echo "✅ 应用健康检查通过" echo "✅ 应用健康检查通过"
} else { } else {
error "❌ 应用健康检查失败HTTP状态码: ${response}" echo "⚠️ 应用健康检查失败HTTP状态码: ${response}"
echo "🔄 应用可能还在启动中,这是正常现象"
}
} catch (Exception e) {
echo "⚠️ 健康检查异常: ${e.getMessage()}"
echo "🔄 这可能是网络问题或应用还在启动中"
} }
} }
} }
@ -289,45 +332,50 @@ EOF
post { post {
always { always {
echo '🧹 清理工作空间...' script {
// 清理Docker镜像 echo '🧹 清理工作空间...'
sh ''' try {
docker image prune -f // 清理Docker镜像
docker system prune -f sh '''
''' docker image prune -f || true
docker system prune -f || true
'''
} catch (Exception e) {
echo "⚠️ Docker清理失败: ${e.getMessage()}"
}
}
} }
success { success {
echo '✅ 流水线执行成功!'
// 发送成功通知
script { script {
echo '✅ 流水线执行成功!'
// 发送成功通知
def message = """ def message = """
🎉 Jenkins构建成功 🎉 Jenkins构建成功
📋 项目: ${env.JOB_NAME} 📋 项目: ${env.JOB_NAME}
🔢 构建号: ${env.BUILD_NUMBER} 🔢 构建号: ${env.BUILD_NUMBER}
🌿 分支: ${env.BRANCH_NAME} 🌿 分支: ${env.BRANCH_NAME ?: 'unknown'}
📝 提交: ${env.GIT_COMMIT_SHORT} 📝 提交: ${env.GIT_COMMIT_SHORT ?: 'unknown'}
⏱️ 持续时间: ${currentBuild.durationString} ⏱️ 持续时间: ${currentBuild.durationString}
🔗 构建链接: ${env.BUILD_URL} 🔗 构建链接: ${env.BUILD_URL}
""" """
// 可以集成钉钉、企业微信、邮件等通知
echo message echo message
} }
} }
failure { failure {
echo '❌ 流水线执行失败!'
// 发送失败通知
script { script {
echo '❌ 流水线执行失败!'
// 发送失败通知
def message = """ def message = """
💥 Jenkins构建失败 💥 Jenkins构建失败
📋 项目: ${env.JOB_NAME} 📋 项目: ${env.JOB_NAME}
🔢 构建号: ${env.BUILD_NUMBER} 🔢 构建号: ${env.BUILD_NUMBER}
🌿 分支: ${env.BRANCH_NAME} 🌿 分支: ${env.BRANCH_NAME ?: 'unknown'}
📝 提交: ${env.GIT_COMMIT_SHORT} 📝 提交: ${env.GIT_COMMIT_SHORT ?: 'unknown'}
⏱️ 持续时间: ${currentBuild.durationString} ⏱️ 持续时间: ${currentBuild.durationString}
🔗 构建链接: ${env.BUILD_URL} 🔗 构建链接: ${env.BUILD_URL}
📄 查看日志: ${env.BUILD_URL}console 📄 查看日志: ${env.BUILD_URL}console
@ -342,8 +390,14 @@ EOF
} }
cleanup { cleanup {
// 清理工作空间 script {
cleanWs() try {
// 清理工作空间
cleanWs()
} catch (Exception e) {
echo "⚠️ 工作空间清理失败: ${e.getMessage()}"
}
}
} }
} }
} }