借助Jib获取特定版本镜像(Maven、Docker、Testcontainers)
关于Testcontainers测试夹具与ImageResolver的疑问
代码背景
我们使用Testcontainers创建测试夹具,原有代码被注释,同事给出了修改建议:
import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; public class SalesforceFixture extends GenericContainer<SalesforceFixture> { private static final String APPLICATION_NAME = "salesforce-emulator"; public SalesforceFixture() { // super(ImageResolver.resolve(APPLICATION_NAME)); super(DockerImageName.parse("gcr.io/ad-selfserve/salesforce-emulator:latest")); ... } ...
同事的注释:
这部分我不太清楚。[ImageResolver]会获取模拟器的特定版本而非latest版本,但需要docker-info文件,Jib不会自动生成该文件(不过我认为它可以生成)。
梳理的信息与疑问
- SalesforceFixture是供其他项目编写测试用的类,会在Docker中启动容器运行模拟真实服务API的模拟器,确保测试代码在生产环境能正常运行。
- 研究了自定义的
ImageResolver类,其核心代码如下:
疑问:它搜索的是哪个文件系统?是运行Java程序的本地电脑当前工作目录?容器内部?还是.jar文件内的目录结构?亦或是镜像仓库中的位置?public static String resolve(String applicationName, File... roots) { Stream<File> searchPaths = Arrays.stream(roots).flatMap((value) -> { return Stream.of(new File(value, "../" + applicationName), new File(value, applicationName)); }); Optional<File> buildFile = searchPaths.flatMap((searchFile) -> { if (searchFile.exists()) { File imageFile = new File(searchFile + File.separator + "/target/docker/image-name"); if (imageFile.exists()) { return Stream.of(imageFile); } } return Stream.empty(); }).findAny(); InputStream build = (InputStream)buildFile.map(ImageResolver::fileStream).orElseGet(() -> { return searchClasspath(applicationName); }); if (build != null) { try { return IOUtils.toString(build, Charset.defaultCharset()).trim(); } catch (IOException var6) { throw new RuntimeException("An exception has occurred while reading build file", var6); } } else { throw new RuntimeException("Could not resolve target image for application: " + applicationName); } } - 同事所说的“特定版本号”与“latest”有什么区别?构建项目时生成的镜像就是latest,什么时候会存在旧版本镜像?
- 是否意味着使用该镜像的项目无法通过Maven/pom.xml指定版本,始终会启动latest版本?
问题解答
1. ImageResolver的搜索范围
从代码逻辑来看:
- 优先在本地文件系统中搜索:基于传入的
roots参数(默认是当前工作目录),查找../applicationName或applicationName目录下的/target/docker/image-name文件。 - 本地找不到时,会从当前Java程序的类路径(包括本地class文件、jar包内的资源)中查找对应资源。
- 不会搜索容器内部或远程镜像仓库(如gcr.io),仅在运行测试的本地环境范围内查找。
2. 特定版本号与latest的差异
latest是Docker镜像的可变标签:每次新构建并推送镜像到仓库时,latest会被覆盖指向最新镜像,无法固定到某个特定版本。- 特定版本号(如
v1.2.3、20240520-build123)是固定标签,每个版本对应唯一镜像,不会被后续构建覆盖,能确保测试使用的镜像版本稳定。 - 旧版本镜像会保留在远程仓库中,项目迭代发布新版本后,旧版本镜像不会自动删除,可用于兼容性测试等场景。
3. Maven版本指定的问题
- 原
ImageResolver逻辑是读取本地构建生成的image-name文件,该文件由salesforce-emulator项目构建时生成(配置Jib可生成包含具体版本的镜像名称文件),能保证测试镜像版本与依赖的项目版本一致。 - 改成硬编码
latest后,确实无法通过Maven/pom.xml指定版本,测试会始终拉取仓库中最新的latest镜像,无法匹配项目依赖的特定版本。 - 若要支持版本指定,应恢复
ImageResolver逻辑,并配置Jib在构建salesforce-emulator时自动生成image-name文件。
内容的提问来源于stack exchange,提问作者Andrew Cheong
相关产品推荐
相关产品推荐

