or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdcontainer-lifecycle.mddocker-client.mddocker-compose.mdimage-building.mdimage-management.mdimage-pull-policies.mdindex.mdjunit-jupiter-integration.mdlifecycle.mdmodules-overview.mdnetwork-configuration.mdoutput-handling.mdstartup-checks.mdutility-classes.mdwait-strategies.md
tile.json

container-lifecycle.mddocs/

Container Lifecycle and Configuration

Core container management functionality for creating, configuring, starting, and managing Docker containers in tests. The GenericContainer class serves as the foundation of Testcontainers, providing a fluent API for all container operations.

Capabilities

GenericContainer Class

The main workhorse class providing complete container lifecycle management with a fluent configuration API.

/**
 * Base class for all Testcontainers. Provides fluent API for container configuration
 * and lifecycle management.
 *
 * @param <SELF> Self-referential generic type for type-safe method chaining in subclasses
 */
public class GenericContainer<SELF extends GenericContainer<SELF>>
    implements Container<SELF>, AutoCloseable, WaitStrategyTarget, Startable {

    // Constructors
    public GenericContainer(DockerImageName dockerImageName);
    public GenericContainer(RemoteDockerImage image);
    public GenericContainer(String dockerImageName);
    public GenericContainer(Future<String> image);
    @Deprecated
    public GenericContainer();  // No-args constructor (deprecated)

    // Constants
    /** Default timeout in seconds for waiting for container to be in running state */
    public static final int CONTAINER_RUNNING_TIMEOUT_SEC = 30;
    /** Hostname used to access host machine from within containers */
    public static final String INTERNAL_HOST_HOSTNAME = "host.testcontainers.internal";

    // Image configuration
    public SELF withImagePullPolicy(ImagePullPolicy policy);
    public void setDockerImageName(@NonNull String dockerImageName);
    public void setImage(Future<String> image);

    // Command configuration
    public SELF withCommand(String... command);
    public void setCommand(@NonNull String command);
    public void setCommand(@NonNull String... commandParts);
    public String[] getCommandParts();
    public void setCommandParts(String[] commandParts);
    public SELF withWorkingDirectory(String workingDirectory);
    public void setWorkingDirectory(String workingDirectory);
    public String getWorkingDirectory();

    // Environment configuration
    public SELF withEnv(String key, String value);
    public SELF withEnv(Map<String, String> env);
    public void addEnv(String key, String value);
    public void setEnv(List<String> env);
    public Map<String, String> getEnvMap();
    @Deprecated
    public List<String> getEnv();
    public SELF withLabel(String key, String value);
    public SELF withLabels(Map<String, String> labels);
    public Map<String, String> getLabels();
    public void setLabels(Map<String, String> labels);

    // Port configuration
    public SELF withExposedPorts(Integer... ports);
    public void addExposedPort(Integer port);
    public void addExposedPorts(int... ports);
    public void setExposedPorts(List<Integer> exposedPorts);
    public void setPortBindings(List<String> portBindings);

    // Network configuration
    public SELF withNetwork(Network network);
    public Network getNetwork();
    public void setNetwork(Network network);
    public SELF withNetworkMode(String networkMode);
    public String getNetworkMode();
    public void setNetworkMode(String networkMode);
    public SELF withNetworkAliases(String... aliases);
    public List<String> getNetworkAliases();
    public void setNetworkAliases(List<String> aliases);
    public SELF withExtraHost(String hostname, String ipAddress);
    public List<String> getExtraHosts();
    public void setExtraHosts(List<String> extraHosts);

    // Volume and file configuration
    @Deprecated
    public SELF withFileSystemBind(String hostPath, String containerPath);
    @Deprecated
    public SELF withFileSystemBind(String hostPath, String containerPath, BindMode mode);
    @Deprecated
    public void addFileSystemBind(String hostPath, String containerPath, BindMode mode);
    @Deprecated
    public void addFileSystemBind(String hostPath, String containerPath, BindMode mode, SelinuxContext selinuxContext);
    public List<Bind> getBinds();
    public void setBinds(List<Bind> binds);
    public SELF withVolumesFrom(Container container, BindMode mode);
    public SELF withCopyToContainer(Transferable transferable, String containerPath);
    @Deprecated
    public SELF withCopyFileToContainer(MountableFile mountableFile, String containerPath);

    // Startup and wait configuration
    public SELF waitingFor(WaitStrategy waitStrategy);
    protected WaitStrategy getWaitStrategy();
    public void setWaitStrategy(WaitStrategy waitStrategy);
    public SELF withStartupTimeout(Duration timeout);
    public SELF withStartupCheckStrategy(StartupCheckStrategy strategy);
    public SELF withStartupAttempts(int attempts);

    // Log configuration
    public SELF withLogConsumer(Consumer<OutputFrame> logConsumer);

    // Advanced configuration
    public SELF withPrivilegedMode(boolean privilegedMode);
    public void setPrivilegedMode(boolean mode);
    public boolean isPrivilegedMode();
    public SELF withAccessToHost(boolean accessToHost);
    @UnstableAPI
    public SELF withReuse(boolean reuse);
    public SELF withCreateContainerCmdModifier(Consumer<CreateContainerCmd> modifier);

    /**
     * Configure the shared memory size for the container.
     *
     * @param bytes the size of shared memory in bytes
     *              (e.g., 512 * 1024 * 1024L for 512 MB)
     * @return this container for method chaining
     */
    public SELF withSharedMemorySize(Long bytes);

    /**
     * Configure temporary filesystems (tmpfs) mounted in the container.
     *
     * @param mapping a map where keys are mount paths and values are tmpfs options
     *                (e.g., "rw,noexec,nosuid,size=100m")
     *                Example: Map.of("/tmp", "rw,size=100m")
     * @return this container for method chaining
     */
    public SELF withTmpFs(Map<String, String> mapping);

    public SELF withMinimumRunningDuration(Duration minimumRunningDuration);
    @Deprecated
    public SELF withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode);
    @Deprecated
    public SELF withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode, SelinuxContext selinuxContext);

    // Dependencies
    public SELF dependsOn(Startable... dependencies);
    public SELF dependsOn(List<? extends Startable> dependencies);
    public SELF dependsOn(Iterable<? extends Startable> dependencies);

    // Lifecycle methods
    public void start();
    public void stop();
    public void close(); // AutoCloseable

    // Runtime access methods
    public String getHost();
    public Integer getMappedPort(int originalPort);
    public Integer getFirstMappedPort();
    public List<Integer> getExposedPorts();
    public List<String> getPortBindings();
    public List<Integer> getBoundPortNumbers();
    public String getContainerId();
    public InspectContainerResponse getContainerInfo();
    public InspectContainerResponse getCurrentContainerInfo();
    public String getDockerImageName();
    public Future<String> getImage();
    @Deprecated
    public Map<String, LinkableContainer> getLinkedContainers();
    @Deprecated
    public void setLinkedContainers(Map<String, LinkableContainer> linkedContainers);
    public DockerClient getDockerClient();
    @Deprecated
    public String getTestHostIpAddress();
    public String getContainerName();
    public boolean isRunning();
    public boolean isCreated();
    public boolean isHealthy();
    public Set<Startable> getDependencies();

    // Object methods
    public boolean equals(Object o);
    public int hashCode();

    // Command execution
    public Container.ExecResult execInContainer(String... command) throws Exception;
    public Container.ExecResult execInContainer(Charset charset, String... command) throws Exception;
    public Container.ExecResult execInContainer(ExecConfig execConfig) throws Exception;
    public Container.ExecResult execInContainer(Charset charset, ExecConfig execConfig) throws Exception;

    // File operations
    public void copyFileToContainer(Transferable transferable, String containerPath);
    public void copyFileFromContainer(String containerPath, String destinationPath);

    // Log methods
    public String getLogs();
    public String getLogs(OutputFrame.OutputType... types);
    public void followOutput(Consumer<OutputFrame> consumer);
    public void followOutput(Consumer<OutputFrame> consumer, OutputFrame.OutputType... types);

    // Lifecycle hooks (protected, for subclasses)
    protected void configure();
    protected void containerIsCreated(String containerId);
    protected void containerIsStarting(InspectContainerResponse containerInfo);
    protected void containerIsStarted(InspectContainerResponse containerInfo);
}

