☰
Docker 安装 Jenkins 实现 Spring Boot 持续集成与手动部署实战
2026/10/13 17:41:40 网站建设 项目流程

1. 为什么这套组合至今仍是中小团队的高性价比选择

先把结论摆在前面:用 Docker 跑 Jenkins,配合代码托管平台做触发源,再手动把 Spring Boot 产物部署到目标机器上,这套流程听起来"土",但它在中小团队、个人项目、内部工具类系统里依然是投入产出比最高的方案之一。原因不复杂——它把"持续集成"和"持续部署"这两件事拆开了,CI 部分交给 Jenkins 自动化,CD 部分保留人工确认,既省掉了大量重复构建的体力活,又不会因为一次误提交就把线上环境搞崩。

我见过太多团队一上来就追求全自动流水线,结果光是调试部署脚本、处理权限、排查环境差异就耗掉几周,最后流水线跑通了,业务代码却没写几行。反过来,先把 Jenkins 用 Docker 跑起来,把"拉代码、编译、打包、产出 jar"这一段自动化,部署环节手动执行几条命令,整个链路一两天就能跑通,后续再逐步把部署也自动化,这才是符合实际节奏的做法。

这篇文章面向的是这样几类人:刚接触 CI/CD 想找个能落地的入门方案的后端开发者;手头有几个 Spring Boot 项目、每次发版都靠手动打包上传的独立开发者;以及团队里被安排"搭一套构建环境"但不想引入太重基础设施的运维或全栈同学。整套方案的核心关键词就是Docker 安装 Jenkins、代码托管平台触发构建、Spring Boot 手动部署,我会把每一步为什么这么做、参数怎么定、坑在哪里都讲清楚。

需要提前说明的是,本文的部署环节采用手动方式,这不是偷懒,而是一种刻意的设计选择。手动部署意味着每次上线前有人工确认节点,对于没有完善监控和回滚机制的团队来说,这道人工闸门能挡掉相当一部分事故。等你的自动化测试、健康检查、灰度发布都成熟了,再把这道闸门去掉也不迟。

2. 用 Docker 跑 Jenkins 的镜像选型与目录规划

2.1 为什么不用 apt 或 yum 直接装 Jenkins

很多人第一次搭 Jenkins 的习惯是照着官方文档用包管理器安装,装完发现 Java 版本冲突、插件目录散落各处、想迁移环境得重新装一遍。用 Docker 的核心价值在于环境隔离和可迁移:Jenkins 本体、它依赖的 JDK、它下载的一堆插件,全部封装在容器和挂载卷里,换台机器把卷拷过去就能恢复,这对没有专职运维的团队太重要了。

另一个现实原因是版本管理。Jenkins 的长期支持版和每周更新版差异不小,插件对核心版本还有兼容要求。用 Docker 镜像可以精确锁定某个版本标签,比如锁定到某个 LTS 大版本,避免某天手滑升级导致插件集体罢工。包管理器安装的话,系统一更新就可能被动升级,风险不可控。

还有一点容易被忽略:Jenkins 构建 Spring Boot 项目时需要 Maven 或 Gradle,需要 JDK,这些工具链版本最好和你的项目保持一致。用 Docker 可以把构建工具链也纳入镜像管理,或者干脆用 Jenkins 的"构建时拉取工具"机制,让每个项目用自己声明的版本,互不干扰。

2.2 镜像标签怎么选,别盲目追新

拉镜像的时候你会看到一堆标签,latest、lts、lts-jdk17、jdk21等等。我的建议是永远不要用 latest,因为它的内容会随时间变化,今天跑通的配置明天可能就出问题。选一个带 JDK 版本号的 LTS 标签,比如lts-jdk17这种,既保证了稳定性,又明确了运行环境。

选 JDK 版本要和你的 Spring Boot 项目对齐。Spring Boot 3.x 要求 JDK 17 起步,如果你还在用 Spring Boot 2.x,JDK 8 或 11 也能跑。这里有个坑:Jenkins 容器自带的 JDK 是给 Jenkins 自己用的,你的项目构建时用的 JDK 可以是另一个版本。如果两者不一致,要么在容器里额外装一个 JDK,要么用 Jenkins 的工具配置功能让构建时自动下载指定 JDK。我一般倾向于让容器 JDK 和项目 JDK 保持一致,省去很多麻烦。

