如何在JUnit Testcontainers中为OpenSearch使用自定义Dockerfile
解决方案:在Testcontainers中使用带analysis-phonetic插件的自定义OpenSearch镜像
方法一:预构建自定义镜像并复用
这是最直接的方案,基于官方镜像构建自定义镜像后,直接用OpenSearchContainer引用,保留官方容器的所有便捷特性。
- 构建自定义镜像
在Dockerfile所在目录执行命令:
docker build -t my-opensearch:2.11.1-phonetic .
- 修改测试配置代码
class TestConfiguration : ApplicationContextInitializer<ConfigurableApplicationContext> { val container = OpensearchContainer( DockerImageName.parse("my-opensearch:2.11.1-phonetic") ) override fun initialize(applicationContext: ConfigurableApplicationContext) { container.start() TestPropertySourceUtils.addInlinedPropertiesToEnvironment( applicationContext, "opensearch.username=${container.username}", "opensearch.password=${container.password}", "opensearch.host=${container.host}", "opensearch.scheme=http", "opensearch.port=${container.firstMappedPort}", ) } }
自定义镜像基于官方镜像构建,因此OpenSearchContainer的username、password等便捷方法完全可用,和官方镜像用法一致。
方法二:Testcontainers动态构建自定义镜像
如果不想预先手动构建镜像,可让Testcontainers自动构建并缓存镜像。
方案A:结合ImageFromDockerfile与OpenSearchContainer
class TestConfiguration : ApplicationContextInitializer<ConfigurableApplicationContext> { // 动态生成自定义镜像 val customImage = ImageFromDockerfile() .withDockerfileContent(""" FROM opensearchproject/opensearch:2.11.1 RUN bin/opensearch-plugin install analysis-phonetic """.trimIndent()) .withTag("my-opensearch:test") val container = OpensearchContainer(customImage) override fun initialize(applicationContext: ConfigurableApplicationContext) { container.start() TestPropertySourceUtils.addInlinedPropertiesToEnvironment( applicationContext, "opensearch.username=${container.username}", "opensearch.password=${container.password}", "opensearch.host=${container.host}", "opensearch.scheme=http", "opensearch.port=${container.firstMappedPort}", ) } }
Testcontainers会自动构建镜像并缓存,后续测试直接复用缓存版本,无需重复构建。
方案B:使用GenericContainer手动配置
如果OpenSearchContainer无法适配动态镜像,可直接用GenericContainer,利用官方镜像默认凭据配置:
class TestConfiguration : ApplicationContextInitializer<ConfigurableApplicationContext> { val container = GenericContainer( ImageFromDockerfile() .withDockerfileContent(""" FROM opensearchproject/opensearch:2.11.1 RUN bin/opensearch-plugin install analysis-phonetic """.trimIndent()) ) .withExposedPorts(9200) .withEnv("discovery.type", "single-node") .withEnv("plugins.security.disabled", "false") // 官方镜像默认用户名密码固定为admin/admin private val defaultUsername = "admin" private val defaultPassword = "admin" override fun initialize(applicationContext: ConfigurableApplicationContext) { container.start() TestPropertySourceUtils.addInlinedPropertiesToEnvironment( applicationContext, "opensearch.username=$defaultUsername", "opensearch.password=$defaultPassword", "opensearch.host=${container.host}", "opensearch.scheme=http", "opensearch.port=${container.getMappedPort(9200)}", ) } }
若需自定义密码,可添加环境变量withEnv("OPENSEARCH_INITIAL_ADMIN_PASSWORD", "your-custom-password")。
方法三:修复DockerComposeContainer配置问题
若之前使用DockerComposeContainer失败,检查路径与配置:
- 编写
docker-compose.yml(放在src/test/resources目录下)
version: '3.8' services: opensearch: build: . # 指向Dockerfile所在目录 ports: - "9200:9200" environment: - discovery.type=single-node - plugins.security.disabled=false
- 测试配置代码
class TestConfiguration : ApplicationContextInitializer<ConfigurableApplicationContext> { val composeContainer = DockerComposeContainer(File("src/test/resources/docker-compose.yml")) .withExposedService("opensearch", 9200) override fun initialize(applicationContext: ConfigurableApplicationContext) { composeContainer.start() val opensearchService = composeContainer.getService("opensearch") TestPropertySourceUtils.addInlinedPropertiesToEnvironment( applicationContext, "opensearch.username=admin", "opensearch.password=admin", "opensearch.host=${opensearchService.host}", "opensearch.scheme=http", "opensearch.port=${opensearchService.getMappedPort(9200)}", ) } }
多模块项目需调整docker-compose.yml的文件路径,确保Testcontainers能正确加载。
内容的提问来源于stack exchange,提问作者Crell
相关产品推荐
相关产品推荐

