跳到主要内容

故障排查指南

本章提供 Jenkins 常见问题的诊断和解决方案,帮助你快速定位和解决问题。

日志分析

日志位置

Jenkins 日志是诊断问题的主要工具。

系统日志位置

安装方式日志路径
包管理器安装/var/log/jenkins/jenkins.log
Docker容器标准输出
WAR 文件控制台输出

查看日志命令

# systemd 服务日志
sudo journalctl -u jenkins -f

# 日志文件
sudo tail -f /var/log/jenkins/jenkins.log

# Docker 容器日志
docker logs -f jenkins

# 查看最近 100 行
sudo journalctl -u jenkins -n 100

Jenkins 系统日志

通过 Web 界面查看系统日志:

  1. 导航到 Manage Jenkins → System Log
  2. 点击 All Jenkins Logs 查看完整日志
  3. 可以添加自定义日志记录器,按组件过滤日志

添加日志记录器

  1. 点击 Add new log recorder
  2. 输入名称
  3. 添加要监控的日志级别:
    • hudson.model.Run - 构建执行日志
    • hudson.slaves.SlaveComputer - Agent 连接日志
    • org.jenkinsci.plugins.workflow - Pipeline 日志
    • jenkins.model.Jenkins - Jenkins 核心日志

日志级别

Manage Jenkins → System Log → Log Levels 中可以调整日志级别:

// 通过 Script Console 临时调整日志级别
import java.util.logging.Level
import java.util.logging.Logger

// 设置特定类的日志级别
Logger.getLogger("hudson.model.Run").setLevel(Level.FINE)
Logger.getLogger("org.jenkinsci.plugins.workflow").setLevel(Level.FINER)

启动问题

Jenkins 无法启动

症状:Jenkins 服务启动失败或立即退出

诊断步骤

# 检查服务状态
sudo systemctl status jenkins

# 查看详细日志
sudo journalctl -u jenkins -xe

# 检查端口占用
sudo netstat -tulpn | grep 8080

# 检查 Java 版本
java -version

常见原因和解决方案

1. Java 版本不兼容

错误信息: Unsupported class file major version 65
原因: Jenkins 版本与 Java 版本不兼容

解决方案:根据 Jenkins 版本安装正确的 Java 版本。

Jenkins 版本支持的 Java 版本
2.479.1 LTS 及以后Java 17 或 Java 21
2.426.1 - 2.479Java 11、17 或 21
2.361.1 - 2.426Java 11 或 17

2. 端口被占用

# 查找占用端口的进程
sudo lsof -i :8080

# 终止进程或修改 Jenkins 端口
sudo nano /etc/default/jenkins
# 修改 HTTP_PORT=8081

3. 权限问题

# 检查 Jenkins 主目录权限
ls -la /var/lib/jenkins

# 修复权限
sudo chown -R jenkins:jenkins /var/lib/jenkins
sudo chmod -R 755 /var/lib/jenkins

4. 内存不足

# 检查内存使用
free -h

# 调整 JVM 堆内存
sudo nano /etc/default/jenkins
# 修改 JAVA_OPTS="-Xmx2048m -Xms512m"

Jenkins 启动缓慢

症状:Jenkins 启动时间过长

可能原因

  1. 插件过多
  2. 任务配置过多
  3. 磁盘 I/O 性能差
  4. JVM 内存不足

解决方案

# 1. 检查插件数量
ls /var/lib/jenkins/plugins | wc -l

# 2. 禁用不需要的插件(谨慎操作)
# 在 Manage Jenkins → Plugins → Installed 中禁用

# 3. 增加启动超时时间
sudo nano /etc/default/jenkins
# 添加 JAVA_OPTS="-Djenkins.model.Jenkins.loadTimeout=600"

# 4. 使用 SSD 或优化磁盘 I/O

连接问题

Agent 无法连接

症状:Agent 显示离线状态

诊断步骤

# 在 Agent 机器上测试连接
telnet jenkins.example.com 8080
curl -I http://jenkins.example.com:8080

# 检查 Jenkins 日志
grep -i "agent\|slave" /var/log/jenkins/jenkins.log

