or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

Testcontainers Elasticsearch Module

The Testcontainers Elasticsearch module provides a specialized container implementation for running Elasticsearch instances in Docker containers during testing. It enables Java developers to write integration tests against real Elasticsearch instances by automatically managing container lifecycle, port mappings, and configuration.

Key Information for Agents

Required Dependencies:

  • org.testcontainers:elasticsearch (this package, version 1.21.4)
  • org.testcontainers:testcontainers core library is required (provided transitively)
  • Docker must be installed and running
  • Elasticsearch Java client library (e.g., org.elasticsearch.client:elasticsearch-rest-client or co.elastic.clients:elasticsearch-java) for connecting to the container (not required by testcontainers itself)

Default Behaviors:

  • Default HTTP port: 9200 (exposed and mapped to random host port)
  • Default transport port: 9300 (exposed, deprecated in ES 8.x)
  • Default discovery type: single-node (Elasticsearch runs in single-node mode)
  • Default disk threshold: Disabled (cluster.routing.allocation.disk.threshold_enabled=false)
  • Default JVM heap memory: 2GB (configurable via ES_JAVA_OPTS)
  • Default image: Must be specified in constructor (no default, typically docker.elastic.co/elasticsearch/elasticsearch:7.9.2 or 8.1.2)
  • Default security (ES 8.x+): Enabled with password "changeme" (username: "elastic")
  • Default security (ES 7.x and below): Disabled (optional via withPassword())
  • Default SSL (ES 8.x+): Enabled with self-signed certificate
  • Default SSL (ES 7.x and below): Disabled
  • Default wait strategy: Version-appropriate log pattern matching
  • Startup timeout: Inherited from GenericContainer (typically 60 seconds, configurable)
  • Port mapping: Random available ports on host (use getHttpHostAddress() or getMappedPort(9200) to retrieve)
  • Container reuse: Not enabled by default (new container per test)
  • Network isolation: Each container runs in isolated network by default
  • Data persistence: Ephemeral (data lost when container stops)

Threading Model:

  • ElasticsearchContainer instances are not thread-safe for concurrent modification
  • Container lifecycle methods (start(), stop(), close()) are not thread-safe
  • Multiple containers can run concurrently (each gets unique ports)
  • Once started, read operations (getHttpHostAddress(), getMappedPort()) are safe from multiple threads
  • Elasticsearch client operations are independent of container thread safety

Lifecycle:

  • Container must be started with container.start() before use
  • Container automatically waits for Elasticsearch to be ready (log pattern matching)
  • Container must be stopped with container.stop() or container.close() for cleanup
  • Container implements AutoCloseable - use try-with-resources for automatic cleanup
  • Container restart: Not directly supported (stop and create new instance)
  • Container disposal: Automatically cleaned up when using try-with-resources
  • Configuration methods (e.g., withPassword(), withCertPath()) must be called before start()
  • Access methods (e.g., getHttpHostAddress(), createSslContextFromCa()) must be called after start()

Exceptions:

  • ContainerLaunchException - Container failed to start
  • IllegalArgumentException - Invalid configuration (e.g., withPassword() on OSS image)
  • IllegalStateException - Operation on container in invalid state (e.g., caCertAsBytes() when certificate not available, or calling access methods before start())
  • RuntimeException - SSL/certificate errors, Docker errors, or other runtime issues
  • TimeoutException - Startup timeout exceeded
  • DockerException - Docker daemon not available or image pull failed

