推荐使用 maven:3.9.6-openjdk-17-slim 镜像运行 java 项目,因其预装 jdk 17、maven、git、curl 和 tar,开箱即用;gradle:8.5-jdk17 适用于 gradle 项目;避免使用无 ci 工具的 openjdk 官方镜像。

GitLab Runner 用什么镜像才能跑 Java 项目
Runner 本身不带 JDK,得靠你指定的 image 提供。别直接用 openjdk:17-jdk-slim 这类官方镜像——它没装 git、curl、bash 等 CI 必备工具,Pipeline 会卡在 git clone 那步报错。
推荐用 GitLab 官方维护的 registry.gitlab.com/gitlab-org/cloud-native/gitlab-runner-helper:x86_64-9a2e3c5a 这类基础镜像?不行,它没 JDK。真正能开箱即用的是:
-
maven:3.9.6-openjdk-17-slim(推荐):含 Maven + JDK 17 + git + curl + tar,适合绝大多数 Spring Boot/Maven 项目 -
gradle:8.5-jdk17:Gradle 项目首选,自带 JDK 17 和 gradle wrapper 支持 - 自己构建的私有镜像:若需特定 JCE、JFR 或内部 Nexus 配置,才值得投入
注意:slim 后缀的镜像体积小、拉取快,但不含 vimnet-tools 等调试工具——出问题时别指望 apt-get install,得换带 full 或 buster 的变体。
job 中 image 和 variables 怎么配才不冲突
常见错误是把 JAVA_HOME 硬编码成 /usr/lib/jvm/java-17-openjdk-amd64,结果换了个基础镜像路径就失效。Maven/Gradle 镜像一般已设好 JAVA_HOME,你只需验证,不必覆盖。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 先运行一个
script: ["echo $JAVA_HOME", "java -version"]的 debug job,确认实际路径和版本 - 需要指定 Maven 版本时,用
MAVEN_OPTS而非重装 Maven:例如MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository" - 避免在
variables里写死JDK_HOME;如果必须,用which java反推:比如JAVA_HOME: $(dirname $(dirname $(readlink -f $(which java)))) - 多模块项目慎用
MAVEN_OPTS: "-XX:MaxMetaspaceSize=512m"——某些旧版 OpenJDK 会因 Metaspace 参数触发 JIT 崩溃,CI 直接挂掉
为什么 mvn compile 成功但 mvn test 报 NoClassDefFoundError: javax/xml/bind/JAXBContext
这是 JDK 9+ 移除了 JAXB 默认模块导致的典型问题。不是你的代码错了,是 Maven Surefire 插件默认没加模块参数。
解决方法只有两个有效路径:
- 升级 Surefire 插件到 3.0.0+,并在
pom.xml中显式声明模块依赖:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.5</version> <configuration> <argLine>--add-modules java.xml.bind</argLine> </configuration> </plugin> - 降级 JDK 版本到 8(不推荐)或改用
openjdk:17-jdk-slim镜像并手动安装 JAXB:但 OpenJDK 17 已彻底删除该模块,apt install libjaxb-java无效
更隐蔽的坑:某些私有镜像打了 JDK 补丁却没同步更新 java --list-modules 输出,导致 --add-modules 参数被忽略——务必在 CI job 里加一行 java --list-modules | grep jaxb 验证。
Runner 注册时选 shell 还是 docker executor
除非你在本地开发机上临时跑 CI 调试,否则一律选 docker executor。用 shell 意味着所有构建都在 Runner 主机上执行,JDK 版本、Maven 缓存、环境变量全混在一起,一个 job 改了 PATH 就可能影响下一个。
关键配置点:
-
dockerexecutor 必须开启privileged = false(默认),否则无法运行 Docker-in-Docker 场景;真需要 dind,再单独开一个专用 Runner -
pull_policy = "if-not-present"在 CI 高频触发时很危险——镜像更新后 Runner 不拉新版本,导致 JDK 补丁没生效 - 务必配置
volumes = ["/cache"],否则每次.m2/repository都从零下载,Java 构建时间翻倍 - 不要在
config.toml里写environment = ["JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"]——这会覆盖 job 中image自带的环境变量,引发版本错乱
最常被忽略的一点:Runner 的 concurrent 值设太高(比如 20),而宿主机内存只有 8GB,多个 Java 编译任务同时扛起 GC 压力,会导致 OOM Killer 杀掉 javac 进程,错误日志里只显示 Killed 二字,查无可查。










