在Jenkins里给Maven配私服,很多人第一反应是改settings.xml里的mirror,但实际排查中经常遇到“配置改了,下载还是走中央仓库”的情况。这篇偏处理记录,先讲怎么判断是不是私服真正生效,再讲配置时容易忽略的环节,最后给出验证和回滚边界。如果你所在团队私服已经跑了一段时间,只是觉得构建慢,建议先别急着动配置,按下面的步骤做一次链路确认。
先别急着改配置,确认依赖到底从哪里下载
在Jenkins构建过程中,若想确认依赖是否真正从私服下载,可以在构建日志里过滤类似“Downloading”的行,查看URL中的主机名是否指向私服地址。更稳妥的方法是打开私服的访问日志,观察构建时间段内是否有来自Jenkins节点的GET请求,且请求路径对应用户需要的构件路径。如果日志中没有出现私服记录,但构建却成功了,多半是依赖已在Jenkins节点本地仓库中缓存,或Maven使用了其他镜像源,此时需清空本地仓库对应目录后再验证一次。
这里的关键是区分“本地缓存”和“远程来源”。构建日志里的Downloading行只出现在Maven决定从远程仓库拉取时;如果本地仓库已有构件,日志里不会有Downloading。所以只看一次构建日志不够,要清掉对应目录再验证。另外,很多Jenkins任务会设置“每次构建前clean”,但clean不一定删除本地仓库,需要确认。
settings.xml 不是改一处就完事
配置Jenkins时,不要只依赖默认的~/.m2/settings.xml。推荐在“全局工具配置”中为Maven安装指定自定义的settings.xml,或通过构建命令的-s参数显式传入。这样能让所有使用该Maven的任务统一走私服,也方便后续迁移。需要注意,settings.xml中需同时配置mirror和profile,确保私服对中央仓库的镜像规则覆盖所有远程仓库(包括插件仓库),否则部分插件仍可能尝试从外网下载。
在具体配置时,mirror和profile要配合。mirror用<mirrorOf>*</mirrorOf>可以拦截所有仓库,但如果有多个mirror,Maven按第一个匹配生效。profile里可以配置仓库地址,也可以单独设置snapshot策略。下面是一份常见配置示例:
<settings>
<mirrors>
<mirror>
<id>nexus-mirror</id>
<mirrorOf>*</mirrorOf>
<url>http://nexus.example.com/repository/maven-public/</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>nexus-profile</id>
<repositories>
<repository>
<id>central</id>
<url>http://nexus.example.com/repository/maven-public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>http://nexus.example.com/repository/maven-public/</url>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>nexus-profile</activeProfile>
</activeProfiles>
</settings>这段配置里mirrorOf用了*,表示所有远程仓库请求都指向私服。但插件仓库也需要同样处理,否则部分插件还是会直连中央仓库。建议在profile中同时定义repositories和pluginRepositories,并确保activeProfile生效。
证书和仓库组顺序要对上
如果私服开启HTTPS且使用自签名证书,Jenkins的JVM默认不会信任该证书,构建时会报SSL握手失败,常见的异常是javax.net.ssl.SSLHandshakeException。解决办法是将私服证书导入Jenkins运行时JVM的cacerts信任库,使用keytool命令完成导入后重启Jenkins。注意,如果Jenkins有多个执行节点,每个节点的JVM都需要导入证书,否则分布式构建时部分节点会失败。更稳妥的方案是让私服使用受信任的CA签发证书,但内网环境不一定方便。
如果私服是HTTPS且自签名,上面的配置都正确,构建仍可能失败。注意keytool导入证书时,要确认Jenkins进程使用的JVM路径,不是随便导入系统默认Java的cacerts就行。可以用java -version和echo $JAVA_HOME查看。导入后重启Jenkins是必须的,但分布式节点每个都需要单独处理。还有一种办法:在Maven的settings.xml里使用server配置和自定义SSL库,但那样更复杂,不如直接导入cacerts。
验证私服是否生效的几个信号
配置完成后,不要只看私服页面有没有缓存记录。先在构建任务里执行mvn dependency:resolve,观察下载URL是否指向私服地址。如果仍然看到repo.maven.apache.org,说明mirror没有拦下来。另外要注意,Maven对已经存在于本地仓库的构件不会重新请求远程仓库,所以测试前要删除本地仓库中对应的.lastUpdated文件或整个构件目录。私服访问日志是更可靠的证据,能看到来自Jenkins节点IP的GET请求以及返回状态码。如果日志没有记录,但构建成功,那基本可以断定是本地缓存导致。
改完后看这几个信号
最后补充一些边界。私服如果采用仓库组(group)形式,一个URL聚合release和snapshot,那么settings.xml里不需要为snapshot单独配mirror,但需要注意snapshot的更新策略。Maven对snapshot默认每24小时检查一次,如果频繁发布,可以设置updatePolicy为always或interval:60。但这会带来额外网络请求,需要结合私服压力和发布频率权衡。更稳妥的做法是,在私服上对snapshot仓库关闭远程代理,保证本地唯一性;对于release依赖,私服代理central后第一次拉取较慢,后续都走缓存。这些调整都建议先在测试任务上验证,再推送到所有构建任务。