0
# Docker Compose Integration
1
2
Support for Docker Compose multi-container environments, enabling complex multi-service testing scenarios with service discovery, orchestration, and environment management using existing Docker Compose files.
3
4
## Capabilities
5
6
### DockerComposeContainer
7
8
Primary class for managing Docker Compose environments in tests, providing full lifecycle management and service discovery.
9
10
```java { .api }
11
/**
12
* Container for managing Docker Compose multi-service environments
13
* @param <SELF> Self-referencing type for fluent API
14
*/
15
public class DockerComposeContainer<SELF extends DockerComposeContainer<SELF>>
16
extends GenericContainer<SELF> {
17
18
/** Create from single compose file */
19
public DockerComposeContainer(File composeFile);
20
21
/** Create from multiple compose files */
22
public DockerComposeContainer(List<File> composeFiles);
23
24
/** Create from compose file resource */
25
public DockerComposeContainer(String composeFileResource);
26
27
/** Specify which services to start (default: all services) */
28
public SELF withServices(String... services);
29
30
/** Configure environment variables for compose */
31
public SELF withEnv(String key, String value);
32
public SELF withEnv(Map<String, String> env);
33
34
/** Configure compose file environment variable substitution */
35
public SELF withEnvFile(File envFile);
36
37
/** Configure Docker Compose profiles */
38
public SELF withProfiles(String... profiles);
39
40
/** Configure local Docker Compose binary */
41
public SELF withLocalCompose(boolean localCompose);
42
43
/** Configure compose options */
44
public SELF withOptions(String... options);
45
46
/** Configure build arguments */
47
public SELF withBuild(boolean build);
48
49
/** Configure pull policy */
50
public SELF withPull(boolean pull);
51
52
/** Configure remove orphans */
53
public SELF withRemoveOrphans(boolean removeOrphans);
54
55
/** Get service host address */
56
public String getServiceHost(String serviceName, int servicePort);
57
58
/** Get mapped port for service */
59
public Integer getServicePort(String serviceName, int servicePort);
60
61
/** Get service container by name */
62
public ContainerState getServiceContainer(String serviceName);
63
64
/** Get all service containers */
65
public Map<String, ContainerState> getServiceContainers();
66
67
/** Execute command in specific service */
68
public Container.ExecResult execInService(String serviceName, String... command)
69
throws IOException, InterruptedException;
70
71
/** Get logs from specific service */
72
public String getServiceLogs(String serviceName);
73
}
74
```
75
76
**Usage Examples:**
77
78
```java
79
import org.testcontainers.containers.DockerComposeContainer;
80
import java.io.File;
81
82
// Basic Docker Compose setup
83
DockerComposeContainer<?> compose = new DockerComposeContainer<>(
84
new File("src/test/resources/docker-compose.yml"))
85
.withServices("web", "database")
86
.withExposedService("web", 8080)
87
.withExposedService("database", 5432);
88
89
compose.start();
90
91
// Access services
92
String webHost = compose.getServiceHost("web", 8080);
93
Integer webPort = compose.getServicePort("web", 8080);
94
String webUrl = "http://" + webHost + ":" + webPort;
95
96
String dbHost = compose.getServiceHost("database", 5432);
97
Integer dbPort = compose.getServicePort("database", 5432);
98
```
99
100
### Compose File Management
101
102
Utilities for working with Docker Compose files and configurations.
103
104
```java { .api }
105
/**
106
* Utilities for Docker Compose file handling
107
*/
108
public class DockerComposeFiles {
109
110
/** Load compose file from classpath */
111
public static File fromClasspath(String resource);
112
113
/** Load multiple compose files */
114
public static List<File> fromClasspath(String... resources);
115
116
/** Create temporary compose file from content */
117
public static File fromContent(String composeContent);
118
119
/** Merge multiple compose configurations */
120
public static File merge(File... composeFiles);
121
}
122
123
/**
124
* Parsed Docker Compose file representation
125
*/
126
public class ParsedDockerComposeFile {
127
128
public ParsedDockerComposeFile(File composeFile);
129
130
/** Get all service names */
131
public Set<String> getServiceNames();
132
133
/** Get service configuration */
134
public Map<String, Object> getServiceConfig(String serviceName);
135
136
/** Get service ports */
137
public List<Integer> getServicePorts(String serviceName);
138
139
/** Get service environment variables */
140
public Map<String, String> getServiceEnv(String serviceName);
141
142
/** Check if service exists */
143
public boolean hasService(String serviceName);
144
145
/** Get compose file version */
146
public String getComposeVersion();
147
}
148
```
149
150
### Local Docker Compose
151
152
Support for using local Docker Compose binary instead of embedded compose functionality.
153
154
```java { .api }
155
/**
156
* Local Docker Compose execution support
157
*/
158
public class LocalDockerCompose {
159
160
public LocalDockerCompose(File... composeFiles);
161
public LocalDockerCompose(List<File> composeFiles);
162
163
/** Configure environment variables */
164
public LocalDockerCompose withEnv(String key, String value);
165
public LocalDockerCompose withEnv(Map<String, String> env);
166
167
/** Configure services to start */
168
public LocalDockerCompose withServices(String... services);
169
170
/** Configure Docker Compose command options */
171
public LocalDockerCompose withCommand(String... command);
172
173
/** Start services */
174
public LocalDockerCompose up();
175
176
/** Stop services */
177
public LocalDockerCompose down();
178
179
/** Execute compose command */
180
public LocalDockerCompose invoke(String... args);
181
182
/** Get service information */
183
public String getServiceHost(String serviceName, int servicePort);
184
public Integer getServicePort(String serviceName, int servicePort);
185
}
186
```
187
188
### Compose Container Extensions
189
190
Extended container functionality for compose environments.
191
192
```java { .api }
193
/**
194
* Enhanced compose container with additional service management
195
*/
196
public class ComposeContainer extends DockerComposeContainer<ComposeContainer> {
197
198
public ComposeContainer(File... composeFiles);
199
200
/** Wait for specific service to be ready */
201
public ComposeContainer waitingForService(String serviceName, WaitStrategy waitStrategy);
202
203
/** Configure service-specific wait strategies */
204
public ComposeContainer withServiceWaitStrategy(String serviceName, WaitStrategy waitStrategy);
205
206
/** Scale service to specific number of instances */
207
public ComposeContainer withServiceScale(String serviceName, int scale);
208
209
/** Get all instances of a scaled service */
210
public List<ContainerState> getServiceInstances(String serviceName);
211
212
/** Execute command across all service instances */
213
public List<Container.ExecResult> execInAllServiceInstances(String serviceName, String... command);
214
}
215
```
216
217
## Advanced Docker Compose Patterns
218
219
### Multi-File Compose Setup
220
221
Using multiple compose files for different environments and configurations:
222
223
```java
224
@Test
225
public void testWithMultipleComposeFiles() {
226
DockerComposeContainer<?> compose = new DockerComposeContainer<>(
227
Arrays.asList(
228
new File("docker-compose.base.yml"),
229
new File("docker-compose.test.yml"),
230
new File("docker-compose.override.yml")
231
))
232
.withServices("app", "database", "redis")
233
.withEnv("ENVIRONMENT", "test")
234
.withProfiles("testing");
235
236
compose.start();
237
238
// Test services
239
testApplication(compose.getServiceHost("app", 8080),
240
compose.getServicePort("app", 8080));
241
}
242
```
243
244
### Service Dependencies and Ordering
245
246
Managing service startup order and dependencies:
247
248
```java
249
@Test
250
public void testServiceDependencies() {
251
DockerComposeContainer<?> compose = new DockerComposeContainer<>(
252
new File("docker-compose.yml"))
253
// Database must be ready before application
254
.waitingForService("database", Wait.forListeningPort())
255
.waitingForService("redis", Wait.forListeningPort())
256
// Application waits for both database and redis
257
.waitingForService("app", Wait.forHttp("/health").forStatusCode(200))
258
.withStartupTimeout(Duration.ofMinutes(5));
259
260
compose.start();
261
262
// All services are now ready in correct order
263
}
264
```
265
266
### Environment-Specific Configuration
267
268
Using environment variables and profiles for different test scenarios:
269
270
```java
271
@Test
272
public void testProductionLikeEnvironment() {
273
DockerComposeContainer<?> compose = new DockerComposeContainer<>(
274
new File("docker-compose.yml"))
275
.withEnv("DATABASE_URL", "postgresql://db:5432/prodlike")
276
.withEnv("REDIS_URL", "redis://cache:6379")
277
.withEnv("LOG_LEVEL", "DEBUG")
278
.withProfiles("production", "monitoring")
279
.withServices("app", "database", "redis", "monitoring");
280
281
compose.start();
282
283
// Test production-like configuration
284
}
285
```
286
287
### Service Scaling and Load Testing
288
289
Testing with multiple instances of services:
290
291
```java
292
@Test
293
public void testServiceScaling() {
294
ComposeContainer compose = new ComposeContainer(
295
new File("docker-compose.yml"))
296
.withServiceScale("worker", 3) // Scale worker service to 3 instances
297
.withServiceScale("app", 2) // Scale app service to 2 instances
298
.waitingForService("app", Wait.forHttp("/health"));
299
300
compose.start();
301
302
// Get all app instances
303
List<ContainerState> appInstances = compose.getServiceInstances("app");
304
assertEquals(2, appInstances.size());
305
306
// Test load balancing across instances
307
for (ContainerState instance : appInstances) {
308
String url = "http://" + instance.getHost() + ":" + instance.getMappedPort(8080);
309
// Test each instance
310
}
311
}
312
```
313
314
### Custom Compose File Generation
315
316
Generating compose files dynamically for test scenarios:
317
318
```java
319
@Test
320
public void testDynamicComposeFile() {
321
String composeContent = """
322
version: '3.8'
323
services:
324
app:
325
image: myapp:latest
326
ports:
327
- "8080"
328
environment:
329
- DATABASE_URL=postgresql://db:5432/testdb
330
- REDIS_URL=redis://cache:6379
331
depends_on:
332
- db
333
- cache
334
db:
335
image: postgres:13
336
environment:
337
POSTGRES_DB: testdb
338
POSTGRES_USER: test
339
POSTGRES_PASSWORD: test
340
ports:
341
- "5432"
342
cache:
343
image: redis:alpine
344
ports:
345
- "6379"
346
""";
347
348
File tempCompose = DockerComposeFiles.fromContent(composeContent);
349
350
DockerComposeContainer<?> compose = new DockerComposeContainer<>(tempCompose)
351
.withServices("app", "db", "cache");
352
353
compose.start();
354
355
// Test the dynamically created environment
356
}
357
```
358
359
### Integration with TestContainers Networks
360
361
Combining Docker Compose with TestContainers networks:
362
363
```java
364
@Test
365
public void testComposeWithCustomNetwork() {
366
try (Network testNetwork = Network.newNetwork()) {
367
368
DockerComposeContainer<?> compose = new DockerComposeContainer<>(
369
new File("docker-compose.yml"))
370
.withNetwork(testNetwork)
371
.withServices("app", "database");
372
373
// Additional container in same network
374
GenericContainer<?> monitor = new GenericContainer<>("monitoring:latest")
375
.withNetwork(testNetwork)
376
.withNetworkAliases("monitor")
377
.withExposedPorts(9090);
378
379
compose.start();
380
monitor.start();
381
382
// All containers can communicate within the network
383
}
384
}
385
```
386
387
### Compose File Validation and Debugging
388
389
```java
390
@Test
391
public void testComposeFileValidation() {
392
File composeFile = new File("docker-compose.yml");
393
ParsedDockerComposeFile parsed = new ParsedDockerComposeFile(composeFile);
394
395
// Validate compose file structure
396
assertTrue(parsed.hasService("app"));
397
assertTrue(parsed.hasService("database"));
398
399
// Check service configuration
400
List<Integer> appPorts = parsed.getServicePorts("app");
401
assertTrue(appPorts.contains(8080));
402
403
Map<String, String> dbEnv = parsed.getServiceEnv("database");
404
assertEquals("testdb", dbEnv.get("POSTGRES_DB"));
405
406
// Create container with validated configuration
407
DockerComposeContainer<?> compose = new DockerComposeContainer<>(composeFile)
408
.withServices(parsed.getServiceNames().toArray(new String[0]));
409
}
410
```