Usage Examples:

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.RemoteDockerImage;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;
import java.time.Duration;

// Basic container
GenericContainer<?> redis = new GenericContainer<>(DockerImageName.parse("redis:7.0"))
    .withExposedPorts(6379);

// Container with environment variables
GenericContainer<?> postgres = new GenericContainer<>(DockerImageName.parse("postgres:15"))
    .withExposedPorts(5432)
    .withEnv("POSTGRES_PASSWORD", "secret")
    .withEnv("POSTGRES_DB", "testdb")
    .withEnv("POSTGRES_USER", "testuser");

// Container with volume mounts
GenericContainer<?> nginx = new GenericContainer<>(DockerImageName.parse("nginx:alpine"))
    .withExposedPorts(80)
    .withFileSystemBind("/host/path/nginx.conf", "/etc/nginx/nginx.conf", BindMode.READ_ONLY)
    .withCopyFileToContainer(
        MountableFile.forClasspathResource("static/index.html"),
        "/usr/share/nginx/html/index.html"
    );

// Container with custom command and wait strategy
GenericContainer<?> alpine = new GenericContainer<>(DockerImageName.parse("alpine:latest"))
    .withCommand("sh", "-c", "while true; do echo 'Hello'; sleep 5; done")
    .waitingFor(Wait.forLogMessage(".*Hello.*", 1))
    .withStartupTimeout(Duration.ofSeconds(30));

// Container with network
Network network = Network.newNetwork();
GenericContainer<?> database = new GenericContainer<>(DockerImageName.parse("postgres:15"))
    .withNetwork(network)
    .withNetworkAliases("db")
    .withEnv("POSTGRES_PASSWORD", "secret");

GenericContainer<?> app = new GenericContainer<>(DockerImageName.parse("myapp:latest"))
    .withNetwork(network)
    .withEnv("DB_HOST", "db")
    .dependsOn(database);

// Container with advanced configuration
GenericContainer<?> advanced = new GenericContainer<>(DockerImageName.parse("memcached:alpine"))
    .withExposedPorts(11211)
    .withSharedMemorySize(512 * 1024 * 1024L) // 512 MB shared memory
    .withTmpFs(Map.of("/tmp", "rw,noexec,nosuid,size=100m"))
    .withExtraHost("myhost.local", "192.168.1.100")
    .withMinimumRunningDuration(Duration.ofSeconds(5));

// Container with classpath resource mapping
GenericContainer<?> withConfig = new GenericContainer<>(DockerImageName.parse("nginx:alpine"))
    .withExposedPorts(80)
    .withClasspathResourceMapping("nginx.conf", "/etc/nginx/nginx.conf", BindMode.READ_ONLY)
    .withClasspathResourceMapping("static/", "/usr/share/nginx/html/");

// Using container
try (GenericContainer<?> container = new GenericContainer<>("redis:7.0")
        .withExposedPorts(6379)) {
    container.start();

    String host = container.getHost();
    Integer port = container.getMappedPort(6379);

    // Use container in tests
} // Automatically stopped and removed

LinkableContainer Interface

Deprecated interface for containers that can be linked. Use Network features instead.

/**
 * A container which can be linked to by other containers.
 *
 * @deprecated Links are deprecated. Please use Network features instead.
 */
@Deprecated
public interface LinkableContainer {
    /**
     * @return the container name used for linking
     */
    String getContainerName();
}

Container Interface

Core interface defining the contract for all containers. Extends multiple interfaces for complete functionality.

/**
 * Core container interface defining configuration and lifecycle methods.
 *
 * @param <SELF> Self-referential generic type for fluent API
 */
