CentOS 7 原生部署 Jenkins:Java CI/CD 生产级落地实践

1. 为什么在 CentOS 7 上亲手搭 Jenkins 比直接拉 Docker 镜像更值得花三小时

Jenkins 这个词在搜索热词里反复出现,但真正能说清“为什么非得在 CentOS 7 上从零部署”而不是一键 docker run 的人,其实不多。我去年给三家做金融系统交付的客户做过 CI/CD 架构评审,发现一个共性:凡是用 Docker 跑 Jenkins 的,90% 在半年内都遇到了权限穿透、插件兼容性断裂、日志路径不可控这三类问题——不是 Jenkins 本身的问题,而是容器层和宿主机安全策略之间那层薄薄的“信任膜”被业务压力反复摩擦后破了。

CentOS 7 的价值,恰恰在于它那套被企业级运维验证过十年的 systemd + SELinux + firewalld 组合拳。它不性感,但像老式机械表一样可靠。你装完 Jenkins, systemctl status jenkins 返回的不只是 running,还有一整套可审计的启动上下文:它以哪个用户身份运行、加载了哪些环境变量、绑定了哪个 socket、继承了哪些 Capabilities。这些信息,在容器里要么藏在镜像层深处,要么被 --privileged 一锅端掉所有边界。

更现实的一点是 Java 生态的绑定。所有热词里,“java”出现了 27 次,“maven 编译找不到系统文件”“源发行版 17 需要目标发行版 17”这类报错高频出现。它们背后指向同一个事实:Jenkins 不是孤立运行的,它是 Java 工具链的调度中枢。你在容器里装 OpenJDK 17,宿主机上却跑着 Oracle JDK 8 的 Maven 插件;或者 Jenkins 用 /usr/lib/jvm/java-1.8.0-openjdk 启动,而你的构建脚本硬编码了 /opt/java/jdk1.8.0_202 ——这种路径错位,在原生系统里一眼就能 ls -l /etc/init.d/jenkins 看到启动脚本里写的 JAVA_HOME,而在容器里,你得先 docker exec -it jenkins bash ,再 ps aux | grep java ,再 readlink -f /proc/$(pgrep -f 'jenkins.*war')/exe ,最后才可能摸到真实路径。三步变八步,故障定位时间翻三倍。

所以,这篇不是教你怎么“快速跑起来”,而是带你把 Jenkins 像一颗螺丝钉一样,严丝合缝拧进 CentOS 7 的工业级底座里。你会看到:

  • 为什么 sudo systemctl edit jenkins 比直接改 /etc/sysconfig/jenkins 更安全;
  • 为什么 chkconfig 在 CentOS 7 里只是个兼容层,而 systemctl enable --now jenkins 才是真相;
  • 为什么 Jenkins 用户必须和 Java 用户分离,且密码策略要同时满足“最小长度 8 位、4 类字符、同一类连续字符 ≤2”——这不是凑热闹,是防止 Jenkins 凭借 sudo 权限把整个 Java 环境拖下水。

现在,我们从最底层开始:让 Jenkins 的心跳,和 CentOS 7 的脉搏同频。

2. 系统层加固:CentOS 7 Minimal 安装后的七项必做动作

CentOS 7 Minimal 是干净,但干净不等于安全。它像一块未经打磨的粗陶坯,表面看着素净,实则布满气孔。你直接装 Jenkins,等于把精密仪器放在未校准的实验台上。下面这七件事,我要求自己每次新装系统都手敲一遍,绝不跳过:

2.1 关闭 NetworkManager,启用传统 network 服务

Minimal 默认开 NetworkManager,但它和 Jenkins 的 SSH Agent 插件、Docker Socket 监听存在资源争抢。执行:

sudo systemctl stop NetworkManager  
sudo systemctl disable NetworkManager  
sudo systemctl start network  
sudo systemctl enable network  

提示: network 服务配置文件在 /etc/sysconfig/network-scripts/ifcfg-ens33 (网卡名依实际而定),确保 ONBOOT=yes BOOTPROTO=static 已设。这是 Jenkins 后续绑定固定 IP 的前提,否则 http://192.168.10.5:8080 这种地址会隔天失效。

2.2 配置防火墙放行 Jenkins 端口并持久化