Edge Cases:

  • Port conflicts: Container automatically maps to random available port (use getHttpHostAddress() to get actual endpoint)
  • Image pull failures: Requires network access and valid image name
  • Startup timeout: May need to increase timeout for slower systems (via waitingFor() with custom wait strategy)
  • Multiple versions: Can run multiple Elasticsearch versions simultaneously (different containers)
  • Container restart: Not directly supported - must stop and create new instance (data is lost)
  • Memory constraints: 2GB default may be insufficient for large datasets (can be overridden via ES_JAVA_OPTS environment variable)
  • Authentication: For ES 8.x+, password must be set before start() is called (default is "changeme")
  • SSL certificates: For ES 8.x+, must use createSslContextFromCa() for HTTPS connections
  • OSS images: Cannot use withPassword() with OSS images (throws IllegalArgumentException)
  • Network isolation: Containers can be isolated using withNetworkMode() or withNetwork()
  • File system: Container file system is ephemeral (use withClasspathResourceMapping() or withCopyToContainer() for persistent setup)
  • Health check: Wait strategy uses log pattern matching (may fail if Elasticsearch version incompatible)
  • Elasticsearch 8.x: Security and SSL enabled by default, must use HTTPS with SSL context
  • Elasticsearch 7.x and below: Security optional, HTTP connections work by default
  • Calling getHttpHostAddress() before start(): Throws IllegalStateException
  • Calling createSslContextFromCa() on ES 7.x: May throw IllegalStateException if certificate not available
  • Empty password: withPassword("") may cause authentication failures
  • Certificate path: withCertPath() must be called before start() and path must exist in container
  • Multiple containers with same image: Each gets unique ports, can run concurrently
  • Container logs: Available via getLogs() after container starts
  • Executing commands: execInContainer() can be used after container starts

Package Information

  • Package Name: org.testcontainers:elasticsearch
  • Package Type: Maven
  • Language: Java
  • Installation:

Gradle:

testImplementation "org.testcontainers:elasticsearch:1.21.4"

Maven:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>1.21.4</version>
    <scope>test</scope>
</dependency>

Core Imports

import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.utility.DockerImageName;

Architecture

The ElasticsearchContainer class extends GenericContainer<ElasticsearchContainer> from the Testcontainers core library, inheriting all standard container lifecycle and configuration methods. It provides Elasticsearch-specific functionality including:

  • Version Detection: Automatically detects Elasticsearch version and applies appropriate configuration (6.x, 7.x, or 8.x+)
  • Security Management: Handles authentication and SSL/TLS setup, with security enabled by default for 8.x+
  • Certificate Handling: Extracts and manages self-signed CA certificates for HTTPS connections in 8.x+
  • Resource Configuration: Preconfigures single-node mode, memory settings, and disk threshold checks for testing environments
  • Wait Strategies: Uses version-appropriate log patterns to determine when Elasticsearch is ready

API Reference

Container Creation and Configuration

Create Elasticsearch container instances with version-specific Docker images.

package org.testcontainers.elasticsearch;

public class ElasticsearchContainer extends GenericContainer<ElasticsearchContainer> {
    /**
     * @deprecated Use ElasticsearchContainer(DockerImageName) instead
     */
    @Deprecated
    public ElasticsearchContainer();

    public ElasticsearchContainer(String dockerImageName);

    public ElasticsearchContainer(DockerImageName dockerImageName);
}

Parameters:

  • dockerImageName (String or DockerImageName): Full docker image name, e.g., "docker.elastic.co/elasticsearch/elasticsearch:7.9.2" or "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"

Returns: ElasticsearchContainer instance (not started)

Supported Images:

  • docker.elastic.co/elasticsearch/elasticsearch (recommended)
  • docker.elastic.co/elasticsearch/elasticsearch-oss (deprecated after 7.10.2, no security features)
  • elasticsearch (Docker Hub)

Default Configuration Applied:

  • Single-node discovery mode (discovery.type=single-node)
  • Disk threshold checks disabled (cluster.routing.allocation.disk.threshold_enabled=false)
  • 2GB JVM heap memory (configurable)
  • Exposed ports: 9200 (HTTP), 9300 (Transport - deprecated)
  • For Elasticsearch 8.x+: Security enabled with default password "changeme"

Example:

// Recommended approach with DockerImageName
DockerImageName image = DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.9.2");
ElasticsearchContainer container = new ElasticsearchContainer(image);

// Also valid with String
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
);

Security Configuration

Enable and configure security features including authentication and password management.

public ElasticsearchContainer withPassword(String password);

Parameters:

  • password (String): Password to set for the 'elastic' user (non-null, non-empty recommended)

Returns: ElasticsearchContainer for method chaining

When to Call: Must be called before start()