public interface Container<SELF extends Container<SELF>>
    extends LinkableContainer, ContainerState {

    // All configuration methods return SELF for method chaining
    // See GenericContainer for full list of methods

    /**
     * Result of executing a command inside a container.
     * Immutable value object containing command execution results.
     * Generated by Lombok @Value annotation.
     */
    @Value
    @AllArgsConstructor(access = AccessLevel.MODULE)
    public static class ExecResult {
        /**
         * Get the exit code from the command execution.
         * Generated by Lombok @Value annotation from 'exitCode' field.
         *
         * @return exit code (0 indicates success, non-zero indicates failure)
         */
        public int getExitCode();

        /**
         * Get the standard output from the command execution.
         * Generated by Lombok @Value annotation from 'stdout' field.
         *
         * @return stdout as a string (decoded using UTF-8 or specified charset)
         */
        public String getStdout();

        /**
         * Get the standard error from the command execution.
         * Generated by Lombok @Value annotation from 'stderr' field.
         *
         * @return stderr as a string (decoded using UTF-8 or specified charset)
         */
        public String getStderr();
    }
}

ContainerState Interface

Interface representing the state and runtime information of a running container.

/**
 * Provides access to container state and runtime information.
 */
public interface ContainerState {
    /**
     * @return true if the container is currently running
     */
    boolean isRunning();

    /**
     * @return true if the container has been created
     */
    boolean isCreated();

    /**
     * @return true if the container is healthy (based on Docker healthcheck)
     */
    boolean isHealthy();

    /**
     * @return the host that this container is accessible from
     */
    String getHost();

    /**
     * Get the IP address that this container may be reached on.
     *
     * @return an IP address
     * @deprecated use {@link #getHost()} instead
     */
    @Deprecated
    String getContainerIpAddress();

    /**
     * @return the container ID
     */
    String getContainerId();

    /**
     * @return container inspection information
     */
    InspectContainerResponse getContainerInfo();

    /**
     * @return current container inspection information (refreshed)
     */
    InspectContainerResponse getCurrentContainerInfo();

    /**
     * Get the mapped port on the Docker host for an exposed container port.
     *
     * @param originalPort the exposed port in the container
     * @return the mapped port on the host
     */
    Integer getMappedPort(int originalPort);

    /**
     * @return the first mapped port
     */
    Integer getFirstMappedPort();

    /**
     * @return list of all exposed ports
     */
    List<Integer> getExposedPorts();

    /**
     * @return list of port bindings
     */
    List<String> getPortBindings();

    /**
     * Get the list of bound port numbers on the host.
     *
     * @return list of bound port numbers (host-side ports)
     */
    List<Integer> getBoundPortNumbers();

    /**
     * Get all logs from the container.
     *
     * @return container logs as a string
     */
    String getLogs();

    /**
     * Get logs from the container, filtered by output type.
     *
     * @param types the output types to include (STDOUT, STDERR)
     * @return filtered logs as a string
     */
    String getLogs(OutputFrame.OutputType... types);

    /**
     * Execute a command inside the running container.
     *
     * @param command the command to execute
     * @return result containing stdout, stderr, and exit code
     * @throws Exception if execution fails
     */
    Container.ExecResult execInContainer(String... command) throws Exception;

    /**
     * Execute a command inside the running container with a specific charset.
     *
     * @param charset the charset for decoding output
     * @param command the command to execute
     * @return result containing stdout, stderr, and exit code
     * @throws Exception if execution fails
     */
    Container.ExecResult execInContainer(Charset charset, String... command) throws Exception;

    /**
     * Execute a command using ExecConfig for advanced configuration.
     *
     * @param execConfig the execution configuration
     * @return result containing stdout, stderr, and exit code
     * @throws Exception if execution fails
     */
    Container.ExecResult execInContainer(ExecConfig execConfig) throws Exception;

    /**
     * Execute a command using ExecConfig with a specific charset.
     *
     * @param charset the charset for decoding output
     * @param execConfig the execution configuration
     * @return result containing stdout, stderr, and exit code
     * @throws Exception if execution fails
     */
    Container.ExecResult execInContainer(Charset charset, ExecConfig execConfig) throws Exception;

    /**
     * Execute a command inside the running container as a specific user.
     *
     * @deprecated Use ExecConfig with user parameter instead
     * @param user the user to execute as
     * @param command the command to execute
     * @return result containing stdout, stderr, and exit code
     * @throws UnsupportedOperationException if not supported
     * @throws IOException if I/O error occurs
     * @throws InterruptedException if execution is interrupted
     */
    @Deprecated
    default Container.ExecResult execInContainerWithUser(String user, String... command)
        throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * Execute a command inside the running container as a specific user with charset.
     *
     * @deprecated Use ExecConfig with user parameter instead
     * @param charset the charset for decoding output
     * @param user the user to execute as
     * @param command the command to execute
     * @return result containing stdout, stderr, and exit code
     * @throws UnsupportedOperationException if not supported
     * @throws IOException if I/O error occurs
     * @throws InterruptedException if execution is interrupted
     */
    @Deprecated
    default Container.ExecResult execInContainerWithUser(Charset charset, String user, String... command)
        throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * Copy a file or directory to the container.
     *
     * @param transferable the content to copy
     * @param containerPath the destination path in the container
     */
    void copyFileToContainer(Transferable transferable, String containerPath);

    /**
     * Copy a file from the container to the host.
     *
     * @param containerPath the source path in the container
     * @param destinationPath the destination path on the host
     */
    void copyFileFromContainer(String containerPath, String destinationPath);

    /**
     * Copy a file from the container and process it with a function.
     * Useful for streaming file contents without writing to disk.
     *
     * @param containerPath the source path in the container
     * @param function function that processes the InputStream and returns result
     * @param <T> the return type
     * @return the result from the function
     */
    <T> T copyFileFromContainer(String containerPath, ThrowingFunction<InputStream, T> function);
}

Usage Examples:

