1. 概述
Jenkins 是一个功能强大的自动化流程管理平台,主要由 Java 编写。它通过定义每个步骤的脚本实现高效的流水线管理。虽然 Jenkins 的部署过程通常较为简单,但在实际环境中仍可能遇到一些与环境相关的问题。
在本文中,我们将手动安装 Jenkins,并探讨可能导致服务无法启动的常见问题。首先,我们会介绍基于包管理器的基本安装流程;接着分析 Jenkins 的核心依赖,特别是 Java 相关的问题;随后讨论由于依赖配置不当导致的启动失败及其解决办法;最后展示一种更简洁、更稳定的方式来部署 Jenkins。
本文中的示例代码已在 Debian 12(Bookworm)和 GNU Bash 5.2.15 环境下测试通过,适用于大多数 POSIX 兼容系统。
2. 安装 Jenkins 包
尽管 Jenkins 有多种运行方式,通过包管理器进行经典安装仍然是最常见的部署方法之一。
首先,确保我们添加了 Jenkins 的官方仓库:
$ wget --output-document=/usr/share/keyrings/jenkins-keyring.asc https://pkg.jenkins.io/debian/jenkins.io-2023.key
上面的命令使用 wget
下载 Jenkins 的仓库签名密钥,并保存到 /usr/share/keyrings/jenkins-keyring.asc
。如需获取最新密钥,可访问 https://pkg.jenkins.io/debian/。
接下来,创建仓库配置文件:
$ echo 'deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian binary/' >> /etc/apt/sources.list.d/jenkins.list
更新包列表并安装 Jenkins:
$ apt-get update && apt-get install jenkins
或者,我们也可以从 https://get.jenkins.io/war-stable/ 手动下载 Jenkins 的通用 WAR 包进行部署。
⚠️ 注意:安装过程中 Jenkins 会尝试自动启动服务,这可能导致启动失败。
3. Jenkins 服务启动失败的常见原因
Jenkins 服务启动失败可能由多种原因引起,例如:
✅ Jenkins 未正确设置 shell 环境变量
✅ 安装脚本未正确执行
✅ 配置文件损坏或缺失
✅ 可执行文件损坏或缺失
虽然这些情况不会直接导致服务无法启动,但它们可能是更严重问题的表征。
Jenkins 启动失败的最终原因通常集中在其启动脚本上,路径为 /usr/bin/jenkins
或 /usr/bin/jenkins.sh
。
我们可以通过 grep
查看脚本中可能导致失败的判断逻辑:
$ grep 'die ' /usr/bin/jenkins -C 1
if $required && [ -z "${val}" ]; then
die "check_env: ${var} must be non-empty"
fi
--
if [ -n "${JENKINS_HOME}" ]; then
[ -d "${JENKINS_HOME}" ] || die "${JENKINS_HOME} is not a directory"
fi
[ -f "${JENKINS_WAR}" ] || die "${JENKINS_WAR} is not a file"
infer_java_cmd || die 'failed to find a valid Java installation'
从上面的脚本片段可以看出,以下几种情况会导致启动失败:
- 必要的环境变量为空(如
JENKINS_WAR
) JENKINS_HOME
路径不存在或不是一个目录- WAR 文件不存在
- Java 安装异常
⚠️ 即使删除了 $JENKINS_HOME
下的 config.xml
文件,Jenkins 仍能正常启动,因此 Java 通常是导致启动失败的罪魁祸首。
4. Jenkins 的 Java 依赖
Jenkins 最重要的外部依赖是 Java 运行环境(JRE)或开发工具包(JDK)。如果在安装 Jenkins 时未安装 Java,即使安装成功,服务也会因缺少依赖而无法启动。
安装 Jenkins 时,可能出现如下错误:
$ apt-get install jenkins
[...]
Created symlink /etc/systemd/system/multi-user.target.wants/jenkins.service → /lib/systemd/system/jenkins.service.
Job for jenkins.service failed because the control process exited with error code.
See "systemctl status jenkins.service" and "journalctl -xeu jenkins.service" for details.
[...]
进一步查看日志:
$ journalctl -xeu jenkins.service
Feb 02 10:00:00 xost jenkins[6660]: jenkins: failed to find a valid Java installation
✅ 问题明确:缺少有效的 Java 安装。
解决方法:安装 OpenJDK:
$ apt-get install openjdk-17-jre
安装完成后,验证 Java 是否安装成功:
$ java -version
openjdk version "17.0.9" 2023-10-17
OpenJDK Runtime Environment (build 17.0.9+9-Debian-1deb12u1)
OpenJDK 64-Bit Server VM (build 17.0.9+9-Debian-1deb12u1, mixed mode, sharing)
再次启动 Jenkins 服务:
$ systemctl start jenkins.service
$ systemctl status jenkins.service
● jenkins.service - Jenkins Continuous Integration Server
Loaded: loaded (/lib/systemd/system/jenkins.service; enabled; preset: enabled)
Active: active (running) since Thu 2024-02-02 16:00:01 UTC; 966ms ago
Main PID: 6111 (java)
⚠️ 注意:有时即使安装了 Java,服务仍可能无法启动,还需进一步排查。
5. Jenkins 的 Java 配置问题
5.1. Java 是否在 $PATH
中
即使安装了 Java,如果 java
命令不在环境变量 $PATH
中,Jenkins 也无法识别:
$ java
bash: /usr/bin/java: No such file or directory
常见原因包括:
- 安装路径未加入
$PATH
- 安装方式未创建符号链接
- 安装后未重启 shell 会话
解决方法:
$ update-alternatives --config java
选择正确的 Java 安装路径。
5.2. 支持的 Java 版本
Jenkins 不同版本对 Java 的兼容性要求不同:
支持的 Java 版本 | 长期支持版本(LTS) | 周发布版本(Weekly) |
---|---|---|
Java 11, 17, 21 | 2.426.1(2023年11月) | 2.419(2023年8月) |
Java 11, 17 | 2.361.1(2022年9月) | 2.357(2022年6月) |
Java 8, 11, 17 | 2.346.1(2022年6月) | 2.340(2022年3月) |
Java 8, 11 | 2.164.1(2019年3月) | 2.164(2019年2月) |
⚠️ Jenkins 控制器节点必须使用支持的 Java 版本。
5.3. 设置 Jenkins 使用的 Java 版本
系统中可能安装了多个 Java 版本,Jenkins 默认使用 java
命令,但可能不是预期版本。
解决方案包括:
✅ 修改 systemd 服务文件:
Environment="JAVA_HOME=/custom/java/path"
✅ 修改 Jenkins 启动脚本 /usr/bin/jenkins
中的 infer_java_cmd()
函数:
infer_java_cmd() {
if [ -n "${JENKINS_JAVA_CMD}" ] && [ -x "${JENKINS_JAVA_CMD}" ]; then
return 0
fi
if [ -n "${JAVA_HOME}" ] && [ -x "${JAVA_HOME}/bin/java" ]; then
JENKINS_JAVA_CMD="${JAVA_HOME}/bin/java"
return 0
fi
JENKINS_JAVA_CMD="$(command -v java)" || return "$?"
}
✅ 使用 update-alternatives
设置默认 Java:
$ update-alternatives --config java
5.4. 安装旧版本或替代 Java
某些情况下,我们需要安装非官方源提供的 Java 版本:
- Oracle Java 档案页面:https://www.oracle.com/java/technologies/downloads/archive/
- OpenJDK 档案页面:https://jdk.java.net/archive/
⚠️ 注意:安装旧版本时可能会遇到依赖冲突,需手动解决。
6. 使用容器避免部署问题
最简单、最稳定的 Jenkins 部署方式是使用容器化部署,例如 Docker:
$ docker run --name jenkins --publish 8080:8080 --detach jenkins/jenkins:lts
该命令会:
- 启动一个基于
jenkins/jenkins:lts
镜像的容器 - 将容器的 8080 端口映射到宿主机
- 以后台方式运行容器
⚠️ 注意:默认情况下,容器停止后数据会丢失。可通过挂载卷保留数据:
$ docker run --name jenkins \
--publish 8080:8080 \
--volume /var/data/jenkins_home:/var/jenkins_home \
--detach \
jenkins/jenkins:lts
7. 总结
本文讨论了 Jenkins 在部署和启动过程中可能遇到的常见问题,尤其是 Java 依赖相关的错误。
尽管 Jenkins 本身是一个相对独立的单体应用,但其运行依赖于外部组件(如 Java)。只有在 Java 环境配置正确、版本兼容的前提下,Jenkins 才能正常启动。
推荐做法:
✅ 使用容器化部署(如 Docker)来简化配置
✅ 确保 Java 安装并配置正确
✅ 使用 update-alternatives
管理多版本 Java
✅ 避免直接修改 Jenkins 启动脚本或服务文件(除非调试)