Description:

  • For Elasticsearch 8.x+: Security is enabled by default; this method sets the password (overrides default "changeme")
  • For Elasticsearch 7.x and below: Enables X-Pack security and sets the password
  • Not available for OSS images (throws IllegalArgumentException)
  • Empty password may cause authentication failures

Throws:

  • IllegalArgumentException - If called with OSS image or invalid configuration

Example:

// Elasticsearch 7.x with security enabled
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)
    .withPassword("mysecretpassword");
container.start();

// Create authenticated REST client
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
    AuthScope.ANY,
    new UsernamePasswordCredentials("elastic", "mysecretpassword")
);

RestClient client = RestClient
    .builder(HttpHost.create(container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder ->
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
    )
    .build();

HTTP Endpoint Access

Get the HTTP endpoint address for connecting to Elasticsearch.

public String getHttpHostAddress();

Returns: String in format "host:port" (e.g., "localhost:32768")

When to Call: Must be called after start() completes

Description: Returns the host and dynamically mapped port for the Elasticsearch HTTP endpoint (port 9200). Use this to construct HTTP clients for connecting to the Elasticsearch instance.

Throws:

  • IllegalStateException - If called before container is started

Example:

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
);
container.start();

String endpoint = container.getHttpHostAddress();
// endpoint = "localhost:32768" (port varies)

RestClient client = RestClient.builder(HttpHost.create(endpoint)).build();

SSL Certificate Management (Elasticsearch 8.x+)

Extract and use SSL certificates for HTTPS connections to Elasticsearch 8.x+ instances.

public Optional<byte[]> caCertAsBytes();

public SSLContext createSslContextFromCa();

public ElasticsearchContainer withCertPath(String certPath);

caCertAsBytes():

  • Returns: Optional<byte[]> containing CA certificate bytes, or empty if not available
  • When to Call: Must be called after start() completes
  • Description: Extracts the self-signed CA certificate from the container (Elasticsearch 8.x+ only)
  • Throws: No exceptions (returns empty Optional if certificate not available or ES version < 8.x)

createSslContextFromCa():

  • Returns: SSLContext configured to trust the container's CA certificate
  • When to Call: Must be called after start() completes
  • Description: Creates an SSL context for establishing HTTPS connections to Elasticsearch 8.x+
  • Throws:
    • IllegalStateException - If CA certificate not found (ES version < 8.x or certificate path invalid)
    • RuntimeException - For SSL/certificate errors

withCertPath(String certPath):

  • Parameters: certPath - Path to CA certificate within the Docker container (non-null)
  • Returns: ElasticsearchContainer for method chaining
  • When to Call: Must be called before start()
  • Description: Configures a custom CA certificate path (default: /usr/share/elasticsearch/config/certs/http_ca.crt)
  • Throws: No exceptions (validation happens when certificate is accessed)

Example:

// Elasticsearch 8.x with HTTPS
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
);
container.start();

// Create HTTPS client with SSL context
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
    AuthScope.ANY,
    new UsernamePasswordCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
);

RestClient client = RestClient
    .builder(HttpHost.create("https://" + container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder -> {
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        httpClientBuilder.setSSLContext(container.createSslContextFromCa());
        return httpClientBuilder;
    })
    .build();

// Optionally get certificate bytes
Optional<byte[]> certBytes = container.caCertAsBytes();
if (certBytes.isPresent()) {
    // Use certificate bytes for custom SSL configuration
}

Transport Client Access (Deprecated)

Get the transport client endpoint for legacy TransportClient connections.

/**
 * @deprecated The TransportClient is removed in Elasticsearch 8
 */
@Deprecated
public InetSocketAddress getTcpHost();

Returns: InetSocketAddress with host and mapped transport port (9300)

When to Call: Must be called after start() completes

Description: Returns the endpoint for the deprecated TransportClient API. The TransportClient was removed in Elasticsearch 8.x. Use the REST client instead.

Throws:

  • IllegalStateException - If called before container is started

Example (for Elasticsearch 7.x only):

@SuppressWarnings("deprecation")
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
);
container.start();