# 检查 Agent 日志
# Agent 日志通常在 Agent 的工作目录下

常见原因和解决方案

1. 防火墙阻止连接

# 检查防火墙状态
sudo ufw status
sudo firewall-cmd --list-all

# 开放必要端口
sudo ufw allow 8080/tcp
sudo ufw allow 50000/tcp

2. 网络不通

# 检查网络连通性
ping jenkins.example.com
traceroute jenkins.example.com

# 检查 DNS 解析
nslookup jenkins.example.com

3. 协议不匹配

Manage Jenkins → System → Agent protocols 中检查启用的协议:

  • 推荐:JNLP4-connect
  • 不推荐:JNLP-connect(已弃用)

4. Agent JAR 版本不兼容

# 重新下载最新的 agent.jar
curl -o agent.jar http://jenkins.example.com:8080/jnlpJars/agent.jar

# 重新启动 Agent
java -jar agent.jar -url http://jenkins.example.com:8080 \
-secret <secret-key> \
-name <agent-name>

WebSocket 连接问题

症状:WebSocket 模式下 Agent 连接不稳定

解决方案

  1. 检查反向代理配置(需要支持 WebSocket):
# Nginx 配置
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
  1. 如果不支持 WebSocket,切换到 TCP 模式:

在 Agent 配置中,将 Launch method 改为 "Launch agents via SSH"。

构建问题

构建卡住不动

症状:构建一直处于执行状态,无法完成

诊断步骤

  1. 检查执行器状态:Manage Jenkins → Nodes
  2. 检查构建队列:Jenkins 首页的 "Build Queue"
  3. 查看构建日志是否有输出

常见原因和解决方案

1. 等待用户输入

检查是否有 input 步骤等待审批:

// 检查 Pipeline 中是否有未完成的 input
stage('Approval') {
steps {
input message: 'Continue?'
}
}

2. 死锁或无限循环

添加超时保护:

pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS')
}
stages {
stage('Build') {
steps {
timeout(time: 30, unit: 'MINUTES') {
sh 'mvn clean package'
}
}
}
}
}

3. Agent 资源不足

# 检查 Agent 资源使用
ssh agent-server 'top -bn1 | head -20'
ssh agent-server 'df -h'

# 检查是否有僵尸进程
ssh agent-server 'ps aux | grep defunct'

中止卡住的构建

// 通过 Script Console 中止所有正在运行的构建
Jenkins.instance.getAllItems(Job.class).each { job ->
job.builds.each { build ->
if (build.isInProgress()) {
println "Aborting: ${job.name} #${build.number}"
build.doStop()
}
}
}

构建失败但没有明确错误

症状:构建失败,但日志中没有明确的错误信息

诊断方法

1. 启用详细日志

pipeline {
agent any

stages {
stage('Build') {
steps {
sh '''
# 启用 shell 调试模式
set -x
mvn clean package
'''
}
}
}
}

2. 检查退出码

stage('Build') {
steps {
script {
def result = sh(script: 'mvn clean package', returnStatus: true)
echo "Exit code: ${result}"
if (result != 0) {
error "Build failed with exit code ${result}"
}
}
}
}

3. 捕获错误详情

stage('Build') {
steps {
script {
try {
sh 'mvn clean package'
} catch (Exception e) {
echo "Error: ${e.getMessage()}"
echo "Stack trace: ${e.getStackTrace()}"
throw e
}
}
}
}

Git 克隆失败

症状:无法从 Git 仓库拉取代码

常见错误和解决方案

1. 认证失败

错误: Authentication failed

解决方案:

// 使用正确的凭据
git credentialsId: 'github-credentials',
url: 'https://github.com/example/repo.git'

// 或使用 SSH
git url: '[email protected]:example/repo.git'

2. SSL 证书问题

错误: SSL certificate problem

解决方案:

// 临时禁用 SSL 验证(不推荐生产环境)
checkout scm: [
$class: 'GitSCM',
userRemoteConfigs: [[
url: 'https://github.com/example/repo.git',
credentialsId: 'github-credentials'
]],
extensions: [
[$class: 'CloneOption', noTags: false, shallow: false, depth: 0, reference: '', timeout: 10,
$class: 'DisableGitRemoteRequireSSLVerify']
]
]

