Gradle docker 图像无法连接到 mysql 测试容器

Gradle docker image can't connect to mysql testcontainer

我有一个使用 MySQL 测试容器的小型集成测试。

当我在本地构建时,运行使用简单的 gradlew 构建命令,运行s,测试并构建项目。但是当我尝试使用官方 gradle docker 图像时,测试停止等待 mysql 数据库可用。

当我构建 运行s 时,它创建了 3 个容器:

我的 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;
        }
    }
}

这将适用于其他容器类型。