Reputation: 371
I have a small integration test that uses MySQL Test container.
When I build locally, running the simple gradlew build command, it runs, test and builds the project. But when I try to use the official gradle docker image, the test stalls waiting for the availability of the mysql database.
When my build runs, it creates 3 containers:
My gradle image is different from the official one, because it has docker installed:
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
When the connection was stalled, I connected to the gradle image, and I installed the mysql client. I tried to connect to the same image the tests are being connected and I had no problem to connect. Does anyone has any idea on what I'm doing wrong, since only running the build inside the container I have this problem?
I run with this:
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
Edit: This is not because of the gradle docker image, but any image. If I run using the Jenkins, and it being a container, this doesn't work also. Tries to connect to the 172.x.x.1 (host address) and the port exposed and the Test doesn't connect, but accessing the container, and trying the same exact connection using the mysql client, I can connect.
Upvotes: 1
Views: 1197
Reputation: 371
I found a solution for this.
Instead of using the MysqlContainer class, I defined a new class extending this one. It will detect if the application is running inside a container, and if so, it tries to connect to the database container internally, instead of using the localhost and the generated port.
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;
}
}
}
This will work with other container types.
Upvotes: 1