Quarkus deployment module that provides automatic configuration and orchestration of development services using Docker Compose
—
Complete Docker Compose project lifecycle management including service discovery, startup orchestration, health checking, and configuration extraction.
Core class that wraps Docker Compose functionality and manages the complete lifecycle of compose-based services including startup, health checking, and shutdown.
/**
* A wrapper around compose that starts and stops services defined in a set of compose files
*/
public class ComposeProject {
/**
* Constructor for ComposeProject with full configuration
* @param dockerClient Docker client for container operations
* @param composeFiles Compose files to manage
* @param executable Compose executable name (docker or podman)
* @param project Project name for compose services
* @param startupTimeout Maximum time to wait for service startup
* @param stopTimeout Maximum time to wait for service shutdown
* @param stopContainers Whether to stop containers on shutdown
* @param ryukEnabled Whether to enable Ryuk for cleanup
* @param followContainerLogs Whether to follow container logs
* @param removeVolumes Whether to remove volumes on shutdown
* @param removeImages Image removal strategy
* @param build Whether to build images before starting
* @param options Additional compose command options
* @param profiles Compose profiles to activate
* @param scalingPreferences Service scaling configuration
* @param env Environment variables
*/
public ComposeProject(
DockerClient dockerClient,
ComposeFiles composeFiles,
String executable,
String project,
Duration startupTimeout,
Duration stopTimeout,
boolean stopContainers,
boolean ryukEnabled,
boolean followContainerLogs,
boolean removeVolumes,
String removeImages,
Boolean build,
List<String> options,
List<String> profiles,
Map<String, Integer> scalingPreferences,
Map<String, String> env);
/**
* Gets the project name
* @return Project name
*/
public String getProject();
/**
* Starts all services defined in the compose files
*/
public synchronized void start();
/**
* Waits until all services are ready according to their wait strategies
* @param waitOn Executor for parallel waiting, null for default
*/
public void waitUntilServicesReady(Executor waitOn);
/**
* Combines start and wait operations
* @param waitOn Executor for parallel waiting
*/
public void startAndWaitUntilServicesReady(Executor waitOn);
/**
* Stops all services and cleans up resources
*/
public synchronized void stop();
/**
* Discovers running service instances
* @param checkForRequiredServices Whether to validate required services are running
*/
public synchronized void discoverServiceInstances(boolean checkForRequiredServices);
/**
* Runs a compose command with environment variables
* @param cmd Command to execute
* @param env Environment variables
*/
public void runWithCompose(String cmd, Map<String, String> env);
/**
* Gets list of running service instances
* @return List of service wait strategy targets
*/
public List<ComposeServiceWaitStrategyTarget> getServices();
/**
* Gets environment variable configuration from services
* @return Map of environment variable names to values
*/
public Map<String, String> getEnvVarConfig();
/**
* Gets exposed port configuration from services
* @return Map of configuration keys to port values
*/
public Map<String, String> getExposedPortConfig();
/**
* Gets list of Docker networks created by compose
* @return List of networks
*/
public List<Network> getNetworks();
/**
* Gets the default network ID for service communication
* @return Default network ID or fallback name
*/
public String getDefaultNetworkId();
}Usage Examples:
import io.quarkus.devservices.deployment.compose.*;
import java.time.Duration;
import java.util.concurrent.Executors;
// Create and start a compose project
List<File> composeFiles = List.of(new File("docker-compose.yml"));
ComposeFiles files = new ComposeFiles(composeFiles);
ComposeProject project = new ComposeProject.Builder(files, "docker")
.withProject("my-dev-services")
.withStartupTimeout(Duration.ofMinutes(2))
.withStopContainers(true)
.withRyukEnabled(true)
.withFollowContainerLogs(true)
.withEnv(Map.of("POSTGRES_PASSWORD", "secret"))
.build();
// Start services and wait for readiness
project.start();
project.waitUntilServicesReady(Executors.newCachedThreadPool());
// Get service information
String projectName = project.getProject();
List<ComposeServiceWaitStrategyTarget> services = project.getServices();
Map<String, String> envConfig = project.getEnvVarConfig();
Map<String, String> portConfig = project.getExposedPortConfig();
// Use configuration
String dbUrl = portConfig.get("DATABASE_URL");
String dbUser = envConfig.get("DB_USER");
// Cleanup when done
project.stop();Fluent builder pattern for creating ComposeProject instances with extensive configuration options.
/**
* Builder for ComposeProject with fluent configuration
*/
public static class Builder {
/**
* Creates a new builder with required parameters
* @param files Compose files to manage
* @param executable Compose executable name
*/
public Builder(ComposeFiles files, String executable);
/**
* Sets the docker client to use
* @param dockerClient Docker client instance
* @return This builder
*/
public Builder withDockerClient(DockerClient dockerClient);
/**
* Sets the project name
* @param project Project name for compose services
* @return This builder
*/
public Builder withProject(String project);
/**
* Sets whether to stop containers on shutdown
* @param stopContainers Stop containers flag
* @return This builder
*/
public Builder withStopContainers(boolean stopContainers);
/**
* Sets whether to enable Ryuk for cleanup
* @param ryukEnabled Ryuk enabled flag
* @return This builder
*/
public Builder withRyukEnabled(boolean ryukEnabled);
/**
* Sets the startup timeout
* @param duration Maximum startup time
* @return This builder
*/
public Builder withStartupTimeout(Duration duration);
/**
* Sets the stop timeout
* @param duration Maximum stop time
* @return This builder
*/
public Builder withStopTimeout(Duration duration);
/**
* Sets whether to build images before starting
* @param build Build images flag
* @return This builder
*/
public Builder withBuild(Boolean build);
/**
* Sets environment variables
* @param envVariables Environment variable map
* @return This builder
*/
public Builder withEnv(Map<String, String> envVariables);
/**
* Sets compose command options
* @param options List of command options
* @return This builder
*/
public Builder withOptions(List<String> options);
/**
* Sets compose profiles to activate
* @param profiles List of profile names
* @return This builder
*/
public Builder withProfiles(List<String> profiles);
/**
* Sets service scaling preferences
* @param scalingPreferences Map of service name to replica count
* @return This builder
*/
public Builder withScalingPreferences(Map<String, Integer> scalingPreferences);
/**
* Sets whether to follow container logs
* @param followContainerLogs Follow logs flag
* @return This builder
*/
public Builder withFollowContainerLogs(boolean followContainerLogs);
/**
* Sets image removal strategy
* @param removeImages Image removal option
* @return This builder
*/
public Builder withRemoveImages(String removeImages);
/**
* Sets whether to remove volumes on shutdown
* @param removeVolumes Remove volumes flag
* @return This builder
*/
public Builder withRemoveVolumes(boolean removeVolumes);
/**
* Builds the ComposeProject instance
* @return Configured ComposeProject
*/
public ComposeProject build();
}Usage Examples:
// Minimal configuration
ComposeProject minimal = new ComposeProject.Builder(composeFiles, "docker")
.withProject("my-project")
.build();
// Full configuration with all options
ComposeProject full = new ComposeProject.Builder(composeFiles, "podman")
.withProject("full-config-project")
.withStartupTimeout(Duration.ofMinutes(5))
.withStopTimeout(Duration.ofSeconds(30))
.withStopContainers(true)
.withRyukEnabled(false)
.withBuild(true)
.withFollowContainerLogs(true)
.withRemoveVolumes(true)
.withRemoveImages("all")
.withEnv(Map.of(
"POSTGRES_DB", "testdb",
"POSTGRES_USER", "test",
"POSTGRES_PASSWORD", "secret"
))
.withProfiles(List.of("development", "testing"))
.withOptions(List.of("--compatibility", "--verbose"))
.withScalingPreferences(Map.of("web", 2, "worker", 3))
.build();
// Configure for testing environment
ComposeProject testing = new ComposeProject.Builder(composeFiles, "docker")
.withProject("test-services")
.withStartupTimeout(Duration.ofMinutes(1))
.withRyukEnabled(true)
.withBuild(false)
.withProfiles(List.of("test"))
.build();Executes Docker Compose commands with proper environment setup and error handling, providing a fluent interface for running arbitrary compose operations.
/**
* A class that runs compose commands with proper environment setup
*/
public class ComposeRunner {
/**
* Creates a new compose runner
* @param composeExecutable Executable name (docker, podman, etc.)
* @param composeFiles List of compose files
* @param projectName Project name for compose
*/
public ComposeRunner(String composeExecutable, List<File> composeFiles, String projectName);
/**
* Sets the compose command to run
* @param cmd Command string with arguments
* @return This runner
*/
public ComposeRunner withCommand(String cmd);
/**
* Sets environment variables for the command
* @param env Environment variable map
* @return This runner
*/
public ComposeRunner withEnv(Map<String, String> env);
/**
* Sets compose profiles to use
* @param profiles List of profile names
* @return This runner
*/
public ComposeRunner withProfiles(List<String> profiles);
/**
* Sets additional compose options
* @param options List of command-line options
* @return This runner
*/
public ComposeRunner withOptions(List<String> options);
/**
* Executes the compose command
* @throws RuntimeException If command fails or compose not found
*/
public void run();
/**
* Executes the compose command and returns output
* @return Command output as string
* @throws RuntimeException If command fails or compose not found
*/
public String runAndGetOutput();
/**
* Checks if the compose executable is available
* @param executable Executable name to check
* @return true if executable is found in PATH
*/
public static boolean isComposeAvailable(String executable);
}Usage Examples:
// Basic compose command execution
ComposeRunner runner = new ComposeRunner("docker", composeFiles, "my-project");
runner.withCommand("up -d")
.withEnv(Map.of("POSTGRES_PASSWORD", "secret"))
.run();
// Running with profiles and custom environment
new ComposeRunner("podman", composeFiles, "dev-project")
.withCommand("up --build")
.withProfiles(List.of("development", "debug"))
.withEnv(Map.of(
"API_KEY", "dev-key",
"LOG_LEVEL", "debug",
"REDIS_PASSWORD", "redis-secret"
))
.run();
// Getting command output for inspection
String status = new ComposeRunner("docker", composeFiles, "status-check")
.withCommand("ps --format json")
.runAndGetOutput();
System.out.println("Service status: " + status);
// Using additional options with command
new ComposeRunner("docker", composeFiles, "advanced-project")
.withCommand("up")
.withOptions(List.of("--compatibility", "--abort-on-container-exit"))
.withEnv(Map.of("COMPOSE_HTTP_TIMEOUT", "120"))
.run();
// Check if compose is available before running
if (ComposeRunner.isComposeAvailable("docker")) {
new ComposeRunner("docker", composeFiles, "my-project")
.withCommand("up -d")
.run();
} else if (ComposeRunner.isComposeAvailable("podman")) {
new ComposeRunner("podman", composeFiles, "my-project")
.withCommand("up -d")
.run();
} else {
throw new RuntimeException("No compatible compose executable found");
}
// Stopping services with cleanup
new ComposeRunner("docker", composeFiles, "test-project")
.withCommand("down -v --rmi all")
.run();// Default network name
public static final String DEFAULT_NETWORK_NAME = "default";
// Environment variable names used by ComposeRunner
private static final String DOCKER_HOST_ENV = "DOCKER_HOST";
private static final String DOCKER_CERT_PATH_ENV = "DOCKER_CERT_PATH";
private static final String DOCKER_TLS_VERIFY_ENV = "DOCKER_TLS_VERIFY";
private static final String PROJECT_NAME_ENV = "COMPOSE_PROJECT_NAME";
private static final String COMPOSE_FILE_ENV = "COMPOSE_FILE";
private static final String COMPOSE_PROFILES_ENV = "COMPOSE_PROFILES";Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-devservices-deployment