拉取命令大致是这样:

docker pull jenkins/jenkins:lts-jdk17

拉完之后用docker images确认一下镜像大小,通常几百 MB 到 1GB 出头,属于正常范围。如果拉取很慢,可以配置镜像加速,这个各家云厂商都有公开的加速地址,配置到 Docker 的 daemon 配置里即可。

2.3 挂载目录的设计决定了你日后迁移的痛苦程度

这是整个环境搭建里最值得花心思的部分。容器本身是无状态的,删了重建很容易,但 Jenkins 的所有配置、任务、构建历史、插件都在数据目录里。如果不做挂载,容器一删,你辛苦配的一切全没了。

Jenkins 容器里需要持久化的核心目录是/var/jenkins_home。我建议在宿主机上单独建一个目录,比如/data/jenkins/home,然后挂载进去。这样备份的时候直接打包这个目录就行,迁移的时候拷到新机器同样位置,启动容器就能恢复。

mkdir -p /data/jenkins/home chown -R 1000:1000 /data/jenkins/home

注意那个chown,这是新手最容易踩的坑。Jenkins 镜像里默认用 uid 1000 的用户运行,如果你挂载的宿主机目录属主是 root,容器启动时会因为没权限写数据目录而报错,日志里会提示权限拒绝。把目录属主改成 1000 就能解决。如果你宿主机上 uid 1000 已经被别的用户占了,那就得用--user参数指定运行用户,或者调整目录权限,这个后面讲启动参数时再说。

除了 home 目录,如果你打算让 Jenkins 直接操作 Docker(比如在流水线里构建镜像),还需要把宿主机的 Docker 套接字挂载进去。但这一步有安全考量,等于把宿主机 Docker 的控制权交给了容器,是否要做取决于你的信任边界。本文的手动部署方案其实不太需要容器内操作 Docker,所以可以先不挂,保持最小权限。

2.4 启动参数逐条拆解

启动命令看着简单,但每个参数都有讲究:

docker run -d \ --name jenkins \ -p 8080:8080 \ -p 50000:50000 \ -v /data/jenkins/home:/var/jenkins_home \ -v /etc/localtime:/etc/localtime:ro \ --restart=unless-stopped \ jenkins/jenkins:lts-jdk17

-p 8080:8080是 Web 界面端口,这个大家都知道。-p 50000:50000是 Jenkins 的代理通信端口,如果你以后要加构建节点(agent),这个端口必须开。现在用不上也建议先映射着,省得以后改。

-v /etc/localtime:/etc/localtime:ro是让容器时间和宿主机一致。别小看这个,构建日志的时间戳如果和你的时区差几个小时,排查问题时会很痛苦。只读挂载(:ro)就够了,容器不需要改宿主机时间。

--restart=unless-stopped保证宿主机重启后 Jenkins 自动起来,除非你手动停过它。这个策略比always更符合直觉,手动停掉的服务不应该被自动拉起来。

启动后用docker logs -f jenkins看日志,会看到一行初始管理员密码,形如:

Please use the following password to proceed to installation: a1b2c3d4e5f6...

这个密码也可以从挂载目录里的secrets/initialAdminPassword文件读到。拿到密码后浏览器访问http://你的机器IP:8080,进入初始化向导。

2.5 初始化向导里那些值得犹豫的选项

向导第一步会让你选"安装推荐的插件"还是"选择插件安装"。我的建议是选推荐插件,它会装 Git、Pipeline、凭据管理等一批基础插件,省得你一个个找。虽然会装一些你暂时用不上的,但体积影响不大,而且后续大概率会用到。

第二步创建管理员账号。这里有个细节:向导默认会创建一个叫 admin 的管理员,但初始密码那个账号其实叫admin之外的名字。建议在这一步直接创建你自己的管理员账号,密码设强一点,然后把初始密码那个临时账号禁用或改密。很多人图省事跳过这步,结果线上 Jenkins 一直用着初始账号,安全隐患很大。