// Execute commands in container
Container.ExecResult result = container.execInContainer("psql", "-U", "postgres", "-c", "SELECT 1");
System.out.println("Exit code: " + result.getExitCode());
System.out.println("Output: " + result.getStdout());
System.out.println("Error: " + result.getStderr());

// Copy files
container.copyFileToContainer(
    Transferable.of("test content"),
    "/tmp/test.txt"
);

container.copyFileFromContainer("/var/log/app.log", "./app.log");

// Check logs
String logs = container.getLogs();
String stdoutOnly = container.getLogs(OutputFrame.OutputType.STDOUT);

// Get connection info
String jdbcUrl = String.format("jdbc:postgresql://%s:%d/testdb",
    container.getHost(),
    container.getMappedPort(5432)
);

ExecConfig Class

Configuration for advanced command execution in containers with support for custom user, working directory, and environment variables.

/**
 * Configuration for exec operations in containers.
 * Uses Lombok @Builder pattern for construction.
 * Provides a fluent API for configuring command execution.
 */
@Builder
@Getter
public class ExecConfig {
    /**
     * The command to run as an array of strings.
     */
    private String[] command;

    /**
     * The user to run the exec process as.
     * If not specified, runs as the container's default user.
     */
    private String user;

    /**
     * Key-value pairs of environment variables for the exec process.
     * These are added to the environment in addition to the container's environment.
     */
    private Map<String, String> envVars;

    /**
     * The working directory for the exec process.
     * If not specified, uses the container's WORKDIR.
     */
    private String workDir;

    /**
     * Create a new builder for ExecConfig.
     * Generated by Lombok @Builder annotation.
     *
     * @return ExecConfigBuilder instance
     */
    public static ExecConfig.ExecConfigBuilder builder();

    /**
     * Get the command array.
     * Generated by Lombok @Getter annotation.
     *
     * @return command array
     */
    public String[] getCommand();

    /**
     * Get the user to run as.
     * Generated by Lombok @Getter annotation.
     *
     * @return user name, or null if not set
     */
    public String getUser();

    /**
     * Get the environment variables.
     * Generated by Lombok @Getter annotation.
     *
     * @return map of environment variables, or null if not set
     */
    public Map<String, String> getEnvVars();

    /**
     * Get the working directory.
     * Generated by Lombok @Getter annotation.
     *
     * @return working directory path, or null if not set
     */
    public String getWorkDir();

    /**
     * Builder class for ExecConfig.
     * Generated by Lombok @Builder annotation.
     */
    public static class ExecConfigBuilder {
        /**
         * Set the command to execute.
         *
         * @param command array of command and arguments
         * @return this builder for chaining
         */
        public ExecConfigBuilder command(String[] command);

        /**
         * Set the user to run the command as.
         *
         * @param user username or UID
         * @return this builder for chaining
         */
        public ExecConfigBuilder user(String user);

        /**
         * Set environment variables for the command.
         *
         * @param envVars map of variable names to values
         * @return this builder for chaining
         */
        public ExecConfigBuilder envVars(Map<String, String> envVars);

        /**
         * Set the working directory for the command.
         *
         * @param workDir absolute path to working directory
         * @return this builder for chaining
         */
        public ExecConfigBuilder workDir(String workDir);

        /**
         * Build the ExecConfig instance.
         *
         * @return configured ExecConfig
         */
        public ExecConfig build();
    }
}

Usage Examples:

import org.testcontainers.containers.ExecConfig;
import org.testcontainers.containers.Container;
import java.util.Map;

// Basic command execution with user
ExecConfig config = ExecConfig.builder()
    .command(new String[]{"psql", "-c", "SELECT 1"})
    .user("postgres")
    .build();

Container.ExecResult result = container.execInContainer(config);

// Execute with custom working directory and environment
ExecConfig advancedConfig = ExecConfig.builder()
    .command(new String[]{"npm", "test"})
    .workDir("/app")
    .user("node")
    .envVars(Map.of(
        "NODE_ENV", "test",
        "CI", "true"
    ))
    .build();

Container.ExecResult testResult = container.execInContainer(advancedConfig);
System.out.println("Exit code: " + testResult.getExitCode());
System.out.println("Output: " + testResult.getStdout());

// Database operation with password in environment
ExecConfig dbConfig = ExecConfig.builder()
    .command(new String[]{
        "psql",
        "-U", "testuser",
        "-d", "testdb",
        "-c", "CREATE TABLE test (id serial PRIMARY KEY);"
    })
    .envVars(Map.of("PGPASSWORD", "secret"))
    .build();

container.execInContainer(dbConfig);

FixedHostPortGenericContainer

Container with fixed host port bindings (not recommended for most use cases due to port conflicts).

/**
 * Container that allows binding to fixed host ports.
 * Warning: May cause port conflicts in concurrent test execution.
 *
 * @param <SELF> Self-referential generic type
 */
public class FixedHostPortGenericContainer<SELF extends FixedHostPortGenericContainer<SELF>>
    extends GenericContainer<SELF> {

    /**
     * Create a fixed host port container with the specified image.
     *
     * @deprecated This class is deprecated due to port conflict issues in concurrent execution
     * @param dockerImageName the Docker image name
     */
    @Deprecated
    public FixedHostPortGenericContainer(String dockerImageName);

    /**
     * Bind a container port to a fixed host port.
     *
     * @param hostPort the host port to bind to
     * @param containerPort the container port to expose
     * @return self for method chaining
     */
    public SELF withFixedExposedPort(int hostPort, int containerPort);

    /**
     * Bind a container port to a fixed host port with protocol.
     *
     * @param hostPort the host port to bind to
     * @param containerPort the container port to expose
     * @param protocol the protocol (TCP or UDP)
     * @return self for method chaining
     */
    public SELF withFixedExposedPort(int hostPort, int containerPort, InternetProtocol protocol);
}

Usage Example:

FixedHostPortGenericContainer<?> redis = new FixedHostPortGenericContainer<>(
        DockerImageName.parse("redis:7.0"))
    .withFixedExposedPort(6379, 6379); // Bind host:6379 to container:6379

redis.start();
// Container is accessible at localhost:6379