3. 超时

错误: Git timeout

解决方案:

checkout scm: [
$class: 'GitSCM',
userRemoteConfigs: [[
url: 'https://github.com/example/repo.git',
credentialsId: 'github-credentials',
timeout: 30 // 增加超时时间
]]
]

内存溢出 (OOM)

症状:构建过程中 JVM 崩溃

错误信息

java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: PermGen space

解决方案

1. Agent 内存配置

# 在 Agent 启动参数中增加内存
java -Xmx4g -Xms1g -jar agent.jar ...

2. Maven/Gradle 内存

stage('Build') {
environment {
MAVEN_OPTS = '-Xmx2048m -Xms512m'
}
steps {
sh 'mvn clean package'
}
}

3. Docker 容器内存

agent {
docker {
image 'maven:3.9-eclipse-temurin-21'
args '-e MAVEN_OPTS="-Xmx2048m" --memory=4g'
}
}

性能问题

Jenkins 响应缓慢

症状:Web 界面加载慢,操作响应迟钝

诊断步骤

# 检查系统资源
top
vmstat 1
iostat -x 1

# 检查 JVM 状态
jstat -gcutil <pid> 1000

# 检查磁盘使用
df -h
du -sh /var/lib/jenkins/*

常见原因和解决方案

1. 磁盘空间不足

# 检查磁盘使用
df -h /var/lib/jenkins

# 清理旧构建
# 在 Pipeline 中配置构建丢弃策略
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
}

# 清理工作空间
du -sh /var/lib/jenkins/workspace/* | sort -hr | head -10
rm -rf /var/lib/jenkins/workspace/old-project-*

2. JVM 堆内存不足

# 检查当前 JVM 配置
ps aux | grep jenkins

# 增加堆内存
sudo nano /etc/default/jenkins
JAVA_OPTS="-Xmx4g -Xms2g"

3. 构建历史过多

# 查看构建数量
find /var/lib/jenkins/jobs -name "builds" -exec sh -c 'echo "{}: $(ls "{}" | wc -l)"' \;

# 通过脚本清理
Jenkins.instance.getAllItems(Job.class).each { job ->
job.builds.each { build ->
if (build.number < job.nextBuildNumber - 10) {
build.delete()
}
}
}

4. 插件过多或冲突

# 列出已安装插件
ls /var/lib/jenkins/plugins

# 在安全模式下启动(禁用所有插件)
java -jar jenkins.war --httpPort=8080 --argumentsRealm.passwd.admin=admin --argumentsRealm.roles.admin=admin --disablePlugins

构建执行缓慢

症状:构建执行时间明显变长

诊断方法

// 添加时间戳分析每个阶段
pipeline {
agent any
options {
timestamps()
}
stages {
stage('Stage 1') {
steps {
echo "Starting at ${new Date()}"
// 执行操作
echo "Finished at ${new Date()}"
}
}
}
}

优化建议

1. 并行执行

stage('Test') {
parallel {
stage('Unit Tests') {
steps { sh 'mvn test' }
}
stage('Integration Tests') {
steps { sh 'mvn verify -Pintegration-test' }
}
}
}

2. 增量构建

stage('Build') {
steps {
// Maven 增量构建
sh 'mvn compile -Dmaven.compiler.useIncrementalCompilation=true'
}
}

3. 缓存依赖

agent {
docker {
image 'maven:3.9-eclipse-temurin-21'
args '-v $HOME/.m2:/root/.m2' // 持久化 Maven 仓库
}
}

Pipeline 问题

NotSerializableException

症状:Pipeline 执行时抛出序列化异常

错误信息

java.io.NotSerializableException: java.util.regex.Matcher

原因:Pipeline 需要序列化状态以支持重启恢复,但某些 Groovy 对象不可序列化。

解决方案

// 错误:将不可序列化对象赋值给变量
script {
def matcher = "hello world" =~ /hello/
sleep(time: 10, unit: 'SECONDS') // 序列化点
echo "${matcher.find()}"
}

// 解决方案 1:立即使用结果
script {
def result = ("hello world" =~ /hello/).find()
sleep(time: 10, unit: 'SECONDS')
echo "${result}"
}

// 解决方案 2:使用 @NonCPS
@NonCPS
def findMatch(String text) {
return (text =~ /hello/).find()
}

script {
def result = findMatch("hello world")
}

Pipeline 重启后无法恢复

症状:Jenkins 重启后,运行中的 Pipeline 无法恢复

可能原因

  1. 使用了不可序列化的对象
  2. Pipeline 耐久性设置为 NONE
  3. Agent 不可用

解决方案

// 检查耐久性设置
options {
durabilityHint('MAX_SURVIVABILITY')
}

// 避免使用不可序列化的对象
// 使用 @NonCPS 或立即计算结果

并发构建冲突

症状:并发构建时出现文件冲突或数据不一致

解决方案

1. 禁用并发构建

options {
disableConcurrentBuilds()
}

2. 使用锁

stage('Deploy') {
steps {
lock(resource: 'shared-server') {
sh './deploy.sh'
}
}
}

3. 使用独立工作空间

agent {
docker {
image 'maven:3.9-eclipse-temurin-21'
reuseNode false // 每次使用新的工作空间
}
}

插件问题

插件安装失败

症状:插件无法安装或安装后不工作

诊断步骤

# 检查 Jenkins 日志
grep -i "plugin\|error" /var/log/jenkins/jenkins.log

# 检查插件依赖
# 在 Manage Jenkins → Plugins → Installed 中查看依赖

常见原因和解决方案

1. 依赖缺失

错误: Failed to load plugin due to missing dependency

解决方案:

  • 安装缺失的依赖插件
  • 或更新 Jenkins 版本以支持插件

2. 版本不兼容

错误: Plugin version X requires Jenkins version Y or later

解决方案:

  • 升级 Jenkins
  • 或安装兼容的插件版本

3. 网络问题

# 检查更新中心连接
curl -I https://updates.jenkins.io

# 使用镜像源
# Manage Jenkins → Plugins → Advanced → Update Site
# 设置为国内镜像:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

插件冲突

症状:安装插件后 Jenkins 异常

诊断

# 以安全模式启动
java -jar jenkins.war --httpPort=8080 --disablePlugins=plugin1,plugin2

# 查看插件加载日志
grep "plugin" /var/log/jenkins/jenkins.log | grep -i "fail\|error"

解决方案

  1. 禁用最近安装的插件
  2. 检查插件依赖关系
  3. 查看插件兼容性报告

安全问题

登录失败

症状:无法登录 Jenkins

解决方案

1. 重置管理员密码

# 方法 1:使用 Script Console(如果能访问)
import jenkins.model.*
import hudson.security.*

def instance = Jenkins.getInstance()
def user = instance.getSecurityRealm().getUser("admin")
user.setPassword("new-password")
instance.save()

# 方法 2:禁用安全(需要重启)
# 编辑 config.xml
sudo nano /var/lib/jenkins/config.xml
# 将 <useSecurity>true</useSecurity> 改为 false
# 重启 Jenkins 后修改密码,再重新启用安全

2. LDAP/OAuth 配置错误

# 禁用外部认证
# 编辑 config.xml
sudo nano /var/lib/jenkins/config.xml
# 修改 securityRealm 为本地用户数据库
<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
<disableSignup>true</disableSignup>
</securityRealm>

权限丢失

症状:登录后无任何权限

解决方案

# 编辑 config.xml,重置授权策略
sudo nano /var/lib/jenkins/config.xml

# 使用全控制策略
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
<denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>

# 或使用管理员策略(仅用于恢复)
<authorizationStrategy class="hudson.security.GlobalMatrixAuthorizationStrategy">
<permission>hudson.model.Hudson.Administer:admin</permission>
</authorizationStrategy>

诊断工具

Script Console

Script Console 是诊断问题的重要工具:

访问路径:Manage Jenkins → Script Console

常用诊断脚本

// 查看所有运行中的构建
Jenkins.instance.getAllItems(Job.class).each { job ->
job.builds.each { build ->
if (build.isInProgress()) {
println "Running: ${job.name} #${build.number}"
println " Duration: ${build.duration}"
println " Executor: ${build.executor?.owner?.name}"
}
}
}

// 查看队列中的任务
Jenkins.instance.queue.items.each { item ->
println "Queued: ${item.task.fullDisplayName}"
println " Why: ${item.getCauseOfBlockage()?.shortDescription}"
println " In queue for: ${(System.currentTimeMillis() - item.getInQueueSince()) / 1000}s"
}

// 检查节点状态
Jenkins.instance.nodes.each { node ->
def computer = node.toComputer()
println "${node.name}: ${computer?.online ? 'Online' : 'Offline'}"
println " Executors: ${computer?.numExecutors}"
println " Busy: ${computer?.countBusy}"
}

// 系统信息
println "Jenkins version: ${Jenkins.version}"
println "Java version: ${System.getProperty('java.version')}"
println "OS: ${System.getProperty('os.name')}"
println "Memory: ${Runtime.runtime.maxMemory() / 1024 / 1024} MB"
println "Free memory: ${Runtime.runtime.freeMemory() / 1024 / 1024} MB"

系统信息

Manage Jenkins → System Information 显示:

  • Java 系统属性
  • 环境变量
  • 插件列表

线程转储

获取线程转储

# 方法 1:通过 Web 界面
# Manage Jenkins → Thread Dump

# 方法 2:使用 jstack
jstack <jenkins-pid> > thread-dump.txt

# 方法 3:发送信号
kill -3 <jenkins-pid>
# 查看日志文件中的线程转储

健康检查

// 通过 Script Console 运行健康检查
import jenkins.model.Jenkins

def jenkins = Jenkins.getInstance()

// 检查磁盘空间
def home = jenkins.rootDir
def freeSpace = home.freeSpace
println "Free disk space: ${freeSpace / 1024 / 1024} MB"

// 检查插件状态
jenkins.pluginManager.plugins.each { plugin ->
if (!plugin.isEnabled()) {
println "Disabled plugin: ${plugin.shortName}"
}
if (plugin.hasCycleDependency()) {
println "Cycle dependency: ${plugin.shortName}"
}
}

// 检查节点状态
jenkins.nodes.each { node ->
def computer = node.toComputer()
if (!computer?.online) {
println "Offline node: ${node.name}"
}
}

常用诊断命令

系统状态

# 服务状态
sudo systemctl status jenkins

# 进程信息
ps aux | grep jenkins

# 端口监听
sudo netstat -tulpn | grep java

# 资源使用
top -p $(pgrep -f jenkins.war)

日志分析

# 实时查看日志
sudo tail -f /var/log/jenkins/jenkins.log

# 搜索错误
grep -i "error\|exception\|fail" /var/log/jenkins/jenkins.log

# 按时间过滤
grep "2024-01-15" /var/log/jenkins/jenkins.log

# 统计错误类型
grep -o "ERROR.*" /var/log/jenkins/jenkins.log | sort | uniq -c

磁盘分析

# 磁盘使用
df -h

# 目录大小
du -sh /var/lib/jenkins/*

# 大文件
find /var/lib/jenkins -type f -size +100M -exec ls -lh {} \;

# 构建历史大小
du -sh /var/lib/jenkins/jobs/*/builds

故障排查清单

启动问题

  • 检查 Java 版本兼容性
  • 检查端口是否被占用
  • 检查文件权限
  • 检查内存是否充足
  • 查看启动日志

连接问题

  • 检查网络连通性
  • 检查防火墙配置
  • 检查 Agent 协议
  • 检查 Agent JAR 版本

构建问题

  • 检查构建日志
  • 检查资源使用
  • 检查凭据配置
  • 检查网络连接

性能问题

  • 检查磁盘空间
  • 检查内存使用
  • 检查构建历史数量
  • 检查插件数量

安全问题

  • 检查用户配置
  • 检查权限设置
  • 检查认证配置
  • 检查安全日志

下一步