第三步配置实例地址,填你实际访问的地址就行,比如http://192.168.1.100:8080/。这个地址会影响邮件通知里的链接、构建触发回调地址等,填错了后面改起来麻烦。

装完推荐插件后,建议再手动补几个:Git 插件(通常已包含)、Pipeline(已包含)、Credentials Binding(已包含)、Maven Integration(如果用 Maven 构建)。如果推荐列表里没有 Maven Integration,去插件管理里搜一下装上。

3. 打通代码托管平台与 Jenkins 的认证链路

3.1 凭据类型的选择:SSH 密钥还是访问令牌

Jenkins 要拉代码,就得有访问代码仓库的凭据。常见两种方式:SSH 密钥和 HTTPS 访问令牌。两者各有适用场景,选错了后面会反复折腾。

SSH 密钥的好处是配置一次可以长期用,不受令牌过期影响,适合机器对机器的长期集成。缺点是密钥管理稍微麻烦,公钥要传到代码平台,私钥要存进 Jenkins 凭据,而且如果多个项目用同一个密钥,权限粒度不好控制。

HTTPS 访问令牌的好处是权限可以精细控制,比如只给读权限,而且可以随时吊销。缺点是令牌有有效期,到期要换,忘了换就会导致构建突然失败。

我的建议是:内部可信环境用 SSH 密钥,跨团队或权限敏感的场景用访问令牌。本文为了通用性,用访问令牌的方式演示,因为它配置起来更直观,不需要生成密钥对。

在代码托管平台的设置里找到"访问令牌"或"个人访问令牌"入口,创建一个令牌,权限勾选仓库读取即可。如果后续要让 Jenkins 回写构建状态到代码平台,还需要额外的权限。创建后令牌只显示一次,务必先复制保存。

3.2 在 Jenkins 里正确添加凭据

进入 Jenkins 的"系统管理"→"凭据"→"系统"→"全局凭据",添加一个"用户名密码"类型的凭据。用户名填你的代码平台账号,密码填刚才生成的访问令牌。ID 可以留空让 Jenkins 自动生成,也可以自己起个有意义的名字比如git-access-token,方便在流水线里引用。

这里有个常见误区:有人把令牌当成密码直接填,用户名随便写。实际上很多代码平台校验的是"用户名+令牌"组合,用户名必须是你真实的账号名,否则认证会失败。如果用的是某些平台的"仅令牌"认证方式,用户名可以填任意非空值,但具体要看平台文档。

添加完凭据后,建议立刻在 Jenkins 里建一个测试任务验证一下。新建一个自由风格任务,源码管理选 Git,填仓库地址,凭据选刚添加的,保存后点"立即构建"。如果能在工作空间里看到代码被拉下来,说明认证链路通了。这一步别跳过,后面所有构建都依赖它。

3.3 仓库地址的两种写法与踩坑点

仓库地址有 SSH 和 HTTPS 两种写法。用访问令牌的话必须用 HTTPS 地址,形如https://代码平台域名/组织/仓库.git。用 SSH 密钥的话用git@域名:组织/仓库.git这种形式。

一个高频坑是:仓库地址填对了,但 Jenkins 所在机器无法解析代码平台的域名,或者网络不通。这种情况构建日志里会卡在拉取阶段,报连接超时或域名解析失败。排查方法是进 Jenkins 容器里手动执行git clone试试,或者ping一下域名。容器内的网络和宿主机不一定完全一致,特别是公司内网有代理的情况下,容器可能没继承代理配置。

另一个坑是仓库太大导致拉取超时。Jenkins 默认的 Git 超时时间可能不够,可以在任务配置的"附加行为"里调整超时,或者用浅克隆(--depth 1)只拉最近一次提交。浅克隆对构建来说通常够用,能显著加快拉取速度,但如果你需要基于历史提交做变更分析,就不能用浅克隆。