Startable Interface

Interface for resources that can be started and stopped, with dependency management.

/**
 * Represents something that can be started and stopped, typically a container.
 */
public interface Startable extends AutoCloseable {
    /**
     * Start the resource.
     */
    void start();

    /**
     * Stop the resource.
     */
    void stop();

    /**
     * Get the dependencies that must be started before this resource.
     * Default implementation returns an empty set.
     *
     * @return set of dependencies (default: empty set)
     */
    default Set<Startable> getDependencies() {
        return Collections.emptySet();
    }

    /**
     * Close the resource (calls stop()).
     */
    @Override
    default void close() {
        stop();
    }
}

Startables Utility

Utility class for managing multiple Startable instances with dependency resolution.

/**
 * Utilities for managing multiple Startable resources.
 */
public class Startables {
    /**
     * Start multiple resources, respecting their dependencies.
     *
     * @param startables resources to start
     * @return CompletableFuture that completes when all are started
     */
    public static CompletableFuture<Void> deepStart(Startable... startables);

    /**
     * Start a collection of resources, respecting their dependencies.
     *
     * @param startables resources to start
     * @return CompletableFuture that completes when all are started
     */
    public static CompletableFuture<Void> deepStart(Collection<? extends Startable> startables);

    /**
     * Start a stream of resources asynchronously, respecting dependencies.
     *
     * @param startables stream of resources to start
     * @return CompletableFuture that completes when all are started
     */
    public static CompletableFuture<Void> deepStart(Stream<? extends Startable> startables);
}

Usage Example:

Network network = Network.newNetwork();

GenericContainer<?> database = new GenericContainer<>(DockerImageName.parse("postgres:15"))
    .withNetwork(network)
    .withNetworkAliases("db");

GenericContainer<?> redis = new GenericContainer<>(DockerImageName.parse("redis:7.0"))
    .withNetwork(network)
    .withNetworkAliases("cache");

GenericContainer<?> app = new GenericContainer<>(DockerImageName.parse("myapp:latest"))
    .withNetwork(network)
    .dependsOn(database, redis);

// Start all containers respecting dependencies
Startables.deepStart(app).join();

// All containers are now running with proper startup order

Lifecycle Hooks

Protected methods in GenericContainer that can be overridden in subclasses to customize behavior.

/**
 * Override this method to configure the container before creation.
 * Called during start() before container is created.
 */
protected void configure() {
    // Override in subclass to add configuration
}

/**
 * Called immediately after the container is created.
 *
 * @param containerId the container ID
 */
protected void containerIsCreated(String containerId) {
    // Override in subclass for post-creation logic
}

/**
 * Called during container startup, before waiting for readiness.
 *
 * @param containerInfo container inspection information
 */
protected void containerIsStarting(InspectContainerResponse containerInfo) {
    // Override in subclass for startup logic
}

/**
 * Called after the container is started and ready.
 *
 * @param containerInfo container inspection information
 */
protected void containerIsStarted(InspectContainerResponse containerInfo) {
    // Override in subclass for post-startup logic
}

Usage Example:

public class PostgreSQLContainer extends GenericContainer<PostgreSQLContainer> {

    public PostgreSQLContainer(String dockerImageName) {
        super(dockerImageName);
    }

    @Override
    protected void configure() {
        // Called before container creation
        withExposedPorts(5432);
        withEnv("POSTGRES_PASSWORD", "test");
        waitingFor(Wait.forListeningPort());
    }

    @Override
    protected void containerIsStarted(InspectContainerResponse containerInfo) {
        // Called after container is ready
        String jdbcUrl = getJdbcUrl();
        logger.info("PostgreSQL started at: " + jdbcUrl);
    }

    public String getJdbcUrl() {
        return String.format("jdbc:postgresql://%s:%d/test",
            getHost(), getMappedPort(5432));
    }
}

Types

Docker-java Types

Testcontainers uses types from the docker-java library for Docker API interactions:

// From com.github.dockerjava.api.command
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.InspectContainerResponse;

// From com.github.dockerjava.api
import com.github.dockerjava.api.DockerClient;

Enums

/**
 * Volume bind modes for mounting directories.
 */
public enum BindMode {
    /** Read-only mount */
    READ_ONLY,
    /** Read-write mount */
    READ_WRITE;

    /**
     * The underlying Docker Java API AccessMode.
     * Can be used for direct docker-java API interactions.
     */
    public final com.github.dockerjava.api.model.AccessMode accessMode;
}

/**
 * Internet protocols for port bindings.
 */
public enum InternetProtocol {
    /** TCP protocol */
    TCP,
    /** UDP protocol */
    UDP;

    /**
     * Convert protocol to Docker notation (lowercase).
     * @return Protocol name in lowercase (e.g., "tcp", "udp")
     */
    public String toDockerNotation();

    /**
     * Parse protocol from Docker notation string.
     * @param protocol Protocol string in Docker notation (case-insensitive)
     * @return Corresponding InternetProtocol enum value
     */
    public static InternetProtocol fromDockerNotation(String protocol);
}

/**
 * SELinux context for volume mounts.
 */
public enum SelinuxContext {
    /** Shared SELinux context */
    SHARED,
    /** Single/private SELinux context */
    SINGLE,
    /** No SELinux context */
    NONE;

    /**
     * The underlying Docker Java API SELContext.
     * Can be used for direct docker-java API interactions.
     */
    public final com.github.dockerjava.api.model.SELContext selContext;
}

TestLifecycleAware Interface

Interface for containers to be aware of test lifecycle events, enabling integration with test frameworks.

/**
 * Interface for containers that need to be notified of test lifecycle events.
 * Useful for integrating with JUnit and other test frameworks.
 */
public interface TestLifecycleAware {
    /**
     * Called before a test starts.
     *
     * @param description the test description
     */
    void beforeTest(TestDescription description);

    /**
     * Called after a test completes.
     *
     * @param description the test description
     * @param throwable optional throwable if test failed
     */
    void afterTest(TestDescription description, Optional<Throwable> throwable);
}

