Skip to content

Commit adae983

Browse files
Fix KafkaContainer with multiple networks defined (#4213)
Current implementation exposes only two listeners PLAINTEXT and BROKER. BROKER must be advertised to explicitly specified network or bridge. If a host port is exposed using `Testcontainers.exposeHostPorts` and a network is specified, the container will be "attached" to an additional network, creating to listeners with the same name Configure the BROKER listener using the network specified (withNetwork) or "bridge" if not specified, instead of iterating over all the networks in the container info. Additional test cases when a port of the host is exposed (proxy container started) and a external network is specified to the container placing multiple network entries in the container info, making additional Kafka Broker listener entries with the same name "BROKER" Co-authored-by: Sergei Egorov <[email protected]>
1 parent 655110a commit adae983

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
import org.testcontainers.utility.DockerImageName;
77

88
import java.nio.charset.StandardCharsets;
9-
import java.util.stream.Collectors;
10-
import java.util.stream.Stream;
9+
import java.util.Comparator;
1110

1211
/**
1312
* This container wraps Confluent Kafka and Zookeeper (optionally)
@@ -122,13 +121,8 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole
122121
}
123122

124123
command += "export KAFKA_ZOOKEEPER_CONNECT='" + zookeeperConnect + "'\n";
125-
command += "export KAFKA_ADVERTISED_LISTENERS='" + Stream
126-
.concat(
127-
Stream.of(getBootstrapServers()),
128-
containerInfo.getNetworkSettings().getNetworks().values().stream()
129-
.map(it -> "BROKER://" + it.getIpAddress() + ":9092")
130-
)
131-
.collect(Collectors.joining(",")) + "'\n";
124+
125+
command += "export KAFKA_ADVERTISED_LISTENERS='" + String.join(",", getBootstrapServers(), brokerAdvertisedListener(containerInfo)) + "'\n";
132126

133127
command += ". /etc/confluent/docker/bash-config \n";
134128
command += "/etc/confluent/docker/configure \n";
@@ -139,4 +133,30 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole
139133
STARTER_SCRIPT
140134
);
141135
}
136+
137+
protected String brokerAdvertisedListener(InspectContainerResponse containerInfo) {
138+
// Kafka supports only one INTER_BROKER listener, so we have to pick one.
139+
// The current algorithm uses the following order of resolving the IP:
140+
// 1. Custom network's IP set via `withNetwork`
141+
// 2. Bridge network's IP
142+
// 3. Best effort fallback to getNetworkSettings#ipAddress
143+
String ipAddress = containerInfo.getNetworkSettings().getNetworks().entrySet()
144+
.stream()
145+
.filter(it -> it.getValue().getIpAddress() != null)
146+
.max(Comparator.comparingInt(entry -> {
147+
if (getNetwork() != null && getNetwork().getId().equals(entry.getValue().getNetworkID())) {
148+
return 2;
149+
}
150+
151+
if ("bridge".equals(entry.getKey())) {
152+
return 1;
153+
}
154+
155+
return 0;
156+
}))
157+
.map(it -> it.getValue().getIpAddress())
158+
.orElseGet(() -> containerInfo.getNetworkSettings().getIpAddress());
159+
160+
return String.format("BROKER://%s:%s", ipAddress, "9092");
161+
}
142162
}

modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.junit.ClassRule;
2525
import org.junit.Test;
2626
import org.rnorth.ducttape.unreliables.Unreliables;
27+
import org.testcontainers.Testcontainers;
2728
import org.testcontainers.utility.DockerImageName;
2829

2930
public class KafkaContainerTest {
@@ -113,6 +114,24 @@ public void testConfluentPlatformVersion6() throws Exception {
113114
}
114115
}
115116

117+
@Test
118+
public void testWithHostExposedPort() throws Exception {
119+
Testcontainers.exposeHostPorts(12345);
120+
try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE)) {
121+
kafka.start();
122+
testKafkaFunctionality(kafka.getBootstrapServers());
123+
}
124+
}
125+
126+
@Test
127+
public void testWithHostExposedPortAndExternalNetwork() throws Exception {
128+
Testcontainers.exposeHostPorts(12345);
129+
try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE).withNetwork(Network.newNetwork())) {
130+
kafka.start();
131+
testKafkaFunctionality(kafka.getBootstrapServers());
132+
}
133+
}
134+
116135
protected void testKafkaFunctionality(String bootstrapServers) throws Exception {
117136
testKafkaFunctionality(bootstrapServers, 1, 1);
118137
}

0 commit comments

Comments
 (0)