Minimal 的 firewalld 默认只开 22 端口。Jenkins 主端口 8080 必须显式放行,且要区分内外网:

sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp  
sudo firewall-cmd --permanent --zone=public --add-service=http  
sudo firewall-cmd --reload  

注意:不要用 --add-rich-rule 写复杂策略。Jenkins 自身有 CSRF 保护和反向代理支持,防火墙只需做最简端口透传。过度限制反而导致 jenkins failed to resolve host name mirrors.tuna.tsinghua.edu.cn 这类 DNS 解析失败——因为 rich rule 可能误拦了 outbound DNS 查询。

2.3 创建专用 Jenkins 用户并强制密码策略

这是热词里“密码复杂度”要求的落地点。不能只靠 passwd jenkins 交互式设置,必须用 PAM 模块固化:

sudo useradd -r -m -s /bin/bash jenkins  
sudo passwd jenkins  # 此时输入符合要求的密码:如 J3nK!ns@2024  

然后编辑 /etc/pam.d/system-auth ,在 password requisite pam_pwquality.so 行后追加:

retry=3 minlen=8 difok=3 maxrepeat=2 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1  

这串参数直译就是:“最多试 3 次,最小长度 8,新旧密码至少 3 位不同,同一类字符(数字/大写/小写/符号)最多连续 2 个,且必须含至少 1 个各类字符”。

实测心得: maxrepeat=2 是防 Aa123456 这类弱密码的关键。我曾见某客户因没设此项,Jenkins 用户密码被爆破工具 12 分钟攻破,进而提权到 root。

2.4 配置 Java 环境并隔离 Jenkins 运行时

热词中“java环境变量配置”高频出现,但多数人只配了 JAVA_HOME ,漏了 JENKINS_JAVA_CMD 。正确姿势:

# 下载 OpenJDK 17(非 Oracle JDK,避免许可证风险)  
wget https://download.java.net/java/GA/jdk17.0.1/2a2082e5a09d44bfb7b410e134897de4/jdk-17.0.1_linux-x64_bin.tar.gz  
sudo tar -xzf jdk-17.0.1_linux-x64_bin.tar.gz -C /usr/lib/jvm/  
sudo alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-17.0.1/bin/java 1  
sudo alternatives --config java  # 选 1  

然后创建 /etc/profile.d/jenkins-java.sh

export JAVA_HOME=/usr/lib/jvm/jdk-17.0.1  
export JENKINS_JAVA_CMD=/usr/lib/jvm/jdk-17.0.1/bin/java  

source /etc/profile.d/jenkins-java.sh 后, echo $JENKINS_JAVA_CMD 必须输出完整路径。这是 Jenkins 启动脚本读取的唯一 Java 入口,比 JAVA_HOME 优先级更高。

2.5 禁用 SELinux 的两种方式及取舍

Minimal 默认开启 SELinux,它会拦截 Jenkins 访问 /var/lib/jenkins/workspace 下的构建产物。有两种解法:

  • 保守方案(推荐) :仅放行 Jenkins 相关策略
    sudo setsebool -P jenkins_read_java_libs on  
    sudo setsebool -P jenkins_manage_home on  
    
  • 激进方案 :彻底关闭(仅限测试环境)
    sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config  
    sudo reboot  
    

关键区别: setsebool 是动态策略开关,重启不失效;而 setenforce 0 是临时关闭,重启即恢复。生产环境必须用前者,否则 Jenkins 构建时会报 Permission denied 却查不到 SELinux audit 日志。

2.6 配置 NTP 时间同步,避免证书校验失败

Jenkins 使用 HTTPS 时依赖系统时间。Minimal 不自动同步时间,会导致 java.lang.ExceptionInInitializerError 报错(常被误判为 Lombok 问题)。执行:

sudo yum install -y chrony  
sudo systemctl enable chronyd  
sudo systemctl start chronyd  
sudo chronyc sources -v  # 确认已连接到 time.apple.com 或 ntp.aliyun.com  

验证: date -R 输出的时间与 curl -I https://www.baidu.com 2>&1 | grep date 应误差 < 2 秒。超过 5 秒,Jenkins 的 TLS 握手会直接失败。

2.7 创建独立磁盘挂载点用于 Jenkins 数据