Usage Example:

public class CustomContainer extends GenericContainer<CustomContainer>
    implements TestLifecycleAware {

    public CustomContainer(String imageName) {
        super(imageName);
    }

    @Override
    public void beforeTest(TestDescription description) {
        // Called before each test
        logger.info("Starting test: " + description.getTestId());
        // Setup test-specific configuration
    }

    @Override
    public void afterTest(TestDescription description, Optional<Throwable> throwable) {
        // Called after each test
        if (throwable.isPresent()) {
            logger.error("Test failed: " + description.getTestId(), throwable.get());
            // Capture logs or diagnostics
        }
        // Cleanup test-specific resources
    }
}

TestDescription Interface

Describes a test for lifecycle callbacks.

/**
 * Describes a test being executed.
 */
public interface TestDescription {
    /**
     * Get the unique identifier for the test.
     *
     * @return test identifier
     */
    String getTestId();

    /**
     * Get a filesystem-friendly name for the test.
     * Useful for creating test-specific files or directories.
     *
     * @return filesystem-friendly test name
     */
    String getFilesystemFriendlyName();
}

Specialized Container Classes

FutureContainer Class

A container reference that may not have been launched yet. Used for container linking and references.

/**
 * A container that may not have been launched yet.
 * Used for container linking patterns and references.
 *
 * @since 2.0.0
 */
@Data
public class FutureContainer implements LinkableContainer {
    private final String containerName;

    /**
     * Constructor with container name.
     *
     * @param containerName the name of the container
     */
    public FutureContainer(String containerName);

    /**
     * Get the container name for linking.
     *
     * @return the container name
     */
    public String getContainerName();
}

Usage Example:

// Create a future reference to a container for linking
FutureContainer futureDb = new FutureContainer("my-database");

// Use in container configuration (for legacy linking)
GenericContainer<?> app = new GenericContainer<>("myapp:latest")
    .withLink(futureDb, "db");

ExecInContainerPattern Utility

Provides utility methods for executing commands in containers using the Docker exec API.

/**
 * Provides utility methods for executing commands in containers.
 * Utility class with static methods for exec operations.
 */
@UtilityClass
public class ExecInContainerPattern {

    /**
     * Run a command inside a running container, interpreting output as UTF-8.
     *
     * @param dockerClient the Docker client
     * @param containerInfo the container info
     * @param command the command to execute
     * @return the execution result
     * @throws UnsupportedOperationException if docker exec is not supported
     * @throws IOException if there's a communication error
     * @throws InterruptedException if interrupted while waiting
     */
    public Container.ExecResult execInContainer(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        String... command
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * Run a command inside a running container with custom charset.
     *
     * @param dockerClient the Docker client
     * @param containerInfo the container info
     * @param outputCharset the character set for output
     * @param command the command to execute
     * @return the execution result
     * @throws UnsupportedOperationException if docker exec is not supported
     * @throws IOException if there's a communication error
     * @throws InterruptedException if interrupted while waiting
     */
    public Container.ExecResult execInContainer(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        Charset outputCharset,
        String... command
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * Run a command inside a running container with exec configuration.
     *
     * @param dockerClient the Docker client
     * @param containerInfo the container info
     * @param execConfig the exec configuration
     * @return the execution result
     * @throws UnsupportedOperationException if docker exec is not supported
     * @throws IOException if there's a communication error
     * @throws InterruptedException if interrupted while waiting
     */
    public Container.ExecResult execInContainer(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        ExecConfig execConfig
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * Run a command inside a running container with exec configuration and custom charset.
     *
     * @param dockerClient the Docker client
     * @param containerInfo the container info
     * @param outputCharset the character set for output
     * @param execConfig the exec configuration
     * @return the execution result
     * @throws UnsupportedOperationException if docker exec is not supported
     * @throws IOException if there's a communication error
     * @throws InterruptedException if interrupted while waiting
     */
    public Container.ExecResult execInContainer(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        Charset outputCharset,
        ExecConfig execConfig
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, String...)}
     */
    @Deprecated
    public Container.ExecResult execInContainer(
        InspectContainerResponse containerInfo,
        String... command
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, Charset, String...)}
     */
    @Deprecated
    public Container.ExecResult execInContainer(
        InspectContainerResponse containerInfo,
        Charset outputCharset,
        String... command
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, ExecConfig)}
     */
    @Deprecated
    public Container.ExecResult execInContainerWithUser(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        String user,
        String... command
    ) throws UnsupportedOperationException, IOException, InterruptedException;

    /**
     * @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, Charset, ExecConfig)}
     */
    @Deprecated
    public Container.ExecResult execInContainerWithUser(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        Charset outputCharset,
        String user,
        String... command
    ) throws UnsupportedOperationException, IOException, InterruptedException;
}

Usage Example:

// Execute command in a running container
DockerClient dockerClient = DockerClientFactory.instance().client();
InspectContainerResponse containerInfo = container.getContainerInfo();

// Simple command execution
Container.ExecResult result = ExecInContainerPattern.execInContainer(
    dockerClient,
    containerInfo,
    "ls", "-la", "/app"
);

System.out.println("Exit code: " + result.getExitCode());
System.out.println("Output: " + result.getStdout());

// With custom configuration
ExecConfig config = ExecConfig.builder()
    .command(new String[]{"bash", "-c", "echo $HOME"})
    .user("appuser")
    .workDir("/app")
    .envVars(Map.of("CUSTOM_VAR", "value"))
    .build();

Container.ExecResult customResult = ExecInContainerPattern.execInContainer(
    dockerClient,
    containerInfo,
    config
);

SocatContainer Class

A TCP proxy container using socat, enabling any TCP port of another container to be exposed publicly.

/**
 * A socat container used as a TCP proxy, enabling any TCP port of another container
 * to be exposed publicly, even if that container does not make the port public itself.
 *
 * Uses the alpine/socat image.
 */
public class SocatContainer extends GenericContainer<SocatContainer> {

