最近公司使用testcontainer来做单元测试,但是通过云效流水线构建时单元测试找不到docker服务,跳过了所有使用testcontainer的测试用例,于是开始查找怎么设置testcontanier连接的docker服务
1、查找官网
点击查看官网描述
通过官网可知,有两种方法可以自定义docker host
1、修改环境变量的DOCKER_HOST为你的docker服务器地址
我试过是可行的, 大家可以自行尝试。因为我把我的docker设置为所有连接都可以访问,所以我不需要配置校验密钥就可以直接连接。
如果需要配置的话,可以将DOCKER_TLS_VERIFY值设置为true或1,同时DOCKER_CERT_PATH路径给你的docker验证密钥的文件夹。
至于怎么设置开放docker连接和怎么开启dockerTLS验证,请读者自行查询资料。
由于我们使用的云效构建单元测试的,并不方便添加环境变量,所以决定再看看有没有其他方法。
2、在.testcontainer.preoperties文件中添加docker.host
不同的操作系统,.testcontainer.preoperties 文件所在位置不同,下面是官网描述。
按照下面配置即可,同第一种方式相同,需要注意的是参数名称是小写的了,且多个单词之间用 . 隔开。
第二种方法也不符合我的要求。我想通过代码里直接配置dockerhost或者通过配置文件的方式来修改docker主机地址。官网能提供的两种方法都不可行,我尝试去看一下testcontainer代码里到底是怎么取用docker服务地址的。
2、翻源码
我们直接翻到构建container的位置
可以看到是在org.testcontainers.containers.GenericContainer中定义的docker连接,
再进入client()方法
再进入org.testcontainers.DockerClientFactory的getOrInitializeStrategy方法
从这个里可以看到
默认加载了5种连接策略,其实我们之前设置的环境变量方式,就是使用的EnvironmentAndSystemPropertyClientProviderStrategy连接策略来实现的。
进入DockerClientProviderStrategy.getFirstValidStrategy(configurationStrategies)方法
再往下看就是对连接策略进行过滤
第一个filter是去重,
第二个filter是判断当前策略是否启用,需要由每个策略自行判断,否则固定返回true
第三个是验证改策略配置的docker地址是否可用。
然后找到所有条件都匹配的第一个策略。
这里再简单讲一下EnvironmentAndSystemPropertyClientProviderStrategy连接策略,
EnvironmentAndSystemPropertyClientProviderStrategy初始化的时候会获取环境变量中配置的dockerhost,如果配置了,上面的第二个filter才会返回true,所以必须是配置了dockerhost并且该地址是有效的才会使用此策略。
都看一遍后,发现五种连接策略都无法满足我们的要求,
通过上面加载连接策略的时候发现是通过 ServiceLoader.load() 加载的,因此我们可以添加自定义的加载策略,
ServiceLoader.load() 会通过MATE_INF/services下的文件来加载类,
因此我们在resource下创建此目录
在文件中添加我们自定义的连接策略,这样我们自定义的连接策略就会被加载进去了。
前面5个就是默认的5种连接策略。
接下来写我们自定义的连接策略代码
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientConfig;
import lombok.extern.slf4j.Slf4j;
import org.testcontainers.dockerclient.DockerClientProviderStrategy;
import org.testcontainers.dockerclient.TransportConfig;
/**
* testContainer的docker自定义连接策略
*/
@Slf4j
public class MyDockerClientProviderStrategy extends DockerClientProviderStrategy {
private final DockerClientConfig dockerClientConfig;
private static final String DOCKER_HOST = "tcp://192.168.61.14:2375";
/**
* 初始化的时候配置dockerClientConfig,我们通过docker-java来连接docker
*/
public MyDockerClientProviderStrategy() {
DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder();
configBuilder.withDockerHost(DOCKER_HOST);
// 开启dockerTLS校验
configBuilder.withDockerTlsVerify(true);
// 密钥所在文件夹,换到你的项目目录中即可
configBuilder.withDockerCertPath("C:\\Users\\Administrator\\Desktop\\docker");
dockerClientConfig = configBuilder.build();
}
/**
* 这里定义docker连接配置
*/
@Override
public TransportConfig getTransportConfig() {
return TransportConfig.builder()
.dockerHost(dockerClientConfig.getDockerHost())
.sslConfig(dockerClientConfig.getSSLConfig())
.build();
}
/**
* 对应上面第二个filter,固定返回true即可。
*/
@Override
protected boolean isApplicable() {
return true;
}
@Override
public String getDescription() {
return "my-custom-strategy";
}
}
如果DockerClientConfig 报红说明你需要引入
<!-- https://mvnrepository.com/artifact/com.github.docker-java/docker-java -->
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.2.13</version>
</dependency>
如果不需要开启TLS验证的话 ,上述代码中这些就可以去掉了
// 开启dockerTLS校验
configBuilder.withDockerTlsVerify(true);
// 密钥所在文件夹,换到你的项目目录中即可
configBuilder.withDockerCertPath("C:\\Users\\Administrator\\Desktop\\docker");
还有这个也不需要
sslConfig(dockerClientConfig.getSSLConfig())
到此,就结束了!