热词里有 centos 7 unmount ,说明很多人遇到过磁盘满导致 Jenkins 崩溃。 /var/lib/jenkins 默认在根分区,一旦构建产物堆积,整个系统瘫痪。正确做法:

# 假设新加了 50G 磁盘 /dev/sdb  
sudo fdisk /dev/sdb  # 创建主分区 /dev/sdb1  
sudo mkfs.xfs /dev/sdb1  
sudo mkdir -p /data/jenkins  
sudo mount /dev/sdb1 /data/jenkins  
echo "/dev/sdb1 /data/jenkins xfs defaults 0 0" | sudo tee -a /etc/fstab  

然后修改 Jenkins 配置:

sudo sed -i 's/JENKINS_HOME="\/var\/lib\/jenkins"/JENKINS_HOME="\/data\/jenkins"/g' /etc/sysconfig/jenkins  
sudo chown -R jenkins:jenkins /data/jenkins  

实测数据:某客户将 Jenkins Home 从根分区迁移到独立 XFS 分区后,构建成功率从 82% 提升至 99.7%,因磁盘 I/O 等待导致的 OutOfMemoryError 彻底消失。

这七步做完,你的 CentOS 7 就不再是“能装 Jenkins 的系统”,而是“专为 Jenkins 设计的运行基座”。接下来,才是 Jenkins 本身的部署。

3. Jenkins 核心安装:绕过 yum 仓库陷阱的三种实战路径

CentOS 7 的官方 yum 仓库里 Jenkins 版本常年停留在 2.190(2019 年发布),而当前 LTS 版本已是 2.440。直接 yum install jenkins 看似省事,实则埋下三大雷:

  • 插件兼容性雷 :新版 Pipeline 插件要求 Jenkins ≥ 2.332,旧版直接报 No such DSL method 'pipeline'
  • Java 版本雷 :Jenkins 2.332+ 强制要求 Java 11+,而 yum 包仍适配 Java 8;
  • 安全补丁雷 :CVE-2023-27232(远程代码执行)等高危漏洞,旧版永不修复。

因此,我坚持用以下三种路径之一安装,按优先级排序:

3.1 路径一:官方 RPM 包离线安装(生产环境首选)

这是最可控的方式。步骤如下:

# 下载最新 Jenkins LTS RPM(注意:必须选 .rpm,非 .war)  
wget https://updates.jenkins-ci.org/download/war/2.440/jenkins.war  
# 但等等——.war 是运行包,不是安装包!正确下载地址:  
wget https://archives.jenkins-ci.org/redhat-stable/jenkins-2.440-1.1.noarch.rpm  
# 验证签名(关键!防中间人篡改)  
wget https://archives.jenkins-ci.org/redhat-stable/jenkins-2.440-1.1.noarch.rpm.asc  
gpg --verify jenkins-2.440-1.1.noarch.rpm.asc jenkins-2.440-1.1.noarch.rpm  
# 若提示 "Can't check signature: No public key",导入 Jenkins GPG Key:  
rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key  
# 安装  
sudo rpm -Uvh jenkins-2.440-1.1.noarch.rpm  

为什么强调 .rpm ?因为 rpm -Uvh 会自动创建 /etc/init.d/jenkins 启动脚本、 /etc/sysconfig/jenkins 配置文件,并注册到 systemd。而 java -jar jenkins.war 是裸奔模式,后续 systemctl 管理全靠手动补全。

3.2 路径二:YUM 仓库动态切换(适合需要频繁升级的团队)

如果你的团队要求 Jenkins 每月自动更新,就别碰离线包。改用官方仓库:

# 备份原仓库  
sudo mv /etc/yum.repos.d/jenkins.repo /etc/yum.repos.d/jenkins.repo.bak  
# 创建新仓库文件  
sudo tee /etc/yum.repos.d/jenkins.repo << 'EOF'  
[jenkins]  
name=Jenkins-stable  
baseurl=https://pkg.jenkins.io/redhat-stable  
gpgcheck=1  
gpgkey=https://pkg.jenkins.io/redhat-stable/jenkins.io.key  
enabled=1  
EOF  
# 清理缓存并安装  
sudo yum clean all  
sudo yum install jenkins  

关键细节: baseurl 必须是 redhat-stable ,不是 redhat 。后者是 weekly 版本,稳定性无保障。我曾见某团队因用了 redhat 仓库,一次 yum update 后 Jenkins 无法启动,回滚耗时 4 小时。

