Skip to content

Commit e03cf13

Browse files
committed
Replace links usage with networks
Links has been deprecated. This commit make changes to attach compose networks to ambassadador container. Fixes #5351
1 parent d895c90 commit e03cf13

File tree

3 files changed

+88
-11
lines changed

3 files changed

+88
-11
lines changed

core/src/main/java/org/testcontainers/containers/ComposeDelegate.java

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,26 @@ List<Container> listChildContainers() {
261261
void startAmbassadorContainer() {
262262
if (!this.ambassadorPortMappings.isEmpty()) {
263263
this.ambassadorContainer.start();
264+
connectAmbassadorToComposeNetworks();
265+
}
266+
}
267+
268+
private void connectAmbassadorToComposeNetworks() {
269+
Set<String> composeNetworkIds = listChildContainers()
270+
.stream()
271+
.filter(container ->
272+
container.getNetworkSettings() != null && container.getNetworkSettings().getNetworks() != null
273+
)
274+
.flatMap(container -> container.getNetworkSettings().getNetworks().entrySet().stream())
275+
.filter(entry -> !Arrays.asList("bridge", "host", "none").contains(entry.getKey()))
276+
.map(entry -> entry.getValue().getNetworkID())
277+
.collect(Collectors.toSet());
278+
279+
for (String composeNetworkId : composeNetworkIds) {
280+
this.dockerClient.connectToNetworkCmd()
281+
.withContainerId(this.ambassadorContainer.getContainerId())
282+
.withNetworkId(composeNetworkId)
283+
.exec();
264284
}
265285
}
266286

@@ -282,27 +302,25 @@ public void withExposedService(String serviceName, int servicePort, @NonNull Wai
282302
/*
283303
* For every service/port pair that needs to be exposed, we register a target on an 'ambassador container'.
284304
*
285-
* The ambassador container's role is to link (within the Docker network) to one of the
286-
* compose services, and proxy TCP network I/O out to a port that the ambassador container
287-
* exposes.
305+
* The ambassador container's role is to proxy TCP network I/O from one of the compose
306+
* services out to a port that the ambassador container exposes.
307+
*
308+
* After Docker Compose starts, the ambassador container is connected to the compose
309+
* network so it can resolve service names via Docker's built-in DNS.
288310
*
289311
* This avoids the need for the docker compose file to explicitly expose ports on all the
290312
* services.
291-
*
292-
* {@link GenericContainer} should ensure that the ambassador container is on the same network
293-
* as the rest of the compose environment.
294313
*/
295314

296315
// Ambassador container will be started together after docker compose has started
297316
int ambassadorPort = nextAmbassadorPort.getAndIncrement();
298317
ambassadorPortMappings
299318
.computeIfAbsent(serviceInstanceName, __ -> new ConcurrentHashMap<>())
300319
.put(servicePort, ambassadorPort);
301-
ambassadorContainer.withTarget(ambassadorPort, serviceInstanceName, servicePort);
302-
ambassadorContainer.addLink(
303-
new FutureContainer(this.project + this.composeSeparator + serviceInstanceName),
304-
serviceInstanceName
305-
);
320+
// Use the full container name as the socat target so Docker DNS can resolve it
321+
// on the compose network (e.g., "project-redis-1" instead of just "redis-1")
322+
String containerName = this.project + this.composeSeparator + serviceInstanceName;
323+
ambassadorContainer.withTarget(ambassadorPort, containerName, servicePort);
306324
addWaitStrategy(serviceInstanceName, waitStrategy);
307325
}
308326

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.testcontainers.junit;
2+
3+
import org.junit.jupiter.api.AutoClose;
4+
import org.junit.jupiter.api.Test;
5+
import org.testcontainers.containers.ComposeContainer;
6+
import org.testcontainers.utility.DockerImageName;
7+
import redis.clients.jedis.Jedis;
8+
9+
import java.io.File;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
13+
class ComposeWithMultipleNetworkTest extends BaseComposeTest {
14+
15+
@AutoClose
16+
public ComposeContainer environment = new ComposeContainer(
17+
DockerImageName.parse("docker:25.0.5"),
18+
new File("src/test/resources/v2-compose-test-with-multiple-networks.yml")
19+
)
20+
.withExposedService("redis-1", REDIS_PORT)
21+
.withExposedService("another-redis-1", REDIS_PORT);
22+
23+
ComposeWithMultipleNetworkTest() {
24+
environment.start();
25+
}
26+
27+
@Override
28+
protected ComposeContainer getEnvironment() {
29+
return environment;
30+
}
31+
32+
@Test
33+
void redisInstanceInDifferentNetworkCanBeUsed() {
34+
Jedis jedis = new Jedis(
35+
getEnvironment().getServiceHost("another-redis-1", REDIS_PORT),
36+
getEnvironment().getServicePort("another-redis-1", REDIS_PORT)
37+
);
38+
39+
jedis.incr("test");
40+
jedis.incr("test");
41+
jedis.incr("test");
42+
43+
assertThat(jedis.get("test")).as("A redis instance defined in compose can be used in isolation").isEqualTo("3");
44+
}
45+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
version: '2.1'
2+
services:
3+
redis:
4+
image: redis
5+
networks:
6+
- redis-net
7+
another-redis:
8+
image: redis
9+
networks:
10+
- another-redis-net
11+
12+
networks:
13+
redis-net:
14+
another-redis-net:

0 commit comments

Comments
 (0)