Running Elasticsearch and Kibana in Docker: From Local Setup to Java Client Integration

Local Deployment with Docker

Create a dedicated bridge network for the Elastic stack containers:

docker network create elastic-net

Pull the Elasticsearch image and start a single-node instance:

docker pull docker.elastic.co/elasticsearch/elasticsearch:8.9.0

docker run -d --name es-node --network elastic-net \
  -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  docker.elastic.co/elasticsearch/elasticsearch:8.9.0

Reset the built-in elastic user password interactively:

docker exec -it es-node bin/elasticsearch-reset-password -u elastic -i

Pull and launch Kibana on the same network:

docker pull docker.elastic.co/kibana/kibana:8.9.0

docker run -d --name kibana-ui --network elastic-net \
  -p 5601:5601 \
  docker.elastic.co/kibana/kibana:8.9.0

Kibana requires an enrollment token on first startup. Generate it from the Elasticsearch container:

docker exec -it es-node bin/elasticsearch-create-enrollment-token -s kibana

Copy the returned token into the Kibana web UI, then authenticate with the elastic user and the password you set.

Indexing and Searching via REST

Use Dev Tools inside Kibana to execute requests against the cluster.

Store a single document. If the index does not exist, it is created automatically:

POST /clients/_doc/101
{
  "givenName": "Diana",
  "familyName": "Prince"
}

Fetch that document by its identifier:

GET /clients/_doc/101

To ingest several documents at once, use the _bulk endpoint with newline-delimited JSON (NDJSON). Every line, including the last, must terminate with a newline:

PUT /clients/_bulk
{ "index": { } }
{ "givenName": "Bruce", "familyName": "Wayne" }
{ "index": { } }
{ "givenName": "Clark", "familyName": "Kent" }
{ "index": { } }
{ "givenName": "Barry", "familyName": "Allen" }
{ "index": { } }
{ "givenName": "Diana", "familyName": "Prince" }

Search for every document whose givenName matches Diana:

GET /clients/_search
{
  "query": {
    "match": { "givenName": "Diana" }
  }
}

To inspect data visually, open Stack Management > Data Views, define a view for clients, then navigate to Analytics > Discover.

Working with the Java API Client

Include the following Maven dependencies:

<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.9.0</version>
</dependency>

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart</artifactId>
    <version>7.1.0</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.15.2</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.15.2</version>
</dependency>

<dependency>
    <groupId>jakarta.json</groupId>
    <artifactId>jakarta.json-api</artifactId>
    <version>2.0.1</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>8.9.0</version>
</dependency>

Configure the client. The snippet below bypasses SSL verification and hostname checks, which is acceptable only for local development:

RestClientBuilder clientBuilder = RestClient.builder(
    new HttpHost("localhost", 9200, "https")
);

BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
    AuthScope.ANY,
    new UsernamePasswordCredentials("elastic", "your-password-here")
);

SSLFactory tlsFactory = SSLFactory.builder()
    .withUnsafeTrustMaterial()
    .withUnsafeHostnameVerifier()
    .build();

clientBuilder.setHttpClientConfigCallback(http -> http
    .setDefaultCredentialsProvider(credsProvider)
    .setSSLContext(tlsFactory.getSslContext())
    .setSSLHostnameVerifier(tlsFactory.getHostnameVerifier())
);

RestClient httpClient = clientBuilder.build();
ElasticsearchTransport transport = new RestClientTransport(
    httpClient, new JacksonJsonpMapper()
);
ElasticsearchClient esClient = new ElasticsearchClient(transport);

Define a simple antity class:

public class Merchandise {
    private String sku;
    private String title;
    private double cost;

    public Merchandise(String sku, String title, double cost) {
        this.sku = sku;
        this.title = title;
        this.cost = cost;
    }

    public String getSku() { return sku; }
    public String getTitle() { return title; }
    public double getCost() { return cost; }
}

Index a new document in to the inventory index:

Merchandise item = new Merchandise("sku-1001", "Mechanical Keyboard", 89.99);

IndexResponse idxResp = esClient.index(idx -> idx
    .index("inventory")
    .id(item.getSku())
    .document(item)
);

System.out.println("Version: " + idxResp.version());

Retrieve the document by SKU:

GetResponse<Merchandise> getResp = esClient.get(g -> g
    .index("inventory")
    .id("sku-1001"),
    Merchandise.class
);

if (getResp.found()) {
    Merchandise found = getResp.source();
    System.out.println("Retrieved: " + found.getTitle());
} else {
    System.out.println("Document not found");
}

Apply a partial update with a map of changed fields:

Map<String, Object> changes = new HashMap<>();
changes.put("title", "Wireless Mechanical Keyboard");
changes.put("cost", 109.99);

UpdateResponse<Merchandise> updResp = esClient.update(u -> u
    .index("inventory")
    .id("sku-1001")
    .doc(changes),
    Merchandise.class
);

Tags: elasticsearch kibana docker java REST API

Posted on Tue, 06 Oct 2026 16:35:00 +0000 by phouchin