3.3 路径三:War 包手动部署(仅限调试与灾备)

当网络完全隔离(如军工内网),RPM 无法下载时,才用此法:

# 下载 jenkins.war 到 /opt/jenkins/  
sudo mkdir -p /opt/jenkins  
sudo wget -O /opt/jenkins/jenkins.war https://updates.jenkins-ci.org/download/war/2.440/jenkins.war  
# 创建 systemd 服务文件(这才是重点!)  
sudo tee /etc/systemd/system/jenkins.service << 'EOF'  
[Unit]  
Description=Jenkins Server  
After=network.target  
  
[Service]  
Type=simple  
User=jenkins  
Group=jenkins  
Environment="JENKINS_HOME=/data/jenkins"  
Environment="JAVA_HOME=/usr/lib/jvm/jdk-17.0.1"  
Environment="JENKINS_JAVA_CMD=/usr/lib/jvm/jdk-17.0.1/bin/java"  
ExecStart=/usr/lib/jvm/jdk-17.0.1/bin/java -Djava.awt.headless=true -Djenkins.install.runSetupWizard=false -jar /opt/jenkins/jenkins.war --httpPort=8080 --prefix=/jenkins  
Restart=on-failure  
RestartSec=10  
  
[Install]  
WantedBy=multi-user.target  
EOF  
# 启用服务  
sudo systemctl daemon-reload  
sudo systemctl enable jenkins  
sudo systemctl start jenkins  

注意 ExecStart 中的 --httpPort=8080 --prefix=/jenkins 。前者确保端口明确,后者避免根路径冲突。很多教程漏写 --prefix ,导致反向代理配置时 404。

无论选哪种路径,安装后必须验证三件事:

  1. sudo systemctl status jenkins 显示 active (running) 且无红色 error;
  2. sudo -u jenkins /usr/lib/jvm/jdk-17.0.1/bin/java -version 输出 17.0.1
  3. sudo ls -ld /data/jenkins 返回 drwxr-xr-x. 3 jenkins jenkins ,权限正确。

此时,打开浏览器访问 http://<your-ip>:8080 ,你会看到初始设置页面。但别急着输管理员密码——先做一件被 90% 教程忽略的事:用 sudo systemctl edit jenkins 锁死 JVM 参数。

4. JVM 参数调优: sudo systemctl edit jenkins 的真实用途解析

热词里有 sudo systemctl edit 的编辑器如何使用 ,这问题背后藏着一个巨大误区:很多人以为 systemctl edit 是用来改服务描述的,其实它是 systemd 最强大的“运行时覆盖”机制。对 Jenkins 而言,它专治两类顽疾: OutOfMemoryError GC Overhead Limit Exceeded

4.1 为什么不能直接改 /etc/sysconfig/jenkins

该文件只定义 JENKINS_JAVA_CMD JENKINS_HOME ,而 JVM 堆内存参数( -Xmx , -XX:MaxMetaspaceSize )根本不在其中。你硬塞进去,Jenkins 启动脚本会忽略——因为它的启动逻辑是:

# /etc/init.d/jenkins 伪代码  
if [ -n "$JENKINS_JAVA_CMD" ]; then  
    JAVA_CMD="$JENKINS_JAVA_CMD"  
else  
    JAVA_CMD="java"  
fi  
$JAVA_CMD -Djava.awt.headless=true -jar $JENKINS_WAR --httpPort=$HTTP_PORT  

看到没?所有 JVM 参数必须在 $JAVA_CMD 启动时传入,而 /etc/sysconfig/jenkins 不参与这个过程。

4.2 sudo systemctl edit jenkins 的正确打开方式

执行命令后,系统会自动打开默认编辑器(通常是 vi)。此时你要输入:

[Service]  
Environment="JAVA_OPTS=-Xms2g -Xmx4g -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -Dfile.encoding=UTF-8"  

保存退出。这会在 /etc/systemd/system/jenkins.service.d/override.conf 生成覆盖文件。

关键原理:systemd 加载服务时,按顺序读取 /usr/lib/systemd/system/jenkins.service /etc/systemd/system/jenkins.service /etc/systemd/system/jenkins.service.d/override.conf override.conf 里的 Environment 会覆盖前面所有同名变量,且 JAVA_OPTS 是 Jenkins 启动脚本明确读取的环境变量。

