Quarkus deployment module that provides automatic configuration and orchestration of development services using Docker Compose
—
Docker Compose file parsing, validation, and service definition extraction with support for multiple compose files and project naming.
Manages multiple compose files and aggregates their service definitions while handling project naming and service conflicts.
/**
* Container for multiple compose files with aggregated service definitions
*/
public class ComposeFiles {
/**
* Creates a ComposeFiles instance from a list of compose files
* @param composeFiles List of compose file objects to process
* @throws IllegalArgumentException If service name conflicts exist
*/
public ComposeFiles(List<File> composeFiles);
/**
* Gets all service names across all compose files
* @return Set of unique service names
*/
public Set<String> getAllServiceNames();
/**
* Gets all service definitions from all compose files
* @return Map of service name to service definition
*/
public Map<String, ComposeServiceDefinition> getServiceDefinitions();
/**
* Gets the project name from the compose files
* @return Project name or null if not specified
*/
public String getProjectName();
/**
* Gets the list of compose files
* @return List of File objects
*/
public List<File> getFiles();
}Usage Examples:
import io.quarkus.devservices.deployment.compose.*;
import java.io.File;
import java.util.List;
// Process multiple compose files
List<File> files = List.of(
new File("docker-compose.yml"),
new File("docker-compose.override.yml"),
new File("compose-dev-services.yml")
);
ComposeFiles composeFiles = new ComposeFiles(files);
// Get aggregated information
Set<String> allServices = composeFiles.getAllServiceNames();
Map<String, ComposeServiceDefinition> definitions = composeFiles.getServiceDefinitions();
String projectName = composeFiles.getProjectName();
// Process each service
for (String serviceName : allServices) {
ComposeServiceDefinition definition = definitions.get(serviceName);
System.out.println("Service: " + serviceName);
System.out.println("Container: " + definition.getContainerName());
System.out.println("Ports: " + definition.getPorts());
System.out.println("Labels: " + definition.getLabels());
System.out.println("Profiles: " + definition.getProfiles());
}
// Use in ComposeProject
ComposeProject project = new ComposeProject.Builder(composeFiles, "docker")
.withProject(projectName != null ? projectName : "default-project")
.build();Parses and validates individual Docker Compose files, extracting service definitions and project metadata.
/**
* Representation of a docker-compose file with parsing and validation
*/
public class ComposeFile {
/**
* Creates a ComposeFile by parsing the given file
* @param composeFile File object pointing to compose file
* @throws IllegalArgumentException If file cannot be parsed
*/
public ComposeFile(File composeFile);
/**
* Gets the project name specified in the compose file
* @return Project name or null if not specified
*/
public String getProjectName();
/**
* Gets all service definitions from this compose file
* @return Map of service name to service definition
*/
public Map<String, ComposeServiceDefinition> getServiceDefinitions();
}Usage Examples:
// Parse a single compose file
File composeFile = new File("docker-compose.yml");
ComposeFile compose = new ComposeFile(composeFile);
// Get project and service information
String projectName = compose.getProjectName();
Map<String, ComposeServiceDefinition> services = compose.getServiceDefinitions();
System.out.println("Project: " + (projectName != null ? projectName : "unnamed"));
System.out.println("Services found: " + services.size());
// Process each service
for (Map.Entry<String, ComposeServiceDefinition> entry : services.entrySet()) {
String serviceName = entry.getKey();
ComposeServiceDefinition definition = entry.getValue();
System.out.println("\nService: " + serviceName);
if (definition.getContainerName() != null) {
System.out.println(" Container: " + definition.getContainerName());
}
if (definition.hasHealthCheck()) {
System.out.println(" Has health check: true");
}
if (!definition.getPorts().isEmpty()) {
System.out.println(" Exposed ports: " + definition.getPorts());
}
if (!definition.getProfiles().isEmpty()) {
System.out.println(" Profiles: " + definition.getProfiles());
}
}
// Handle parsing errors
try {
ComposeFile invalidFile = new ComposeFile(new File("invalid.yml"));
} catch (IllegalArgumentException e) {
System.err.println("Failed to parse compose file: " + e.getMessage());
}Represents an individual service definition from a Docker Compose file with access to all service configuration.
/**
* Represents a service definition in a docker-compose file
*/
public class ComposeServiceDefinition {
/**
* Creates a service definition from compose data
* @param serviceName Name of the service
* @param definitionMap Raw service definition data from YAML
*/
public ComposeServiceDefinition(String serviceName, Map<String, ?> definitionMap);
/**
* Gets the service name
* @return Service name
*/
public String getServiceName();
/**
* Gets the container name if specified
* @return Container name or null if using default naming
*/
public String getContainerName();
/**
* Gets the exposed ports for this service
* @return List of ExposedPort objects, empty if no ports exposed
*/
public List<ExposedPort> getPorts();
/**
* Checks if the service has a health check defined
* @return true if health check is configured
*/
public boolean hasHealthCheck();
/**
* Gets all labels defined for this service
* @return Map of label keys to values, empty if no labels
*/
public Map<String, Object> getLabels();
/**
* Gets the profiles this service belongs to
* @return List of profile names, empty if no profiles
*/
public List<String> getProfiles();
}Usage Examples:
// Working with service definitions
ComposeServiceDefinition webService = serviceDefinitions.get("web");
// Basic service information
String serviceName = webService.getServiceName(); // "web"
String containerName = webService.getContainerName(); // "my-web-app" or null
// Port configuration
List<ExposedPort> ports = webService.getPorts();
for (ExposedPort port : ports) {
System.out.println("Exposed port: " + port.getPort());
}
// Health check configuration
if (webService.hasHealthCheck()) {
System.out.println("Service has health check configured");
// Health check details are handled by wait strategies
}
// Labels for configuration and wait strategies
Map<String, Object> labels = webService.getLabels();
String waitForLogs = (String) labels.get("quarkus.compose.wait-for.logs");
String portTimeout = (String) labels.get("quarkus.compose.wait-for.ports.timeout");
String configPort = (String) labels.get("quarkus.compose.config.port.8080");
if (waitForLogs != null) {
System.out.println("Wait for log message: " + waitForLogs);
}
// Profile-based conditional logic
List<String> profiles = webService.getProfiles();
boolean isDevService = profiles.contains("development");
boolean isTestService = profiles.contains("testing");
if (isDevService) {
System.out.println("Service is part of development profile");
}
// Creating service definitions programmatically (for testing)
Map<String, Object> serviceData = Map.of(
"image", "postgres:13",
"container_name", "dev-postgres",
"ports", List.of("5432:5432"),
"environment", Map.of("POSTGRES_PASSWORD", "secret"),
"labels", Map.of(
"quarkus.compose.config.port.5432", "DATABASE_URL",
"quarkus.compose.wait-for.logs", "database system is ready to accept connections"
),
"profiles", List.of("development", "testing")
);
ComposeServiceDefinition dbService = new ComposeServiceDefinition("database", serviceData);Implements Testcontainers wait strategy interface for compose services, providing container inspection and port information.
/**
* A WaitStrategyTarget that represents a container in a docker-compose file
*/
public class ComposeServiceWaitStrategyTarget implements WaitStrategyTarget, Supplier<InspectContainerResponse> {
/**
* Creates a wait strategy target for a compose service container
* @param dockerClient Docker client for container operations
* @param container Container information from Docker API
*/
public ComposeServiceWaitStrategyTarget(DockerClient dockerClient, Container container);
/**
* Gets the exposed ports for this container
* @return List of exposed port numbers
*/
@Override
public List<Integer> getExposedPorts();
/**
* Gets the container ID
* @return Full container ID
*/
@Override
public String getContainerId();
/**
* Gets the service name from compose labels
* @return Service name
*/
public String getServiceName();
/**
* Gets the container number within the service
* @return Container number (1-based)
*/
public int getContainerNumber();
/**
* Gets the formatted container name
* @return Container name in format "service-number"
*/
public String getContainerName();
/**
* Gets detailed container information
* @return Container inspection response
*/
@Override
public InspectContainerResponse getContainerInfo();
/**
* Supplier interface implementation
* @return Container inspection response
*/
@Override
public InspectContainerResponse get();
}Usage Examples:
// Working with service wait strategy targets
List<ComposeServiceWaitStrategyTarget> services = composeProject.getServices();
for (ComposeServiceWaitStrategyTarget service : services) {
// Basic service information
String serviceName = service.getServiceName();
String containerName = service.getContainerName();
String containerId = service.getContainerId();
int containerNumber = service.getContainerNumber();
System.out.println("Service: " + serviceName);
System.out.println("Container: " + containerName + " (" + containerId.substring(0, 12) + ")");
// Port information
List<Integer> exposedPorts = service.getExposedPorts();
System.out.println("Exposed ports: " + exposedPorts);
// Detailed container inspection
InspectContainerResponse containerInfo = service.getContainerInfo();
String imageName = containerInfo.getConfig().getImage();
String status = containerInfo.getState().getStatus();
System.out.println("Image: " + imageName);
System.out.println("Status: " + status);
// Network information
Map<String, NetworkSettings> networks = containerInfo.getNetworkSettings().getNetworks();
for (Map.Entry<String, NetworkSettings> network : networks.entrySet()) {
String networkName = network.getKey();
String ipAddress = network.getValue().getIpAddress();
System.out.println("Network: " + networkName + " -> " + ipAddress);
}
}
// Using as Testcontainers wait strategy target
WaitStrategy healthCheck = Wait.forHealthcheck();
WaitStrategy logMessage = Wait.forLogMessage("Server started", 1);
WaitStrategy httpEndpoint = Wait.forHttp("/health").forStatusCode(200);
for (ComposeServiceWaitStrategyTarget service : services) {
if (service.getServiceName().equals("web-api")) {
// Apply wait strategy
try {
httpEndpoint.waitUntilReady(service);
System.out.println("Web API service is ready");
} catch (Exception e) {
System.err.println("Web API failed to become ready: " + e.getMessage());
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-devservices-deployment