行业资讯
📅 2026/7/11 0:12:25
Jenkins+Maven+Git生产部署避坑清单:73次故障提炼的实操指南
1. 这不是教程是我在生产环境踩了73次坑后抄出来的部署清单“全网最全的 Jenkins Maven Git 自动化部署指南”——这个标题我第一次看到时笑了。不是笑它夸张而是笑自己三年前也信了这句话结果在客户现场连续通宵48小时就为了搞懂为什么mvn clean package在本地能跑在 Jenkins 里死活报NoClassDefFoundError为什么git clone总卡在fatal: not a git repository为什么 SSH Publisher 传过去的 jar 包双击打不开日志里只有一行no main manifest attribute为什么第5次构建后服务器上堆了17个同名 jarjps一查全是僵尸进程端口占满却连不上……这些不是配置错误是整套链路里埋着的、文档从不提、报错不指向、新手根本找不到入口的“暗坑”。今天这篇不讲“Jenkins 是什么”“Maven 有什么用”这种教科书内容。它是一份可直接粘贴进你服务器终端、按步骤执行就能跑通的生产级部署清单。核心就三件事让代码从 Git 仓库自动拉下来、用 Maven 打出能直接运行的 jar、再一键推到目标服务器并干净启动。全程不依赖 Docker、不强求 Kubernetes、不预设云厂商就用最朴素的三台 Linux 机器Git 服务端、Jenkins 构建机、应用服务器所有路径、命令、参数、权限、环境变量全部来自我亲手部署过的21个Java Web项目真实记录。你不需要理解 CI/CD 的抽象概念只需要知道第3步填哪个路径、第7步改哪行 pom.xml、第12步的 clean.sh 脚本为什么必须加grep java -jar而不是简单grep $appname。文末附的排查表是我把73次故障归类后提炼出的12个高频问题对应ssh命令一行定位答案比如“构建成功但访问404”直接执行curl -v http://localhost:8088/actuator/health就能判断是应用没启、端口错、还是 Spring Boot Actuator 没开。关键词全部落在实操层jenkins安装与配置不是教你点几下按钮而是告诉你/etc/init.d/jenkins里JAVA_HOME必须硬编码否则 systemd 会忽略你的.bashrcmaven配置的核心不是settings.xml位置而是阿里云镜像源必须加mirrorOfcentral/mirrorOf否则spring-boot-starter-parent会绕过镜像去连 Maven Centralgit安装及配置教程的关键不在git config --global user.name而在于 Jenkins 用的 git 用户必须有~/.ssh/id_rsa且权限为600否则gitgithub.com认证永远失败。如果你正被jenkins下载插件失败卡住别折腾代理——90%的情况是/var/lib/jenkins/cache目录属主错了chown -R jenkins:jenkins /var/lib/jenkins/cache一行解决。这整篇就是把热搜词背后那些“看似简单、实则致命”的细节全给你钉死在操作步骤里。2. 整体设计为什么必须用这三台机器为什么不能跳过任何一步2.1 架构选型的底层逻辑隔离性不是为了炫技是为故障兜底看到“三台服务器”很多人第一反应是“太重了我一台机器搞定”。但这是用运维事故换来的认知。我最早在测试环境把 GitLab、Jenkins、应用全塞进一台 4C4G 的虚拟机结果一次git push触发构建Jenkins 吃光内存GitLab Web 页面直接 502开发连代码都提交不了。后来改成两台GitLab Jenkins 合并在一台应用单独一台。结果某次 Jenkins 构建时触发了 Maven 的dependency:copy-dependencies把整个~/.m2/repository打包上传瞬间占满磁盘GitLab 数据库因空间不足崩溃。现在坚持三台不是资源浪费而是故障域物理隔离GitLab 服务器只做代码托管不装 JDK/Maven/Git 客户端不开放 SSH 给 Jenkins 用户。它的唯一职责是响应git clone请求哪怕 Jenkins 服务器宕机开发照样能push代码。Jenkins 服务器只做构建中枢不跑任何业务应用。它装 JDK、Maven、Git、SSH 客户端但绝不装 Tomcat 或任何应用容器。它的角色是“工厂”只负责把源码变成 jar然后交给“物流”SSH Publisher运走。这样当构建出错时不会影响线上服务当 Jenkins 升级卡死业务照常运行。应用服务器只运行最终 jar不装 Git、不装 Maven、不装 Jenkins Agent。它只有 JRE不是 JDK、SSH Server、基础监控工具。这样即使 Jenkins 被误配置成rm -rf /也删不到应用服务器上的业务数据。这个架构的代价是多维护一台机器收益是任何单点故障都不会导致研发流程中断。比如 GitLab 服务器硬盘坏了Jenkins 仍能从缓存拉取上次成功的构建产物应急发布Jenkins 服务器被攻击应用服务器上的老版本 jar 仍在运行用户无感知。2.2 工具链锁定为什么非得是 Jenkins Maven Git替代方案在哪失效有人问“用 GitHub Actions 不更简单”——简单但不可控。GitHub Actions 的 runner 是黑盒你无法精确控制 Maven 的-Dmaven.repo.local/opt/m2路径无法强制使用特定版本的 JDK比如客户要求 JDK 11而 Actions 默认是 JDK 17更无法在构建前执行sed -i s/PROD/TEST/g application.yml这种敏感配置替换。Jenkins 的价值在于每个环节都暴露给你你可以写 Shell 脚本在Pre Steps里改配置可以在Post Steps里用scp传证书甚至能用groovy脚本动态读取数据库里的灰度开关。Maven 也不是唯一选择但它是 Java 生态里构建契约最稳定的工具。Gradle 虽快但build.gradle里一个plugins { id org.springframework.boot version 3.2.0 }版本号写错整个构建就挂错误信息还藏在 200 行堆栈里而 Maven 的pom.xml是 XML结构固定parent标签在哪、properties怎么覆盖IDE 和 Jenkins 插件解析起来零歧义。更重要的是mvn clean package -DskipTests这条命令从 Maven 2 到 Maven 4参数含义从未变过——这种稳定性对生产环境就是生命线。Git 的不可替代性在于分布式协作的原子性。SVN 的svn export无法保证“同一 commit ID 下所有文件版本严格一致”而 Git 的git archive --formatzip HEAD导出的压缩包解压后和git checkout出来的内容字节级相同。这对审计至关重要当客户要求提供“上线版本的源码包”你给的 zip 文件哈希值必须和 GitLab 上该 commit 的哈希完全一致。Jenkins 的 Git 插件正是利用这一点在构建开始前先git rev-parse HEAD记录本次构建的精确版本后续所有日志、产物、告警都带上这个 commit ID出了问题秒级定位。2.3 流程设计的生死线为什么“构建前清理”比“构建后部署”重要十倍几乎所有新手教程都把重点放在“怎么把 jar 传上去”却忽略了一个事实自动化部署最大的敌人不是失败而是残留。我见过最惨的案例一个电商项目Jenkins 每次构建都把新 jar 传到/opt/app/但没人清理旧 jar。半年后目录里有 217 个order-service-*.jar运维手动kill -9时杀错了进程把正在处理支付的旧版本干掉了导致 32 笔订单状态卡在“支付中”。从此我们定下铁律任何部署流程Pre Steps 的权重必须占 60%。具体到本方案“构建前清理”包含三个不可分割的层次Jenkins 工作区清理在 Jenkins 项目配置的General选项卡里勾选Delete workspace before build starts。否则mvn clean只清target/但src/main/resources/config.properties如果被上一次构建脚本修改过就会污染本次构建。应用服务器进程清理clean.sh脚本不是简单pkill -f jenkins-study因为pkill会匹配到grep jenkins-study自身进程导致误杀。必须用ps -ef | grep java -jar | grep jenkins-study精确抓取再用awk {print $2}提取 PID。应用服务器文件清理rm -rf $appname/${appname}*.jar这行命令里$appname是传入的参数如jenkins-study${appname}*.jar用引号包裹防止空格扩展*通配所有版本号。如果不用引号jenkins study-1.0.jar会被拆成两个参数rm命令直接报错。这三个清理动作必须在 Jenkins 的Build阶段之前、Post Steps之后执行。顺序错了比如把清理放在Post Steps那构建失败时清理就不会触发残留物永远留着。这个细节决定了你的自动化是“省事”还是“埋雷”。3. 核心细节解析从安装到配置每一步背后的“为什么”3.1 Jenkins 安装为什么 WAR 包启动比 RPM 包更可控网络上大量教程推荐yum install jenkins但生产环境我一律用java -jar jenkins.war启动。原因很现实RPM 包把 Jenkins 安装到/usr/lib/jenkinsJDK 路径写死在/etc/sysconfig/jenkins一旦你要升级 JDK必须同时改这个文件、重启 jenkins 服务、还要担心 SELinux 是否放行新 JDK 路径。而 WAR 包方式所有路径由你掌控# 创建专用用户避免用 root 运行 useradd -m -d /var/lib/jenkins -s /bin/bash jenkins chown -R jenkins:jenkins /var/lib/jenkins # 下载 WAR 包以 2.440.4 为例 wget https://get.jenkins.io/war-stable/2.440.4/jenkins.war -O /var/lib/jenkins/jenkins.war # 编写启动脚本 /etc/systemd/system/jenkins.service [Unit] DescriptionJenkins Automation Server Afternetwork.target [Service] Typesimple Userjenkins Groupjenkins EnvironmentJAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 EnvironmentJENKINS_HOME/var/lib/jenkins ExecStart/usr/bin/java -Djava.awt.headlesstrue -DJENKINS_HOME/var/lib/jenkins -jar /var/lib/jenkins/jenkins.war --httpPort8080 --prefix/jenkins Restarton-failure RestartSec10 [Install] WantedBymulti-user.target关键点EnvironmentJAVA_HOME...必须显式声明否则 Jenkins 启动时读不到系统级 JAVA_HOME--prefix/jenkins设置上下文路径避免和 Nginx 反向代理冲突RestartSec10设置重启间隔防止 JVM OOM 后疯狂重启打满 CPU。启动后首次访问http://your-ip:8080/jenkins页面会提示输入初始密码。这个密码在/var/lib/jenkins/secrets/initialAdminPassword不要用cat直接看用sudo -u jenkins cat否则权限错误导致 Jenkins 启动失败。3.2 Maven 配置阿里云镜像源的 3 个致命陷阱maven配置阿里云仓库是搜索热词但 90% 的人只复制了mirror标签却栽在三个隐藏坑里陷阱一mirrorOf的值必须是central不是*或external:*错误配置mirror idaliyunmaven/id mirrorOf*/mirrorOf !-- 错会拦截所有仓库包括 JCenter -- nameAliyun Maven/name urlhttps://maven.aliyun.com/repository/public/url /mirror正确配置mirror idaliyunmaven/id mirrorOfcentral/mirrorOf !-- 只拦截 Maven Central -- nameAliyun Maven/name urlhttps://maven.aliyun.com/repository/public/url /mirror为什么Spring Boot 的 parent POM 依赖spring-boot-starter-parent它本身又依赖spring-boot-dependencies而后者在pom.xml中声明的仓库是repositoryidcentral/idurlhttps://repo.maven.apache.org/maven2/url/repository。只有mirrorOf精确匹配centralMaven 才会把请求重定向到阿里云。用*会导致jcenter.bintray.com的依赖也被重定向而阿里云镜像不包含 JCenter 内容构建直接失败。陷阱二settings.xml必须放在 Jenkins 用户家目录下Jenkins 用jenkins用户运行所以 Maven 的全局配置文件路径是/var/lib/jenkins/.m2/settings.xml不是/root/.m2/settings.xml或/etc/maven/settings.xml。验证方法在 Jenkins 的Script Consolehttp://your-jenkins/script里执行println Maven home: ${System.getenv(M2_HOME)} println User settings: ${new File(System.getProperty(user.home), .m2/settings.xml).absolutePath}如果输出的路径不是/var/lib/jenkins/.m2/settings.xml说明 Jenkins 没读到你的配置。陷阱三profile激活必须显式绑定activeByDefault很多教程漏掉这一步导致镜像源不生效profiles profile idaliyun/id repositories repository idcentral/id urlhttps://maven.aliyun.com/repository/public/url /repository /repositories /profile /profiles activeProfiles activeProfilealiyun/activeProfile !-- 必须加这一段 -- /activeProfiles3.3 Git 配置为什么git config --global在 Jenkins 里是无效的Jenkins 的 Git 插件默认用jenkins用户执行git clone而git config --global是写入当前用户的~/.gitconfig。但jenkins用户的家目录是/var/lib/jenkins/var/lib/jenkins/.gitconfig文件很可能不存在或为空。更糟的是Jenkins 有时会用--no-global参数调用 git彻底忽略全局配置。解决方案是在 Jenkins 项目配置里显式设置 Git 全局配置进入Manage JenkinsConfigure System找到Git plugin区域在Global Config user.name Value填Jenkins Bot在Global Config user.email Value填jenkinsyour-company.com这样 Jenkins 会在每次git clone前自动执行git config --global user.name Jenkins Bot git config --global user.email jenkinsyour-company.com同时SSH 密钥必须由 Jenkins 用户生成并管理sudo -u jenkins ssh-keygen -t rsa -b 4096 -C jenkinsyour-company.com -f /var/lib/jenkins/.ssh/id_rsa sudo -u jenkins chmod 600 /var/lib/jenkins/.ssh/id_rsa sudo -u jenkins chmod 644 /var/lib/jenkins/.ssh/id_rsa.pub然后把公钥cat /var/lib/jenkins/.ssh/id_rsa.pub的内容添加到 GitLab 的Deploy Keys不是个人 Access Token并勾选Write access allowed。这样 Jenkins 就能用 SSH 协议gityour-gitlab.com:group/project.git克隆无需输密码。4. 实操过程从创建项目到稳定运行手把手拆解每个环节4.1 创建 Jenkins 项目自由风格 vs Pipeline为什么新手必须选前者Jenkins 有两种项目类型Freestyle project自由风格和Pipeline流水线。新手教程常推 Pipeline因为它用Jenkinsfile代码化但实际落地时95% 的故障都源于Jenkinsfile的语法错误——一个缩进空格不对整个构建就卡在Expected a step。而自由风格项目所有配置都在 Web 界面完成错误即时可见适合建立肌肉记忆。创建步骤DashboardNew Item 输入项目名如jenkins-study 选择Freestyle projectOK在General选项卡勾选Discard old builds设置Max # of builds to keep为 10防磁盘爆满勾选Delete workspace before build starts前文强调的清理在Source Code Management选项卡选择GitRepository URL填gityour-gitlab.com:group/jenkins-study.gitCredentials点AddJenkinsSSH Username with private keyPrivate Key选From the Jenkins master ~/.ssh即刚才生成的id_rsa在Build Triggers选项卡勾选Poll SCMSchedule填H/5 * * * *每5分钟检查一次 Git 变更注意不要用Build when a change is pushed to GitLab那需要 GitLab 配置 Webhook新手极易配错导致触发失败4.2 Maven 构建配置Root POM和Goals的精准填写这是新手最容易填错的地方。Root POM不是pom.xml的绝对路径而是相对于 Jenkins 工作区根目录的相对路径。假设你的 Git 仓库结构是jenkins-study/ ├── pom.xml ├── src/ │ └── main/ │ └── java/那么Root POM就填pom.xml因为工作区根目录就是jenkins-study/pom.xml就在它下面。如果填成/var/lib/jenkins/workspace/jenkins-study/pom.xmlJenkins 会报pom.xml not found。Goals填clean package -Dmaven.test.skiptrue解释clean删除target/目录确保干净构建package执行编译、测试、打包全流程-Dmaven.test.skiptrue跳过测试生产部署通常不跑单元测试节省时间关键技巧如何确认 Maven 能找到 JDK在Build Environment选项卡勾选Provide Node npm bin/ folder to PATH然后在Build步骤的Execute shell里加一行诊断命令echo JAVA_HOME: $JAVA_HOME echo PATH: $PATH mvn -version构建日志里如果出现Apache Maven 3.9.6 (bc02d32b8745...且Java version: 11.0.22说明 JDK 和 Maven 都正常。4.3 SSH Publisher 配置远程目录、前缀、执行命令的黄金组合Post-build ActionsSend files or execute commands over SSH是部署的核心。配置项必须严丝合缝配置项值为什么Nametest-server任意但要和Manage JenkinsConfigure SystemSSH Servers里定义的名字一致Source filestarget/*.jar注意是target/不是*/target/因为工作区根目录就是项目根目录Remove prefixtarget/把target/jenkins-study-0.0.1-SNAPSHOT.jar传过去时去掉target/变成jenkins-study-0.0.1-SNAPSHOT.jarRemote directory~/jenkins-study/传到远程服务器的jenkins-study/目录下而不是家目录根方便管理Exec in pty✅ 勾选否则nohup命令不生效Exec command填cd ~/jenkins-study # 杀掉旧进程clean.sh 的精简版直接写这里 pid$(ps -ef | grep java -jar | grep jenkins-study | awk {print $2}) if [ ! -z $pid ]; then kill -9 $pid; fi # 删除旧 jar rm -f jenkins-study-*.jar # 启动新 jar nohup java -jar jenkins-study-*.jar --server.port8088 log.out 21 为什么不用clean.sh外部脚本因为外部脚本需要chmod 777有安全风险而内联命令在 Jenkins 权限下执行更可控。grep jenkins-study之所以安全是因为nohup java -jar启动的进程命令行里必然包含jenkins-study字符串不会误杀其他进程。4.4 验证与调试三步定位法5 分钟揪出 90% 的问题构建失败时别急着重试。用这套标准化排查法第一步看 Jenkins 控制台输出Console Output重点找三类关键词Cloning into /var/lib/jenkins/workspace/jenkins-study...→ Git 克隆是否成功[INFO] BUILD SUCCESS→ Maven 打包是否成功如果看到[ERROR] Failed to execute goal...说明pom.xml有问题SSH: Connecting from host [jenkins98]→ SSH 连接是否建立如果卡在这里检查test97的 SSH 服务是否开启systemctl status sshd第二步登录 Jenkins 服务器手动模拟构建sudo -u jenkins bash cd /var/lib/jenkins/workspace/jenkins-study git pull # 看是否能拉取最新代码 mvn clean package -Dmaven.test.skiptrue # 看是否能本地打包如果手动失败说明环境配置有硬伤如果手动成功但 Jenkins 失败说明 Jenkins 的环境变量没继承检查JAVA_HOME是否在systemd服务里声明。第三步登录应用服务器检查部署结果# 查看文件是否传过来 ls -l ~/jenkins-study/ # 查看进程是否启动 ps -ef | grep java # 查看日志是否有异常 tail -50 ~/jenkins-study/log.out # 本地 curl 测试 curl -v http://localhost:8088如果curl返回Hello dev说明部署成功如果返回Connection refused检查ps是否真有 java 进程如果ps有进程但curl不通用netstat -tuln | grep 8088看端口是否监听再用ss -tuln | grep 8088确认ss比netstat更准。5. 常见问题与排查技巧实录73 次故障沉淀出的 12 个高频问题速查表以下表格完全基于真实故障场景整理每一行都是血泪教训。问题描述直击现象解决方案给出可立即执行的命令原理说明解释“为什么”让你下次遇到同类问题30 秒内定位。问题现象解决方案直接复制执行原理说明构建日志显示FATAL: Command git fetch --tags --force --progress --prune --no-recurse-submodules --depth1 origin refs/heads/*:refs/remotes/origin/* returned status code 128sudo -u jenkins ssh -T gityour-gitlab.comJenkins 用jenkins用户连接 GitLabssh -T测试 SSH 连通性。返回Welcome to GitLab说明密钥正确返回Permission denied说明~/.ssh/id_rsa权限不对应为600或公钥没加到 GitLab 的 Deploy KeysMaven 构建报错Could not find artifact org.springframework.boot:spring-boot-maven-plugin:jar:3.2.0sudo -u jenkins mvn help:effective-settings此命令输出 Jenkins 实际读取的settings.xml路径和内容。90% 的镜像源失效是因为settings.xml路径错了或mirrorOf值不对必须是central构建成功但应用服务器上jps看不到进程log.out为空sudo -u jenkins ssh test97 bash -c cd ~/jenkins-study java -jar jenkins-study-*.jar --server.port8088手动在远程服务器上执行启动命令观察实时输出。常见原因是JAVA_HOME未在~/.bashrc里导出或java命令不在PATHwhich java查看构建成功jps能看到进程但curl http://localhost:8088返回Connection refusedsudo -u jenkins ssh test97 netstat -tuln | grep 8088netstat查看 8088 端口是否被监听。如果无输出说明 Spring Boot 应用没启动成功如果有输出但curl不通检查application.yml里server.port是否被覆盖如 profile 激活了prod而prod配置里端口是 8080多次构建后应用服务器上~/jenkins-study/目录里堆满jenkins-study-*.jar且jps显示多个同名进程sudo -u jenkins ssh test97 ps -ef | grep jenkins-study | grep java -jar | awk {print \$2} | xargs kill -9此命令精确杀死所有java -jar启动的jenkins-study进程。grep java -jar是关键避免grep jenkins-study匹配到grep自身进程Jenkins 页面打开慢插件安装总失败日志里有java.net.SocketTimeoutException: connect timed outsudo -u jenkins sed -i s/https:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g /var/lib/jenkins/hudson.model.UpdateCenter.xmlJenkins 插件中心默认连国外地址国内网络不稳定。清华镜像源地址已验证可用改完重启 Jenkins 服务构建日志里mvn clean package成功但target/目录下没有 jar 文件sudo -u jenkins ls -l /var/lib/jenkins/workspace/jenkins-study/target/检查target/目录是否存在。如果存在但无 jar说明pom.xml里packaging标签不是jar如误写成war或spring-boot-maven-plugin的executions配置缺失SSH Publisher 传文件时报错Failed to copy file: Permission deniedsudo -u jenkins ssh test97 mkdir -p ~/jenkins-study chmod 755 ~/jenkins-studyJenkins 用户对远程目录无写权限。chmod 755确保组和其他用户可读可执行Jenkins 用户通常是root或jenkins可写构建成功但浏览器访问http://test97:8088返回Whitelabel Error Pagesudo -u jenkins ssh test97 tail -20 ~/jenkins-study/log.out | grep -i errorWhitelabel Error Page是 Spring Boot 默认错误页说明应用启动了但内部出错。tail -20查看最后 20 行日志grep -i error过滤错误常见是数据库连接失败或 Redis 连不上Jenkins 构建时git clone报错fatal: not a git repository (or any of the parent directories): .gitsudo -u jenkins rm -rf /var/lib/jenkins/workspace/jenkins-studyJenkins 工作区损坏。rm -rf强制删除下次构建会重新git clone。此问题多发生在 Jenkins 服务器磁盘满后强制关机nohup java -jar启动后log.out文件一直为空jps也看不到进程sudo -u jenkins ssh test97 bash -c cd ~/jenkins-study nohup java -jar jenkins-study-*.jar log.out 21 手动执行nohup命令观察是否报错。常见原因是log.out所在目录无写权限或java命令路径不对which java输出/usr/bin/java但PATH里没包含/usr/binJenkins 页面显示Plugin installation failed插件列表里Maven Integration灰色不可选sudo systemctl stop jenkins sudo rm -rf /var/lib/jenkins/plugins/maven-plugin* sudo systemctl start jenkins插件安装一半失败残留文件导致冲突。rm -rf彻底删除插件目录重启 Jenkins 后重新安装提示以上所有命令均可直接复制到你的终端执行。它们不是理论方案而是我在客户现场键盘上敲过的真实命令。比如第 6 条清华镜像源我替换了 17 台 Jenkins 服务器无一例外提速 5 倍以上第 11 条nohup手动测试救过我 3 次凌晨两点的紧急发布。6. 实战心得那些文档里永远不会写的“脏技巧”6.1 “一键回滚”不是神话是三行 Shell 脚本的事自动化部署的终极考验不是“怎么上线”而是“上线失败怎么秒级回滚”。我给所有项目标配一个rollback.sh脚本放在应用服务器~/jenkins-study/目录下#!/bin/bash # 回滚到上一个版本 cd ~/jenkins-study # 获取上一个 jar 的文件名按修改时间倒序取第二个 prev_jar$(ls -t jenkins-study-*.jar | sed -n 2p) if [ -z $prev_jar ]; then echo No previous version found exit 1 fi # 杀掉当前进程 pid$(ps -ef | grep java -jar | grep jenkins-study | awk {print $2}) if [ ! -z $pid ]; then kill -9 $pid; fi # 启动上一个版本 nohup java -jar $prev_jar --server.port8088 log.out 21 echo Rolled back to $prev_jar在 Jenkins 的Post Steps里加一个Execute shell内容是sudo -u jenkins ssh test97 ~/jenkins-study/rollback.sh这样只要点击 Jenkins 页面的Build Now就自动回滚。比手动登录服务器快 10 倍且不会因手抖输错文件名。6.2 日志切割为什么log.out必须用logrotate而不是追加nohup java -jar ... log.out看似简单但log.out会无限增长。一个高流量项目一天日志超 2GBtail -f log.out直接卡死。解决方案是用logrotate# 创建 /etc/logrotate.d/jenkins-study /home/jenkins/jenkins-study/log.out { daily missingok rotate 30 compress delaycompress notifempty create 644 jenkins jenkins sharedscripts postrotate sudo -u jenkins pkill