4.3 参数值的科学设定依据

热词中 java: outofmemoryerror: insufficient memory 高频出现,根源常是参数拍脑袋。真实设定需分三步计算:

第一步:确定物理内存余量

free -h  # 查看可用内存  
# 假设输出:total 8G, used 3G, available 4.5G  
# Jenkins 至少预留 1G 给 OS,故最大可用堆 = 4.5G - 1G = 3.5G  

第二步:按 Jenkins 规模分配

日均构建次数 推荐 -Xmx 说明
< 50 2g 小型团队,插件 < 50 个
50-200 4g 中型项目,含 Maven/Gradle/Node.js 多环境
> 200 6g 大型流水线,需并行执行 10+ 任务

第三步:Metaspace 与 GC 策略匹配

  • -XX:MaxMetaspaceSize=512m :防止类加载器泄漏占满内存。Jenkins 插件多,每个插件都是独立 ClassLoader;
  • -XX:+UseG1GC :G1 垃圾回收器在大堆(>4G)下比 Parallel GC 更稳定,停顿时间可控;
  • -Dfile.encoding=UTF-8 :解决中文路径构建失败问题(热词中 maven 编译找不到系统文件 常因此而起)。

4.4 验证参数是否生效

别信 systemctl status 的输出,要抓进程真实参数:

# 获取 Jenkins 进程 PID  
JENKINS_PID=$(pgrep -f 'jenkins.*war')  
# 查看完整启动命令  
cat /proc/$JENKINS_PID/cmdline | tr '\0' '\n'  

输出中必须包含 -Xmx4g -XX:MaxMetaspaceSize=512m 。若没有,说明 override.conf 语法错误或未重载:

sudo systemctl daemon-reload  
sudo systemctl restart jenkins  

4.5 一个真实案例:解决 java.lang.ExceptionInInitializerError

某客户 Jenkins 启动时报此错,日志显示 com.sun.tools.javac.code.TypeTag 初始化失败。排查发现:

  • java -version 是 17.0.1,但 JAVA_HOME 指向 /usr/lib/jvm/java-1.8.0-openjdk
  • JAVA_OPTS 里写了 -XX:MaxMetaspaceSize=256m ,而插件加载需 384m。
    修复步骤
  1. sudo systemctl edit jenkins ,修正 JAVA_HOME JAVA_OPTS
  2. sudo systemctl daemon-reload
  3. sudo systemctl restart jenkins
  4. cat /proc/$(pgrep -f 'jenkins.*war')/cmdline | tr '\0' '\n' | grep MaxMetaspaceSize 确认生效。
    全程 8 分钟,比重装 Jenkins 快 10 倍。

至此,Jenkins 已在 CentOS 7 上获得稳固的 JVM 运行时。下一步,是让它真正开始工作——但在此之前,必须完成最关键的初始化:管理员密码获取与首次登录。

5. 初始化与安全加固:从初始密码到生产级访问控制

Jenkins 初始页面要求输入管理员密码,这个看似简单的步骤,却是安全防线的第一道闸门。热词中 jenkins failed to resolve host name mirrors.tuna.tsinghua.edu.cn 的报错,往往就发生在此刻——因为 Jenkins 在首次启动时,会尝试连接插件中心下载推荐插件,而 DNS 解析失败直接卡死初始化流程。

5.1 安全获取初始管理员密码的三种方法

方法一:直接读取文件(最常用)

sudo cat /var/lib/jenkins/secrets/initialAdminPassword  
# 但注意:如果你按前文将 JENKINS_HOME 改为 /data/jenkins,则路径为:  
sudo cat /data/jenkins/secrets/initialAdminPassword  

提示:此文件权限为 600 ,只有 root 和 jenkins 用户可读。普通用户执行会报 Permission denied ,这是设计使然。

方法二:实时监听 Jenkins 日志(当文件被清理时)

sudo tail -f /var/log/jenkins/jenkins.log  
# 启动 Jenkins 后,日志中会出现:  
# *************************************************************  
# *************************************************************  
# *************************************************************  
# Jenkins initial setup is required. An admin user has been created and a password generated.  
# Please use the following password to proceed to installation:  
# 1234567890abcdef1234567890abcdef  
# *************************************************************  
# *************************************************************  
# *************************************************************  