    /**
     * Create a socat container with default image.
     */
    public SocatContainer();

    /**
     * Create a socat container with custom image.
     *
     * @param dockerImageName the Docker image name
     */
    public SocatContainer(DockerImageName dockerImageName);

    /**
     * Configure target host and port, exposing on the same port.
     *
     * @param exposedPort the port to expose
     * @param host the target host
     * @return this container for method chaining
     */
    public SocatContainer withTarget(int exposedPort, String host);

    /**
     * Configure target host and port with different internal port.
     *
     * @param exposedPort the port to expose externally
     * @param host the target host
     * @param internalPort the internal port on target host
     * @return this container for method chaining
     */
    public SocatContainer withTarget(int exposedPort, String host, int internalPort);
}

Usage Example:

// Create a TCP proxy to expose a port from another container
Network network = Network.newNetwork();

GenericContainer<?> database = new GenericContainer<>("mysql:8")
    .withNetwork(network)
    .withNetworkAliases("mysql")
    .withEnv("MYSQL_ROOT_PASSWORD", "secret");

// Use socat to proxy the MySQL port
SocatContainer proxy = new SocatContainer()
    .withNetwork(network)
    .withTarget(3306, "mysql", 3306);

database.start();
proxy.start();

// Now you can access MySQL through the proxy's exposed port
String jdbcUrl = String.format(
    "jdbc:mysql://%s:%d/test",
    proxy.getHost(),
    proxy.getMappedPort(3306)
);

VncRecordingContainer Class

A sidekick container for recording VNC screen output from another container.

/**
 * Sidekick container with the sole purpose of recording the VNC screen output
 * from another container. Useful for debugging UI tests.
 *
 * Uses the testcontainers/vnc-recorder image.
 */
@Getter
@ToString
public class VncRecordingContainer extends GenericContainer<VncRecordingContainer> {

    public static final String DEFAULT_VNC_PASSWORD = "secret";
    public static final int DEFAULT_VNC_PORT = 5900;
    static final VncRecordingFormat DEFAULT_RECORDING_FORMAT = VncRecordingFormat.FLV;

    /**
     * Create a VNC recording container attached to another container.
     *
     * @param targetContainer the container to record (must have network alias)
     * @throws IllegalStateException if target has no network alias
     */
    public VncRecordingContainer(@NonNull GenericContainer<?> targetContainer);

    /**
     * Create a VNC recording container on a specific network.
     *
     * @param network the network
     * @param targetNetworkAlias the network alias of target container
     * @throws IllegalStateException if configuration is invalid
     */
    public VncRecordingContainer(@NonNull Network network, @NonNull String targetNetworkAlias);

    /**
     * Set the VNC password.
     *
     * @param vncPassword the VNC password
     * @return this container for method chaining
     */
    public VncRecordingContainer withVncPassword(@NonNull String vncPassword);

    /**
     * Set the VNC port.
     *
     * @param vncPort the VNC port
     * @return this container for method chaining
     */
    public VncRecordingContainer withVncPort(int vncPort);

    /**
     * Set the video format.
     *
     * @param videoFormat the video format (FLV or MP4)
     * @return this container for method chaining
     */
    public VncRecordingContainer withVideoFormat(VncRecordingFormat videoFormat);

    /**
     * Set the frame rate.
     *
     * @param frameRate the frame rate
     * @return this container for method chaining
     */
    public VncRecordingContainer withFrameRate(int frameRate);

    /**
     * Stream the recording.
     *
     * @return input stream of the recording
     * @throws Exception if streaming fails
     */
    public InputStream streamRecording() throws Exception;

    /**
     * Save the recording to a file.
     *
     * @param file the output file
     * @throws Exception if saving fails
     */
    public void saveRecordingToFile(@NonNull File file) throws Exception;

    /**
     * Video format options for VNC recording.
     */
    @RequiredArgsConstructor
    public enum VncRecordingFormat {
        /** FLV format */
        FLV("flv"),
        /** MP4 format */
        MP4("mp4");

        @Getter
        private final String filenameExtension;

        /**
         * Re-encode the recording to this format.
         * Abstract method implemented by each enum value.
         *
         * @param container the VNC recording container
         * @param source the source recording path
         * @return the re-encoded recording path
         */
        abstract String reencodeRecording(VncRecordingContainer container, String source);
    }
}

Usage Example:

// Record VNC session from a browser container
Network network = Network.newNetwork();

BrowserWebDriverContainer<?> chrome = new BrowserWebDriverContainer<>()
    .withNetwork(network)
    .withNetworkAliases("chrome")
    .withCapabilities(new ChromeOptions());

// Attach VNC recorder
VncRecordingContainer recorder = new VncRecordingContainer(chrome)
    .withVncPassword("secret")
    .withVideoFormat(VncRecordingContainer.VncRecordingFormat.MP4);

chrome.start();
recorder.start();

// Run your tests...
// ...

// Save the recording
recorder.saveRecordingToFile(new File("test-recording.mp4"));

recorder.stop();
chrome.stop();

DockerMcpGatewayContainer Class

Container for the Docker MCP Gateway service.

/**
 * Testcontainers implementation of the Docker MCP Gateway container.
 *
 * Supported images: docker/mcp-gateway
 * Exposed ports: 8811
 */
public class DockerMcpGatewayContainer extends GenericContainer<DockerMcpGatewayContainer> {

    /**
     * Create an MCP Gateway container with image name.
     *
     * @param dockerImageName the Docker image name
     */
    public DockerMcpGatewayContainer(String dockerImageName);

    /**
     * Create an MCP Gateway container with DockerImageName.
     *
     * @param dockerImageName the Docker image name
     */
    public DockerMcpGatewayContainer(DockerImageName dockerImageName);

    /**
     * Add a server with tools.
     *
     * @param server the server URL
     * @param tools the tools to enable
     * @return this container for method chaining
     */
    public DockerMcpGatewayContainer withServer(String server, List<String> tools);