TransportAddress transportAddress = new TransportAddress(container.getTcpHost());
Settings settings = Settings.builder().put("cluster.name", "docker-cluster").build();
TransportClient transportClient = new PreBuiltTransportClient(settings)
    .addTransportAddress(transportAddress);

Types

/**
 * Default password constant for Elasticsearch 8.x+
 */
public static final String ELASTICSEARCH_DEFAULT_PASSWORD = "changeme";

Usage Patterns

Basic Container Setup

import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.Request;

// Create and start container with Elasticsearch 7.x
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
);
container.start();

// Get HTTP endpoint
String httpHostAddress = container.getHttpHostAddress();

// Create REST client and use it
RestClient client = RestClient.builder(HttpHost.create(httpHostAddress)).build();
client.performRequest(new Request("GET", "/"));

// Container is automatically stopped when closed (try-with-resources)
client.close();
container.close();

Try-With-Resources Pattern

Use try-with-resources for automatic cleanup:

try (ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)) {
    container.start();

    // Use container for tests
    RestClient client = RestClient
        .builder(HttpHost.create(container.getHttpHostAddress()))
        .build();

    // Perform operations
    client.performRequest(new Request("GET", "/_cluster/health"));

    client.close();
} // Container automatically stopped and removed

Elasticsearch 8.x with HTTPS and SSL

import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;

// Elasticsearch 8.x with HTTPS
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
);
container.start();

// Create HTTPS client with SSL context
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
    AuthScope.ANY,
    new UsernamePasswordCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
);

RestClient client = RestClient
    .builder(HttpHost.create("https://" + container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder -> {
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        httpClientBuilder.setSSLContext(container.createSslContextFromCa());
        return httpClientBuilder;
    })
    .build();

// Use the client
client.performRequest(new Request("GET", "/"));
client.close();
container.close();

Elasticsearch 7.x with Security Enabled

import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;

// Elasticsearch 7.x with security enabled
ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)
    .withPassword("mysecretpassword");
container.start();

// Create authenticated REST client
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
    AuthScope.ANY,
    new UsernamePasswordCredentials("elastic", "mysecretpassword")
);

RestClient client = RestClient
    .builder(HttpHost.create(container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder ->
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
    )
    .build();

client.performRequest(new Request("GET", "/"));
client.close();
container.close();

JUnit 5 Test Example

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.apache.http.HttpHost;

import static org.junit.jupiter.api.Assertions.*;

class ElasticsearchIntegrationTest {
    private ElasticsearchContainer container;
    private RestClient client;

    @BeforeEach
    void setUp() {
        container = new ElasticsearchContainer(
            "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
        );
        container.start();

        client = RestClient.builder(
            HttpHost.create(container.getHttpHostAddress())
        ).build();
    }

    @AfterEach
    void tearDown() throws Exception {
        if (client != null) {
            client.close();
        }
        if (container != null) {
            container.close();
        }
    }

    @Test
    void testClusterHealth() throws Exception {
        Response response = client.performRequest(new Request("GET", "/_cluster/health"));
        assertEquals(200, response.getStatusLine().getStatusCode());
    }

    @Test
    void testIndexCreation() throws Exception {
        Request request = new Request("PUT", "/test-index");
        Response response = client.performRequest(request);
        assertEquals(200, response.getStatusLine().getStatusCode());
    }
}

JUnit 4 Test Example

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.apache.http.HttpHost;

import static org.junit.Assert.*;

public class ElasticsearchIntegrationTest {
    private ElasticsearchContainer container;
    private RestClient client;

    @Before
    public void setUp() {
        container = new ElasticsearchContainer(
            "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
        );
        container.start();

        client = RestClient.builder(
            HttpHost.create(container.getHttpHostAddress())
        ).build();
    }

    @After
    public void tearDown() throws Exception {
        if (client != null) {
            client.close();
        }
        if (container != null) {
            container.close();
        }
    }

    @Test
    public void testClusterHealth() throws Exception {
        Response response = client.performRequest(new Request("GET", "/_cluster/health"));
        assertEquals(200, response.getStatusLine().getStatusCode());
    }
}

Advanced Configuration Examples

Elasticsearch 8.x Without SSL

Disable SSL for testing environments where HTTPS is not required:

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
)
    .withEnv("xpack.security.transport.ssl.enabled", "false")
    .withEnv("xpack.security.http.ssl.enabled", "false");