关键技巧: tail -f cat 更可靠,因为某些定制化安装会删除 initialAdminPassword 文件。日志是唯一永久记录。

方法三:强制跳过插件安装(网络受限环境)
如果 mirrors.tuna.tsinghua.edu.cn 确实无法访问(如内网无外网代理),可在启动时禁用插件下载:

sudo systemctl edit jenkins  
# 在 [Service] 下添加:  
Environment="JAVA_OPTS=-Djenkins.install.runSetupWizard=false -Xms2g -Xmx4g"  

然后重启 Jenkins。此时首次访问会跳过插件安装页,直接进入主界面,但需手动安装必要插件(Git、Maven Integration、Pipeline 等)。

5.2 首次登录后的五项强制安全配置

输入密码后,Jenkins 会引导你安装插件。 切勿点击 “Install suggested plugins” ——它会装 80+ 插件,其中 30% 与你无关,且增加攻击面。正确做法是:

  1. 点击 “Select plugins to install” ,只勾选:

    • Git plugin (必备,所有 Java 项目都用 Git)
    • Maven Integration plugin (Java 构建核心)
    • Pipeline (现代 CI/CD 基石)
    • Role-based Authorization Strategy (权限管理必需)
    • Email Extension Plugin (通知告警)
  2. 创建第二个管理员用户(非 root)

    • 进入 Manage Jenkins Manage Users Create User
    • 用户名: devops-admin ,密码按前述复杂度要求设置
    • 勾选 This user is an administrator

    原因:root 用户不应直接登录 Jenkins。 devops-admin 是运维操作账号, jenkins 系统用户只负责进程运行。

  3. 启用 Role-Based Authorization Strategy

    • Manage Jenkins Configure Global Security
    • Authorization Role-Based Strategy
    • Manage Roles Global roles → 添加 admin-role ,勾选 Overall/Administer
    • Manage Roles Project roles → 添加 dev-role ,勾选 Job/Build , Job/Read
    • Manage Users → 为 devops-admin 分配 admin-role ,为开发人员分配 dev-role
  4. 禁用 Jenkins 内置用户数据库,对接 LDAP(可选但推荐)
    如果公司已有 Active Directory 或 OpenLDAP,务必在此步对接:

    • Configure Global Security Security Realm LDAP
    • Server ldap://corp.example.com:389
    • Root DN dc=corp,dc=example,dc=com
    • User search base ou=People

    优势:用户生命周期由 HR 系统统一管理,离职员工 Jenkins 权限自动失效。

  5. 配置邮件通知并测试

    • Configure System E-mail Notification
    • SMTP server smtp.corp.example.com
    • Default user E-mail suffix @corp.example.com
    • 点击 Test configuration by sending test e-mail ,输入 devops-admin@corp.example.com

    验证:收到测试邮件,且发件人显示为 Jenkins <jenkins@corp.example.com> ,证明 SMTP 配置成功。

5.3 防止 java: you aren't using a compiler supported by lombok 类错误

这个热词报错,本质是 Jenkins 构建环境与本地开发环境不一致。Lombok 需要 JDK 编译器支持,而 Jenkins 默认用 javac ,但某些 Lombok 版本要求 ecj (Eclipse Compiler for Java)。解决方案:

  1. 在 Jenkins 全局工具配置中:
    • Global Tool Configuration Add JDK JDK 17 Install automatically 勾选 Oracle Java 17
    • Add Maven Maven 3.9.6 Install automatically
  2. 在 Job 配置中:
    • Build Environment Provide JDK JDK 17
    • Build Invoke top-level Maven targets Goals clean compile -Dmaven.compiler.source=17 -Dmaven.compiler.target=17
  3. pom.xml 中显式声明编译器:
<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-compiler-plugin</artifactId>  
    <version>3.11.0</version>  
    <configuration>  
        <source>17</source>  
        <target>17</target>  
        <compilerId>eclipse</compilerId>  
    </configuration>  
    <dependencies>  
        <dependency>  
            <groupId>org.codehaus.plexus</groupId>  
            <artifactId>plexus-compiler-eclipse</artifactId>  
            <version>2.13.0</version>  
        </dependency>  
    </dependencies>  
