Elasticsearch container
This module helps running elasticsearch using Testcontainers.
Note that it's based on the official Docker image provided by elastic.
Usage example
In the following examples, we will be using the following versions:
static final String ELASTICSEARCH_VERSION_9 = "9.5.2";
static final DockerImageName ELASTICSEARCH_IMAGE_9 = DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
.withTag(ELASTICSEARCH_VERSION_9);
static final String ELASTICSEARCH_VERSION_8 = "8.19.20";
static final DockerImageName ELASTICSEARCH_IMAGE_8 = DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
.withTag(ELASTICSEARCH_VERSION_8);
static final String ELASTICSEARCH_VERSION_7 = "7.17.29";
static final DockerImageName ELASTICSEARCH_IMAGE_7 = DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
.withTag(ELASTICSEARCH_VERSION_7);
From Elasticsearch 8 onwards, security and HTTPS are enabled by default. You can start a container and talk to it with the REST client as follows:
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_LATEST)) {
// Start the container. This step might take some time...
container.start();
// Do whatever you want with the rest client ...
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)
);
client =
RestClient
.builder(HttpHost.create("https://" + container.getHttpHostAddress()))
.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
// SSL is activated by default in Elasticsearch 8+
httpClientBuilder.setSSLContext(container.createSslContextFromCa());
return httpClientBuilder;
})
.build();
Response response = client.performRequest(new Request("GET", "/_cluster/health"));
⋯
}
Disable TLS
HTTPS can be turned off if you do not need it:
// Create the elasticsearch container.
try (
ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_LATEST)
// disable SSL
.withEnv("xpack.security.transport.ssl.enabled", "false")
.withEnv("xpack.security.http.ssl.enabled", "false")
) {
// Start the container. This step might take some time...
container.start();
// Do whatever you want with the rest client ...
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)
);
client =
RestClient
.builder(HttpHost.create(container.getHttpHostAddress()))
.setHttpClientConfigCallback(httpClientBuilder -> {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
})
.build();
Response response = client.performRequest(new Request("GET", "/_cluster/health"));
⋯
}
Elasticsearch 7 (deprecated)
Elasticsearch 7 listens on HTTP and does not enable security unless you opt in with withPassword().
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_7)) {
// Start the container. This step might take some time...
container.start();
client = RestClient.builder(HttpHost.create(container.getHttpHostAddress())).build();
Response response = client.performRequest(new Request("GET", "/_cluster/health"));
⋯
}
⋯
// Create the elasticsearch container.
try (
ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_7)
// With a password
.withPassword(ELASTICSEARCH_PASSWORD)
) {
// Start the container. This step might take some time...
container.start();
// Create the secured client.
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)
);
client =
RestClient
.builder(HttpHost.create(container.getHttpHostAddress()))
.setHttpClientConfigCallback(httpClientBuilder -> {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
})
.build();
Response response = client.performRequest(new Request("GET", "/_cluster/health"));
⋯
}
// Create the elasticsearch container.
try (
ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_7)
// With a password
.withPassword(ELASTICSEARCH_PASSWORD)
) {
// Start the container. This step might take some time...
container.start();
// Create the secured client.
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)
);
client =
RestClient
.builder(HttpHost.create(container.getHttpHostAddress()))
.setHttpClientConfigCallback(httpClientBuilder -> {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
})
.build();
Response response = client.performRequest(new Request("GET", "/_cluster/health"));
⋯
}
The TransportClient
has been removed in Elasticsearch 8. It can still be used against a 7.x container. The default cluster name is
docker-cluster, so you need to change the cluster.name setting or set client.transport.ignore_cluster_name to true.
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_7)) {
// Start the container. This step might take some time...
container.start();
// Do whatever you want with the transport client
TransportAddress transportAddress = new TransportAddress(container.getTcpHost());
String expectedClusterName = "docker-cluster";
Settings settings = Settings.builder().put("cluster.name", expectedClusterName).build();
try (
TransportClient transportClient = new PreBuiltTransportClient(settings)
.addTransportAddress(transportAddress)
) {
ClusterHealthResponse healths = transportClient.admin().cluster().prepareHealth().get();
String clusterName = healths.getClusterName();
⋯
}
}
OSS distribution
The last OSS image is elasticsearch-oss:7.10.2. It does not include features under the Elastic License, and
withPassword() is rejected:
ElasticsearchContainer container = new ElasticsearchContainer(
"docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2"
)
Kibana container
This module also provides a KibanaContainer for testing with Kibana.
Kibana requires a connection to Elasticsearch and KibanaContainer supports two modes: managed and external.
Managed mode
In managed mode, KibanaContainer automatically connects to an ElasticsearchContainer:
// managedModeReachesElasticsearchOnSharedNetwork {
try (
Network network = Network.newNetwork();
ElasticsearchContainer es = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_LATEST).withNetwork(network);
KibanaContainer kibana = new KibanaContainer(es).withNetwork(network)
) {
es.start();
kibana.start();
assertKibanaIsAvailable(kibana);
}
// }
When using managed mode with explicit networks, both containers must share the same Network instance.
Alternatively, you can omit the network configuration entirely, and KibanaContainer will do its best effort to create a shared, ad-hoc network automatically.
External mode
In external mode, KibanaContainer connects to an external Elasticsearch instance via URL and using provided credentials:
final String esHostname = "elasticsearch";
// externalModeReachesElasticsearchWithUsernamePassword {
try (
Network network = Network.newNetwork();
ElasticsearchContainer es = new ElasticsearchContainer(ELASTICSEARCH_IMAGE_LATEST)
.withNetwork(network)
.withNetworkAliases(esHostname)
.withEnv("xpack.security.http.ssl.enabled", "false")
) {
es.start();
String kibanaSystemPassword = setKibanaSystemPassword(es);
try (
KibanaContainer kibana = new KibanaContainer(KIBANA_IMAGE)
.withNetwork(network)
.withElasticsearchUrl("http://" + esHostname + ":9200")
.withKibanaSystemPassword(kibanaSystemPassword)
) {
kibana.start();
assertKibanaIsAvailable(kibana);
}
}
// }
For external mode with HTTPS, use withElasticsearchCaCertificate() to provide the CA certificate.
You can authenticate using either username/password (withElasticsearchCredentials()) or service account tokens (withElasticsearchServiceAccountToken()).
Adding this module to your project dependencies
Add the following dependency to your pom.xml/build.gradle file:
testImplementation "org.testcontainers:testcontainers-elasticsearch:2.0.5"
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-elasticsearch</artifactId>
<version>2.0.5</version>
<scope>test</scope>
</dependency>