3.4 触发方式:轮询、Webhook 还是手动

代码提交后怎么让 Jenkins 知道该构建了?三种方式:

轮询(Poll SCM)是 Jenkins 定时去问代码平台"有没有新提交",有就构建。配置简单,但实时性差,而且频繁轮询会给代码平台压力。适合代码平台不支持 Webhook 的场景。

Webhook是代码平台在收到提交后主动通知 Jenkins。实时性好,是推荐方式。配置需要在代码平台的仓库设置里加一个 Webhook,地址填 Jenkins 的触发地址,形如http://Jenkins地址:8080/generic-webhook-trigger/invoke?token=xxx或项目专用的构建触发地址。不同代码平台的 Webhook 配置界面不同,但核心就是填 URL 和选择触发事件(通常是 push)。

手动触发就是点按钮构建,适合发版这种需要人工确认的场景。

实际项目中我通常组合使用:日常开发分支用 Webhook 自动构建,发版分支用手动触发。这样既保证了开发效率,又给发版留了确认节点。

Webhook 配置有个容易忽略的点:Jenkins 必须能被代码平台访问到。如果你的 Jenkins 跑在内网,代码平台在公网,Webhook 就推不过来。这种情况要么用轮询,要么在内网和公网之间做转发。本文假设 Jenkins 和代码平台网络可达,如果不可达,退而求其次用轮询也能跑通。

4. Spring Boot 项目的构建任务配置与产物管理

4.1 自由风格任务还是流水线任务

Jenkins 有两种主要任务类型:自由风格(Freestyle)和流水线(Pipeline)。自由风格通过界面点选配置,上手快,适合简单构建。流水线用代码描述构建过程(Jenkinsfile),可版本化、可复用,适合复杂流程。

对于"拉代码→编译→打包"这种线性流程,自由风格完全够用,而且配置直观,出了问题一眼能看出哪步配错了。流水线虽然更强大,但学习曲线陡,调试也麻烦。我的建议是:先用自由风格把流程跑通,等流程稳定且需要多环境复用时,再迁移到流水线。

本文以自由风格为例,因为它对新手更友好。如果你已经熟悉流水线,把下面的步骤翻译成 Jenkinsfile 也不难。

4.2 源码管理配置的细节

新建自由风格任务后,第一块是"源码管理"。选 Git,填仓库地址,选之前配好的凭据。分支填你要构建的分支,比如*/main或*/develop。如果填*会构建所有分支,通常不是你想要的。

"附加行为"里可以加一些优化。比如"浅克隆"减少拉取量,"检出到子目录"用于多仓库场景,"清理工作空间"保证每次构建从干净状态开始。清理工作空间这个选项建议勾上,避免上次构建的残留文件影响这次结果。代价是每次都要重新拉全量代码,如果仓库大,构建时间会增加。权衡下来,构建结果的可靠性比省那点时间更重要。

4.3 构建触发器的组合策略

前面讲过触发方式,这里说具体配置。在"构建触发器"里:

  • 勾选"轮询 SCM",日程表填H/5 * * * *表示每 5 分钟检查一次。H是 Jenkins 的哈希符号,会让不同任务的检查时间错开,避免整点集中请求。
  • 或者勾选"GitHub hook trigger for GITScm polling"(如果代码平台是 GitHub 系),配合 Webhook 使用。

日程表用的是 cron 语法,但 Jenkins 对H的支持是个特色。比如H H * * *表示每天随机一个时间点执行一次,适合做每日构建。别小看这个随机化,如果几十个任务都配0 0 * * *,午夜零点会有一波请求高峰。

4.4 构建步骤:Maven 命令怎么写才稳

"构建"环节选"调用顶层 Maven 目标",目标填clean package -DskipTests。这里几个参数值得说明:

clean清理上次构建产物,避免旧 class 文件混入。package执行编译打包。-DskipTests跳过测试,加快构建速度。但跳过测试有风险,如果测试里有重要的集成检查,跳过就等于放弃了这道防线。我的做法是:日常构建跳过测试,发版构建不跳过。可以在任务里用参数化构建,让触发时选择是否跑测试。