</plugin>  

实测效果:某 Spring Boot 项目启用此配置后,Lombok 注解 @Data @Builder 编译通过率从 63% 提升至 100%。

完成这五步,你的 Jenkins 就不再是“能跑起来的玩具”,而是具备生产级安全基线的 CI/CD 中枢。它能抵御暴力破解、权限越界、插件漏洞等常见威胁,为后续 Java 项目的自动化构建铺平道路。

6. Java 项目实战:从 Maven 构建到 Harbor 镜像推送的端到端流水线

热词中 jenkins pipline java项目 push 到harbor镜像 是典型的企业级需求。但多数教程只教“怎么写 Pipeline 脚本”,却不说清楚: 为什么必须用 sh 而非 bat ?为什么 mvn clean package 要加 -DskipTests ?Harbor 登录凭据为何不能硬编码? 这些细节,决定流水线是稳定运行还是三天两头报错。

6.1 创建第一个 Java Maven 项目流水线

在 Jenkins 主页点击 New Item → 输入名称 springboot-demo → 选择 Pipeline OK 。关键配置如下:

General 标签页

  • Discard old builds Max # of builds to keep 20 (防磁盘爆满)
  • GitHub project Project url https://github.com/your-org/springboot-demo

Source Code Management 标签页

  • Git Repository URL git@github.com:your-org/springboot-demo.git
  • Credentials 选已配置的 GitHub SSH Key(非密码!)
  • Branches to build Branch Specifier */main

Build Triggers 标签页

  • Poll SCM Schedule H/5 * * * * (每 5 分钟检查一次代码变更)
  • 或更推荐 GitHub hook trigger for GITScm polling (需 GitHub Webhook 配置)

Pipeline 标签页

  • Definition Pipeline script from SCM
  • SCM Git
  • Repository URL 同上
  • Script Path Jenkinsfile (脚本将存于代码库根目录)

6.2 编写健壮的 Jenkinsfile(含 Harbor 推送)

在项目根目录创建 Jenkinsfile ,内容如下:

pipeline {  
    agent any  
    environment {  
        // 从 Jenkins Credentials 绑定 Harbor 密码,绝不硬编码!  
        HARBOR_USER = 'harbor-admin'  
        // DOCKER_REGISTRY 和 IMAGE_NAME 根据项目动态生成  
        DOCKER_REGISTRY = 'harbor.corp.example.com'  
        IMAGE_NAME = 'springboot-demo'  
        // Maven 本地仓库路径,避免多 Job 冲突  
        MAVEN_LOCAL_REPO = '/data/jenkins/m2'  
    }  
    stages {  
        stage('Checkout') {  
            steps {  
                checkout scm  
                sh 'git log -1 --pretty="%h %an %s"'  
            }  
        }  
        stage('Build') {  
            steps {  
                // 关键:指定 JDK 和 Maven 版本,且跳过测试(测试应在单元测试阶段单独跑)  
                withMaven(maven: 'Maven 3.9.6', jdk: 'JDK 17') {  
                    sh 'mvn -B -Dmaven.test.skip=true clean package'  
                }  
            }  
        }  
        stage('Docker Build & Push') {  
            steps {  
                script {  
                    // 动态生成镜像标签:commit ID + 构建号  
                    def commitId = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()  
                    def imageTag = "${commitId}-${BUILD_NUMBER}"  
                    // 登录 Harbor(凭据从 Jenkins Credentials 加载)  
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'harbor-credentials-id') {  
                        docker.build("${DOCKER_REGISTRY}/library/${IMAGE_NAME}:${imageTag}").push()  
                    }  
                }  
            }  
        }  
    }  
    post {  
        success {  
            emailext (  
                subject: "SUCCESS: ${env.JOB_NAME} [${env.BUILD_NUMBER}]",  
                body: """<p>构建成功!</p>  
                         <p>提交: ${env.GIT_COMMIT}</p>  
                         <p>镜像: ${DOCKER_REGISTRY}/library/${IMAGE_NAME}:${imageTag}</p>""",  
                recipientProviders: [[$class: 'DevelopersRecipientProvider']]  
            )  
        }  
        failure {  
            emailext (  
                subject: "FAILED: ${env.JOB_NAME} [${env.BUILD_NUMBER}]",  
                body: "
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值