container.start();

// Use HTTP instead of HTTPS
RestClient client = RestClient
    .builder(HttpHost.create(container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder -> {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
        );
        return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
    })
    .build();

Custom Memory Configuration

Configure JVM heap size via environment variable:

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)
    .withEnv("ES_JAVA_OPTS", "-Xms1g -Xmx1g");
container.start();

Or via JVM options file:

import org.testcontainers.containers.BindMode;

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)
    .withClasspathResourceMapping(
        "custom-jvm.options",
        "/usr/share/elasticsearch/config/jvm.options.d/custom-jvm.options",
        BindMode.READ_ONLY
    );
container.start();

Custom Wait Strategy

Override the default wait strategy with HTTP-based waiting for Elasticsearch 8.x:

import org.testcontainers.containers.wait.strategy.Wait;
import java.time.Duration;

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
)
    .waitingFor(
        Wait.forHttps("/")
            .forPort(9200)
            .forStatusCode(200)
            .withBasicCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
            .allowInsecure()  // Trust self-signed certificate
            .withStartupTimeout(Duration.ofSeconds(300))
    );
container.start();

Multiple Containers

Run multiple Elasticsearch containers concurrently:

ElasticsearchContainer container1 = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
);
ElasticsearchContainer container2 = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
);

container1.start();
container2.start();

// Each container gets unique ports
String endpoint1 = container1.getHttpHostAddress();
String endpoint2 = container2.getHttpHostAddress();

// Use containers independently
RestClient client1 = RestClient.builder(HttpHost.create(endpoint1)).build();
RestClient client2 = RestClient.builder(HttpHost.create(endpoint2)).build();

// Cleanup
client1.close();
client2.close();
container1.close();
container2.close();

Custom Network Configuration

import org.testcontainers.containers.Network;

Network network = Network.newNetwork();

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)
    .withNetwork(network);
container.start();

Custom Certificate Path

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
)
    .withCertPath("/custom/path/to/certificate.crt");
container.start();

Inherited Methods from GenericContainer

The ElasticsearchContainer inherits all methods from GenericContainer<ElasticsearchContainer>, providing extensive container management capabilities:

Lifecycle Management:

  • void start() - Start the container (blocks until ready)
  • void stop() - Stop the container
  • void close() - Stop and remove the container (AutoCloseable)

Environment Configuration:

  • ElasticsearchContainer withEnv(String key, String value) - Set environment variable
  • ElasticsearchContainer withEnv(Map<String, String> env) - Set multiple environment variables

File Operations:

  • ElasticsearchContainer withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode) - Mount classpath resource
  • ElasticsearchContainer withCopyToContainer(Transferable transferable, String containerPath) - Copy content to container
  • void copyFileFromContainer(String containerPath, Consumer<InputStream> consumer) - Copy file from container

Network Configuration:

  • ElasticsearchContainer withExposedPorts(Integer... ports) - Expose additional ports
  • Integer getMappedPort(int originalPort) - Get dynamically mapped port
  • String getHost() - Get container host (typically "localhost")
  • ElasticsearchContainer withNetwork(Network network) - Attach to specific network
  • ElasticsearchContainer withNetworkMode(String networkMode) - Set network mode (e.g., "host", "bridge")

Wait Strategies:

  • ElasticsearchContainer waitingFor(WaitStrategy waitStrategy) - Set custom wait strategy
  • ElasticsearchContainer setWaitStrategy(WaitStrategy waitStrategy) - Alternative wait strategy setter

Command Execution:

  • ElasticsearchContainer withCommand(String... commandParts) - Override container command
  • Container.ExecResult execInContainer(String... command) - Execute command in running container

Logging:

  • ElasticsearchContainer withLogConsumer(Consumer<OutputFrame> consumer) - Configure log consumption
  • String getLogs() - Get container logs as string
  • String getLogs(OutputFrame.OutputType... types) - Get filtered container logs