如果项目需要指定 JDK 版本,在"构建环境"里勾选"提供 JDK"或"提供 Maven",选择你配置好的版本。这要求你事先在"系统管理"→"全局工具配置"里配好 JDK 和 Maven 的安装。可以配成自动下载,也可以指向容器内已有的路径。

构建日志里会输出 Maven 的下载依赖过程。第一次构建会下载大量依赖,比较慢,后续有本地仓库缓存就快了。但容器重建后缓存会丢,如果依赖下载是瓶颈,可以把 Maven 本地仓库也挂载出来持久化。

4.5 构建产物的归档与定位

构建成功后,Spring Boot 的产物通常在target/目录下,形如项目名-版本号.jar。在"构建后操作"里添加"归档成品",填target/*.jar,Jenkins 会把 jar 保存下来,可以在构建页面直接下载。

归档的意义在于:每次构建的产物都有记录,出问题可以回溯到具体某次构建的产物。手动部署时,直接从 Jenkins 下载对应版本的 jar,比在本地重新打包可靠得多。

这里有个细节:如果target下有多个 jar(比如有 sources jar、javadoc jar),*.jar会把它们都归档。可以用更精确的匹配,比如target/项目名-*.jar,排除掉 sources 和 javadoc。或者干脆在 Maven 配置里关掉这些附加产物的生成。

产物命名建议带上版本号和构建号,比如在 Maven 的finalName里用${project.version}-${build.number},这样每个产物都唯一,部署时不会搞混。不过build.number是 Jenkins 的变量,Maven 直接读不到,需要在构建时通过参数传入,稍微麻烦点。简单做法是用 Maven 的版本号,配合 Jenkins 的构建号在归档文件名里区分。

5. 手动部署 Spring Boot 产物的完整操作链路

5.1 为什么保留手动部署这道工序

前面提过,手动部署是刻意保留的人工闸门。具体来说,它带来三个好处:上线前有人确认,避免自动部署把未验证的代码推上生产;部署过程可见,执行命令的人清楚每一步在做什么,出问题能立刻反应;回滚简单,手动部署通常保留了上一个版本的 jar,回滚就是换个文件重启。

当然手动部署也有代价:容易漏步骤、依赖个人经验、无法做到秒级发布。所以它适合发布频率不高(比如一周几次)、团队规模小、对发布速度要求不极端的场景。如果你的业务需要一天发几十次,那必须上自动化部署,手动方式会成为瓶颈。

5.2 从 Jenkins 取产物的几种方式

产物归档后,取用方式有几种。最简单的是在 Jenkins 构建页面点归档的 jar 直接下载到本地,再上传到目标服务器。这种方式适合偶尔发版,但每次手动下载上传很繁琐。

稍微好一点的是用命令行工具从 Jenkins 拉取。Jenkins 提供了直接的产物下载地址,形如http://Jenkins地址:8080/job/任务名/构建号/artifact/target/项目.jar。用curl或wget就能拉,配合脚本可以半自动化。

curl -u 用户名:API令牌 -O "http://Jenkins地址:8080/job/任务名/lastSuccessfulBuild/artifact/target/项目.jar"

注意这里的认证,用 API 令牌比用密码安全。API 令牌在用户的"配置"页面生成。lastSuccessfulBuild是 Jenkins 的内置变量,指向最近一次成功的构建,用它就不用每次改构建号。

如果目标服务器能直接访问 Jenkins,可以在服务器上执行这条命令拉取产物,省去本地中转。如果访问不了,就得先下载到本地再上传。

5.3 目标服务器上的目录结构与启动脚本

目标服务器上建议规划一个清晰的目录结构:

/opt/app/ ├── releases/ │ ├── 项目-20240101-1.jar │ └── 项目-20240102-2.jar ├── current -> releases/项目-20240102-2.jar ├── logs/ └── start.sh

releases存放历史版本,current是个软链接指向当前运行的版本,logs放日志。这种结构的好处是回滚只需改软链接指向,然后重启服务。

启动脚本大致这样:

#!/bin/bash APP_HOME=/opt/app JAR=$APP_HOME/current LOG=$APP_HOME/logs/app.log PID=$(ps -ef | grep "$JAR" | grep -v grep | awk '{print $2}') if [ -n "$PID" ]; then kill -15 $PID sleep 5 if ps -p $PID > /dev/null; then kill -9 $PID fi fi nohup java -jar $JAR \ --spring.profiles.active=prod \ -Xms512m -Xmx1024m \ > $LOG 2>&1 &

这里用kill -15先发优雅停止信号,给应用时间处理完手头请求、关闭连接池。等 5 秒还没停再kill -9强杀。直接kill -9可能导致数据不一致,能优雅停就优雅停。

JVM 参数-Xms512m -Xmx1024m是堆内存初始值和最大值。设成一样可以避免运行中堆扩容带来的性能波动。具体数值要根据服务器内存和应用实际需求定,别照抄。设太小会频繁 GC,设太大可能挤占其他进程内存。

5.4 部署操作的完整步骤与验证

一次完整的手动部署流程:

  1. 在 Jenkins 上确认目标构建成功,产物已归档。
  2. 从 Jenkins 拉取 jar 到目标服务器的releases目录,文件名带上版本或构建号。
  3. 更新current软链接指向新 jar:ln -sfn /opt/app/releases/新jar /opt/app/current。
  4. 执行start.sh重启服务。
  5. 观察日志tail -f /opt/app/logs/app.log,确认启动无异常。
  6. 访问健康检查接口或业务接口,验证服务正常。
  7. 如果异常,把current指回上一个版本,重启,回滚完成。

第 6 步的验证很关键,别启动完就不管了。Spring Boot 应用启动成功不代表业务正常,可能数据库连不上、配置读错了、端口被占用了。至少要访问一个能反映核心依赖状态的接口。如果项目有健康检查端点(比如 Spring Boot Actuator 的/actuator/health),优先用它。

5.5 部署环节的常见故障与排查思路

端口被占用:启动日志报Address already in use。说明上一个进程没停干净,或者有别的程序占了端口。用lsof -i:端口或netstat -tlnp | grep 端口找到占用进程处理掉。

启动后立刻退出:日志里可能有异常堆栈。常见原因是配置文件缺失、数据库连不上、依赖的中间件不可达。仔细看日志开头的报错,通常能定位到具体原因。

启动慢或卡住:可能是连某个外部服务超时。检查配置里的连接地址、超时设置。有时候是 DNS 解析慢,可以在/etc/hosts里加静态解析。

内存溢出:日志报OutOfMemoryError。要么调大-Xmx,要么排查代码里的内存泄漏。临时调大能救急,但根治还得看代码。

软链接更新后仍跑旧版本:检查current是否真的指向了新文件,用ls -l /opt/app/current确认。有时候是脚本里路径写死了,没走软链接。

6. 让这套流程更耐用的几个加固点

6.1 构建环境的依赖缓存

前面提过,容器重建后 Maven 本地仓库会丢,下次构建要重新下载所有依赖。如果依赖多,这可能是几分钟甚至十几分钟的浪费。解决办法是把 Maven 本地仓库挂载出来持久化。

在启动 Jenkins 容器时加一个挂载:

-v /data/jenkins/m2:/var/jenkins_home/.m2

或者在全局工具配置里把 Maven 的本地仓库路径指到挂载目录。这样依赖只下载一次,后续构建直接命中缓存。代价是占磁盘空间,定期清理一下没用的依赖即可。

6.2 构建失败的快速定位习惯

构建失败时,第一件事是看日志里第一个 ERROR 或 BUILD FAILURE 出现的位置。Jenkins 的日志很长,从后往前翻容易漏掉根因,从前往后找到第一个报错点更高效。

常见失败原因归类:依赖下载失败(网络问题或仓库地址错)、编译错误(代码问题)、测试失败(代码或环境问题)、打包失败(配置问题)。定位到类别后排查方向就清晰了。

如果是偶发失败,比如网络抖动导致的依赖下载失败,可以配置构建重试。Jenkins 本身没有内置重试,但可以用插件或在流水线里写重试逻辑。自由风格任务的话,手动再点一次构建通常就能过。

6.3 凭据与权限的最小化原则

Jenkins 里的凭据能访问代码仓库,一旦泄露影响不小。几个加固建议:凭据只给必要的权限,比如只读仓库;定期轮换访问令牌;不同项目用不同凭据,避免一个泄露全部沦陷;Jenkins 的 Web 界面不要暴露在公网,至少加一层认证或限制访问来源。

如果团队多人使用 Jenkins,用 Jenkins 的权限管理给不同人分配不同权限。普通开发者只能触发构建和看日志,不能改任务配置和系统设置。这个在"系统管理"→"全局安全配置"里设置。

6.4 从手动部署平滑过渡到自动部署的路径

这套流程跑顺之后,如果想进一步自动化,可以按这个顺序推进:先把"拉取产物+重启服务"写成脚本,在目标服务器上手动执行脚本完成部署;然后把脚本调用集成到 Jenkins 的构建后步骤,用 SSH 插件远程执行;最后加上健康检查和自动回滚,失败时自动切回上一版本。

每一步都别跳,因为自动化部署的坑往往在细节里——SSH 免密配置、远程执行的环境变量、脚本的幂等性、并发部署的锁。一步步来,每步验证稳定了再进下一步,比一次性全自动然后天天救火要靠谱得多。

6.5 日志与构建历史的保留策略

Jenkins 默认保留所有构建历史,时间长了磁盘会满。在任务配置里可以设置"丢弃旧的构建",比如保留最近 30 次,或者保留最近 30 天。归档的产物也受这个策略影响,如果产物重要,要么单独备份,要么把保留数量设大一点。

构建日志本身也占空间,但通常比产物小。如果排查问题需要历史日志,保留策略别设太激进。我的习惯是保留最近 50 次构建,产物保留最近 10 次,兼顾排查需求和磁盘占用。

目标服务器上的日志也要管理。Spring Boot 的日志如果不切割,几天就能涨到几个 GB。用 logback 配置按天切割和保留天数,或者用系统的 logrotate 处理。日志写满磁盘导致服务挂掉的事故,我见过不止一次。

7. 我在实际搭建中踩过的几个真实坑

第一个坑是容器内时区不对导致构建日志时间错乱。当时没挂载/etc/localtime,容器默认 UTC 时间,和本地差 8 小时。排查一个"为什么凌晨的构建"问题时被误导了很久,后来才发现是时区问题。挂载时区文件后解决。

第二个坑是挂载目录权限。第一次启动 Jenkins 时没改目录属主,容器反复重启,日志里报权限拒绝。当时不知道 Jenkins 用 uid 1000 运行,折腾了半天。后来chown -R 1000:1000一下就好了。这个坑几乎每个新手都会踩。

第三个坑是 Webhook 配置后不触发。检查发现是 Jenkins 的地址填的是localhost,代码平台从外部访问不到。改成实际 IP 后正常。这个提醒我们,配置里凡是涉及地址的地方,都要想清楚"谁访问谁",别用相对地址或 localhost。

第四个坑是 Maven 构建时 JDK 版本不匹配。项目要求 JDK 17,但 Jenkins 容器默认用的是别的版本,编译报错。后来在全局工具配置里指定了 JDK 17,并在任务里选用,才解决。这个坑的教训是:构建环境的版本一定要和项目要求对齐,别想当然。

第五个坑是手动部署时忘了停旧进程,新进程起不来报端口占用。后来在启动脚本里加了自动停旧进程的逻辑,才避免了这个低级错误。手动操作容易漏步骤,能用脚本固化的就固化。

这些坑的共同点是:都不是技术难题,而是环境配置和操作习惯的问题。但恰恰是这些细节,决定了这套流程是"能用"还是"好用"。把每个环节的边界条件想清楚,把重复操作脚本化,这套 Docker + Jenkins + Spring Boot 手动部署的组合就能稳定地为你服务很久。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询