Gradle docker 图像无法连接到 mysql 测试容器
Gradle docker image can't connect to mysql testcontainer
我有一个使用 MySQL 测试容器的小型集成测试。
当我在本地构建时,运行使用简单的 gradlew 构建命令,运行s,测试并构建项目。但是当我尝试使用官方 gradle docker 图像时,测试停止等待 mysql 数据库可用。
当我构建 运行s 时,它创建了 3 个容器:
- Gradle 容器
- 码头.io/testcontainers/ryuk:0.2.3
- mysql:最新
我的 gradle 图像与官方图像不同,因为它安装了 docker:
FROM gradle
USER root
RUN apt-get update && \
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \
apt-key fingerprint 0EBFCD88 && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable" && \
apt-get update && \
apt-get install -y docker-ce docker-ce-cli containerd.io
当连接停止时,我连接到 gradle 图像,并安装了 mysql 客户端。我尝试连接到正在连接测试的同一图像,但连接没有问题。
有谁知道我做错了什么,因为只有 运行 在容器内构建我有这个问题?
我运行用这个:
docker container run -v /var/run/docker.sock:/var/run/docker.sock -v <local repo>:/home/gradle/project -w /home/gradle/project --rm mygradle gradle build -i
编辑:
这不是因为 gradle docker 图像,而是任何图像。如果我 运行 使用 Jenkins,并且它是一个容器,这也不起作用。尝试连接到 172.x.x.1(主机地址)和暴露的端口并且测试未连接,但是访问容器并使用 mysql 客户端尝试完全相同的连接,我可以连接。
我找到了解决方案。
我没有使用 MysqlContainer class,而是定义了一个新的 class 来扩展它。它将检测应用程序是否在容器内 运行,如果是,它会尝试在内部连接到数据库容器,而不是使用本地主机和生成的端口。
public static class IntegrationTestsDatabase<SELF extends MySQLContainer<SELF>> extends MySQLContainer<SELF> {
public IntegrationTestsDatabase() {
}
public IntegrationTestsDatabase(String dockerImageName) {
super(dockerImageName);
}
public String getJdbcUrl() {
String containerIp = ((ContainerNetwork)this.getContainerInfo().getNetworkSettings().getNetworks().values().stream().findFirst().get()).getIpAddress();
return this.isRunningInsideDocker() ? "jdbc:mysql://" + containerIp + ":" + MySQLContainer.MYSQL_PORT + "/" + this.getDatabaseName() : super.getJdbcUrl();
}
public Boolean isRunningInsideDocker() {
try {
Stream stream = Files.lines(Paths.get("/proc/1/cgroup"));
Boolean var2;
try {
var2 = stream.anyMatch((line) -> {
return line.contains("/docker");
});
} catch (Throwable var5) {
if (stream != null) {
try {
stream.close();
} catch (Throwable var4) {
var5.addSuppressed(var4);
}
}
throw var5;
}
if (stream != null) {
stream.close();
}
return var2;
} catch (IOException var6) {
return false;
}
}
}
这将适用于其他容器类型。
我有一个使用 MySQL 测试容器的小型集成测试。
当我在本地构建时,运行使用简单的 gradlew 构建命令,运行s,测试并构建项目。但是当我尝试使用官方 gradle docker 图像时,测试停止等待 mysql 数据库可用。
当我构建 运行s 时,它创建了 3 个容器:
- Gradle 容器
- 码头.io/testcontainers/ryuk:0.2.3
- mysql:最新
我的 gradle 图像与官方图像不同,因为它安装了 docker:
FROM gradle
USER root
RUN apt-get update && \
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \
apt-key fingerprint 0EBFCD88 && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable" && \
apt-get update && \
apt-get install -y docker-ce docker-ce-cli containerd.io
当连接停止时,我连接到 gradle 图像,并安装了 mysql 客户端。我尝试连接到正在连接测试的同一图像,但连接没有问题。 有谁知道我做错了什么,因为只有 运行 在容器内构建我有这个问题?
我运行用这个:
docker container run -v /var/run/docker.sock:/var/run/docker.sock -v <local repo>:/home/gradle/project -w /home/gradle/project --rm mygradle gradle build -i
编辑: 这不是因为 gradle docker 图像,而是任何图像。如果我 运行 使用 Jenkins,并且它是一个容器,这也不起作用。尝试连接到 172.x.x.1(主机地址)和暴露的端口并且测试未连接,但是访问容器并使用 mysql 客户端尝试完全相同的连接,我可以连接。
我找到了解决方案。
我没有使用 MysqlContainer class,而是定义了一个新的 class 来扩展它。它将检测应用程序是否在容器内 运行,如果是,它会尝试在内部连接到数据库容器,而不是使用本地主机和生成的端口。
public static class IntegrationTestsDatabase<SELF extends MySQLContainer<SELF>> extends MySQLContainer<SELF> {
public IntegrationTestsDatabase() {
}
public IntegrationTestsDatabase(String dockerImageName) {
super(dockerImageName);
}
public String getJdbcUrl() {
String containerIp = ((ContainerNetwork)this.getContainerInfo().getNetworkSettings().getNetworks().values().stream().findFirst().get()).getIpAddress();
return this.isRunningInsideDocker() ? "jdbc:mysql://" + containerIp + ":" + MySQLContainer.MYSQL_PORT + "/" + this.getDatabaseName() : super.getJdbcUrl();
}
public Boolean isRunningInsideDocker() {
try {
Stream stream = Files.lines(Paths.get("/proc/1/cgroup"));
Boolean var2;
try {
var2 = stream.anyMatch((line) -> {
return line.contains("/docker");
});
} catch (Throwable var5) {
if (stream != null) {
try {
stream.close();
} catch (Throwable var4) {
var5.addSuppressed(var4);
}
}
throw var5;
}
if (stream != null) {
stream.close();
}
return var2;
} catch (IOException var6) {
return false;
}
}
}
这将适用于其他容器类型。