    /**
     * Add a server with tools (varargs).
     *
     * @param server the server URL
     * @param tools the tools to enable
     * @return this container for method chaining
     */
    public DockerMcpGatewayContainer withServer(String server, String... tools);

    /**
     * Add secrets for the gateway.
     *
     * @param secrets the secrets map
     * @return this container for method chaining
     */
    public DockerMcpGatewayContainer withSecrets(Map<String, String> secrets);

    /**
     * Add a single secret.
     *
     * @param secretKey the secret key
     * @param secretValue the secret value
     * @return this container for method chaining
     */
    public DockerMcpGatewayContainer withSecret(String secretKey, String secretValue);

    /**
     * Get the gateway endpoint URL.
     *
     * @return the endpoint URL
     */
    public String getEndpoint();
}

Usage Example:

// Create MCP Gateway container
DockerMcpGatewayContainer gateway = new DockerMcpGatewayContainer("docker/mcp-gateway:latest")
    .withServer("http://my-mcp-server:8080", "tool1", "tool2")
    .withSecret("API_KEY", "secret-key-value");

gateway.start();

// Get the endpoint
String endpoint = gateway.getEndpoint();
System.out.println("MCP Gateway available at: " + endpoint);

DockerModelRunnerContainer Class

Proxy container for the Docker Model Runner service provided by Docker Desktop.

/**
 * Testcontainers proxy container for the Docker Model Runner service
 * provided by Docker Desktop.
 *
 * Supported images: alpine/socat
 * Exposed ports: 80
 */
@Slf4j
public class DockerModelRunnerContainer extends SocatContainer {

    /**
     * Create a Model Runner container with image name.
     *
     * @param image the Docker image name
     */
    public DockerModelRunnerContainer(String image);

    /**
     * Create a Model Runner container with DockerImageName.
     *
     * @param image the Docker image name
     */
    public DockerModelRunnerContainer(DockerImageName image);

    /**
     * Set the model to pull and use.
     *
     * @param model the model name
     * @return this container for method chaining
     */
    public DockerModelRunnerContainer withModel(String model);

    /**
     * Get the base endpoint URL.
     *
     * @return the base endpoint URL
     */
    public String getBaseEndpoint();

    /**
     * Get the OpenAI-compatible endpoint URL.
     * Returns base endpoint + "/engines".
     *
     * @return the OpenAI endpoint URL (e.g., "http://host:port/engines")
     */
    public String getOpenAIEndpoint();
}

Usage Example:

// Create Model Runner container with a specific model
DockerModelRunnerContainer modelRunner = new DockerModelRunnerContainer("alpine/socat:latest")
    .withModel("llama3.2:latest");

modelRunner.start();

// Get endpoints
String baseEndpoint = modelRunner.getBaseEndpoint();
String openAiEndpoint = modelRunner.getOpenAIEndpoint();

System.out.println("Model Runner base endpoint: " + baseEndpoint);
System.out.println("OpenAI-compatible endpoint: " + openAiEndpoint);

// Use the endpoint with your AI client
// ...

Container Extensibility

CreateContainerCmdModifier Interface

Callback interface for customizing container creation commands. This is a key extensibility point in Testcontainers, loaded via Java ServiceLoader mechanism.

/**
 * Callback interface that can be used to customize a CreateContainerCmd.
 * Implementations can be loaded via ServiceLoader to automatically apply
 * modifications to all containers.
 *
 * @since 2.0.0
 */
public interface CreateContainerCmdModifier {
    /**
     * Callback to modify a CreateContainerCmd instance.
     *
     * @param createContainerCmd the command to modify
     * @return the modified command
     */
    CreateContainerCmd modify(CreateContainerCmd createContainerCmd);
}

Usage Example (Direct):

// Use in GenericContainer directly
GenericContainer<?> container = new GenericContainer<>("nginx:latest")
    .withCreateContainerCmdModifier(cmd -> cmd
        .withHostName("custom-hostname")
        .withMacAddress("02:42:ac:11:00:02")
    );

Usage Example (ServiceLoader):

Create a file META-INF/services/org.testcontainers.core.CreateContainerCmdModifier:

com.example.MyCustomModifier

Implement the modifier:

package com.example;

import com.github.dockerjava.api.command.CreateContainerCmd;
import org.testcontainers.core.CreateContainerCmdModifier;

public class MyCustomModifier implements CreateContainerCmdModifier {
    @Override
    public CreateContainerCmd modify(CreateContainerCmd cmd) {
        // Add custom labels to all containers
        Map<String, String> labels = new HashMap<>(cmd.getLabels());
        labels.put("com.example.environment", "test");
        labels.put("com.example.version", "1.0");
        return cmd.withLabels(labels);
    }
}

Common Use Cases:

// Add security options
container.withCreateContainerCmdModifier(cmd ->
    cmd.withSecurityOpts(List.of("no-new-privileges"))
);

// Configure resource limits via HostConfig
container.withCreateContainerCmdModifier(cmd -> {
    cmd.getHostConfig()
        .withCpuShares(512L)
        .withMemory(512 * 1024 * 1024L)  // 512 MB
        .withMemorySwap(1024 * 1024 * 1024L);  // 1 GB
});

// Configure ulimits (file descriptors, processes, etc.)
container.withCreateContainerCmdModifier(cmd -> {
    cmd.getHostConfig().withUlimits(
        new Ulimit("nofile", 1024L, 2048L),  // File descriptors: soft 1024, hard 2048
        new Ulimit("nproc", 512L, 1024L)      // Max processes: soft 512, hard 1024
    );
});

// Set capabilities
container.withCreateContainerCmdModifier(cmd -> {
    cmd.getHostConfig()
        .withCapAdd(Capability.NET_ADMIN)
        .withCapDrop(Capability.CHOWN);
});

// Configure cgroup parent
container.withCreateContainerCmdModifier(cmd -> {
    cmd.getHostConfig()
        .withCgroupParent("custom-cgroup");
});

// Configure DNS
container.withCreateContainerCmdModifier(cmd ->
    cmd.withDns("8.8.8.8", "8.8.4.4")
);