And many more standard container operations available in the Testcontainers GenericContainer API.

Version-Specific Behavior

Elasticsearch 6.x and 7.x

  • Security is optional
  • Use withPassword() to enable X-Pack security
  • HTTP connections (no SSL by default)
  • TransportClient supported (deprecated)
  • Default cluster name: docker-cluster
  • Wait strategy: Log pattern matching for readiness

Elasticsearch 8.x+

  • Security enabled by default
  • Password automatically set to ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD ("changeme")
  • HTTPS/SSL enabled by default with auto-generated self-signed certificate
  • Must use createSslContextFromCa() for HTTPS connections
  • TransportClient not supported (removed in ES 8)
  • Can disable SSL with environment variables for testing
  • Wait strategy: Log pattern matching for readiness

Error Handling

Container Startup Errors

try {
    ElasticsearchContainer container = new ElasticsearchContainer(
        "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
    );
    container.start();
    // Use container
} catch (ContainerLaunchException e) {
    // Container failed to start
    // Check Docker daemon, image availability, system resources
    System.err.println("Container failed to start: " + e.getMessage());
    e.printStackTrace();
} catch (TimeoutException e) {
    // Startup timeout exceeded
    // Increase timeout or check system performance
    System.err.println("Startup timeout: " + e.getMessage());
    e.printStackTrace();
} catch (DockerException e) {
    // Docker daemon not available or image pull failed
    // Check Docker daemon status, network connectivity
    System.err.println("Docker error: " + e.getMessage());
    e.printStackTrace();
} catch (Exception e) {
    // Other unexpected errors
    System.err.println("Unexpected error: " + e.getMessage());
    e.printStackTrace();
}

Authentication Errors

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
);
container.start();

try {
    RestClient client = RestClient
        .builder(HttpHost.create("https://" + container.getHttpHostAddress()))
        .setHttpClientConfigCallback(httpClientBuilder -> {
            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
            );
            httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            httpClientBuilder.setSSLContext(container.createSslContextFromCa());
            return httpClientBuilder;
        })
        .build();

    client.performRequest(new Request("GET", "/"));
    client.close();
} catch (ResponseException e) {
    if (e.getResponse().getStatusLine().getStatusCode() == 401) {
        // Authentication failed
        // Verify password matches expected value
        System.err.println("Authentication failed - check password");
    } else {
        System.err.println("Request failed: " + e.getMessage());
    }
} catch (Exception e) {
    System.err.println("Error: " + e.getMessage());
    e.printStackTrace();
} finally {
    container.close();
}

SSL Certificate Errors

try {
    SSLContext sslContext = container.createSslContextFromCa();
    // Use SSL context
} catch (IllegalStateException e) {
    // CA certificate not found
    // Check if using Elasticsearch 8.x+, verify certificate path
    System.err.println("Certificate not found: " + e.getMessage());
    // Verify ES version is 8.x+ and certificate path is correct
} catch (RuntimeException e) {
    // SSL/certificate errors
    // Check certificate validity, SSL configuration
    System.err.println("SSL error: " + e.getMessage());
    e.printStackTrace();
}

Invalid Configuration Errors

try {
    ElasticsearchContainer container = new ElasticsearchContainer(
        "docker.elastic.co/elasticsearch/elasticsearch-oss:7.9.2"  // OSS image
    )
        .withPassword("mypassword");  // This will throw IllegalArgumentException
    container.start();
} catch (IllegalArgumentException e) {
    // withPassword() not available for OSS images
    // Use default distribution instead
    System.err.println("Invalid configuration: " + e.getMessage());
    // Solution: Use docker.elastic.co/elasticsearch/elasticsearch:7.9.2 instead
}

Common Issues and Solutions

Issue: Connection refused when connecting to Elasticsearch 8.x

Solution: Use HTTPS instead of HTTP and configure SSL context:

RestClient client = RestClient
    .builder(HttpHost.create("https://" + container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder ->
        httpClientBuilder.setSSLContext(container.createSslContextFromCa())
    )
    .build();

Issue: Authentication errors with Elasticsearch 8.x

Solution: Provide credentials (default username is "elastic"):

CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
    AuthScope.ANY,
    new UsernamePasswordCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
);

Issue: Cannot use withPassword() with OSS image

Solution: Use the default distribution instead:

// Instead of elasticsearch-oss image, use:
new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.9.2")
    .withPassword("mypassword");

Issue: Container takes too long to start

Solution: Ensure Docker has adequate resources allocated. Elasticsearch requires at least 2GB RAM (configured by default). You can also increase the startup timeout:

import org.testcontainers.containers.wait.strategy.Wait;
import java.time.Duration;

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
)
    .waitingFor(Wait.forHttp("/").withStartupTimeout(Duration.ofSeconds(300)));
container.start();

Issue: SSL certificate errors with Elasticsearch 8.x

Solution: Use createSslContextFromCa() method to create SSL context:

SSLContext sslContext = container.createSslContextFromCa();
// Use in HTTP client configuration

Issue: Port conflicts

Solution: Container automatically maps to random ports. Use getHttpHostAddress() to get the actual endpoint:

String endpoint = container.getHttpHostAddress();  // Returns "localhost:32768" (varies)

Issue: getHttpHostAddress() called before start()

Solution: Always call start() before accessing container endpoints:

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
);
container.start();  // Must call start() first
String endpoint = container.getHttpHostAddress();  // Now safe to call

Issue: createSslContextFromCa() fails on ES 7.x

Solution: SSL context methods are only available for Elasticsearch 8.x+. For ES 7.x, use HTTP without SSL:

// For ES 7.x, use HTTP
RestClient client = RestClient.builder(
    HttpHost.create(container.getHttpHostAddress())
).build();

Integration with Elasticsearch Clients

REST Client (Low-Level)

import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.apache.http.HttpHost;

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:7.9.2"
);
container.start();

RestClient client = RestClient.builder(
    HttpHost.create(container.getHttpHostAddress())
).build();

// Perform requests
Request request = new Request("GET", "/_cluster/health");
Response response = client.performRequest(request);

client.close();
container.close();

Elasticsearch Java API Client (High-Level)

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;

ElasticsearchContainer container = new ElasticsearchContainer(
    "docker.elastic.co/elasticsearch/elasticsearch:8.1.2"
);
container.start();

// For ES 8.x with HTTPS
RestClient restClient = RestClient
    .builder(HttpHost.create("https://" + container.getHttpHostAddress()))
    .setHttpClientConfigCallback(httpClientBuilder -> {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials("elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
        );
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        httpClientBuilder.setSSLContext(container.createSslContextFromCa());
        return httpClientBuilder;
    })
    .build();

ElasticsearchClient client = new ElasticsearchClient(
    new RestClientTransport(restClient, new JacksonJsonpMapper())
);

// Use the client
client.indices().create(c -> c.index("test-index"));

restClient.close();
container.close();

Important Notes

  • The container is designed for testing and local development, not production use
  • Data is ephemeral and will be lost when the container stops
  • Each container runs an independent Elasticsearch instance
  • The single-node configuration is optimized for fast startup in test environments
  • Containers are automatically cleaned up when using try-with-resources
  • For manual cleanup, call container.close() when done
  • Container ports are randomly assigned to avoid conflicts
  • Multiple containers can run simultaneously (each gets unique ports)
  • Container startup time varies based on system resources and network speed
  • Elasticsearch 8.x requires authentication (handled automatically by container)
  • Elasticsearch 7.x may have different authentication requirements
  • JVM memory settings can be overridden via environment variables
  • Container logs are available via container.getLogs() method
  • Container execution commands can be run via container.execInContainer()
  • TransportClient is deprecated and removed in Elasticsearch 8.x - use REST client instead
  • SSL/HTTPS is enabled by default in Elasticsearch 8.x - use createSslContextFromCa() for connections
  • Configuration methods must be called before start()
  • Access methods must be called after start() completes
  • Always use try-with-resources or explicit cleanup to avoid resource leaks