Elasticsearch single node instance using Docker Compose

Elasticsearch single node instance using Docker Compose

Preface

This post assumes that you have some basic understanding of Docker/Podman, Docker Compose, and the key components used in the docker ecosystem. Get up to speed, with the Prepare Your Container Environment with Docker or Podman section of Docker docs.

  1. Install Docker or Podman
  2. install Docker Compose

Deploy Elasticsearch Single node with docker-compose

Elasticsearch single node instance using Docker Compose

Create the docker-compose.yml with the following

 services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch-wolfi:8.17.4
    container_name: elasticsearch
    environment:
      - cluster.name=oio-es-cluster       # Name of your Elasticsearch cluster
      - node.name=es-node                 # Logical name of the node
      - discovery.type=single-node        # Single-node mode (no cluster discovery)
      - bootstrap.memory_lock=true        # Prevent JVM memory from being swapped
      - network.host=0.0.0.0              # Bind to all network interfaces
      - xpack.license.self_generated.type=trial  # Enable trial X-Pack license
      - xpack.security.enabled=false      # Disable security (auth, TLS)
      - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m" # Set JVM heap size to 1GB
    ports: ['9200:9200']
    volumes:
      # Persists Elasticsearch data to a named volume es_data.
      - 'es_data:/usr/share/elasticsearch/data'
    # Checks if ES is up every 30s, times out in 10s, retries 5 times on failure.
    healthcheck:
      test: curl -s http://localhost:9200 >/dev/null || exit 1
      interval: 30s
      timeout: 10s
      retries: 5
volumes:
  es_data:
   

Run

docker-compose up -d

Container Status

docker-compose ps -a

docker container ls 

docker ps -a

Check the APIs

# Get nodes
curl -XGET 'localhost:9200/_cat/nodes?pretty'

# Get health
curl -XGET 'localhost:9200/_cat/health?pretty'

# Cluster stats
curl -XGET 'localhost:9200/_cluster/stats?human&pretty'

# Node Stats
curl -XGET 'localhost:9200/_nodes/stats?pretty'

# A specific node stats:

curl -XGET 'localhost:9200/_nodes/es-node/stats?pretty'

# GET Indices, initially there are no custom indices

curl -XGET 'localhost:9200/_cat/indices?pretty'

# GET ALL Indices

curl -XGET 'localhost:9200/_cat/indices?expand_wildcards=all&pretty'

# Index Level Stats, It includes the stats about the default indices as well. 

curl -XGET 'localhost:9200/_nodes/stats/indices?pretty'

# Retrieve data on plugins or ingest:

curl -XGET 'localhost:9200/_nodes/plugins'

CRUD Operation

Create Index

Without mappings: Elasticsearch auto-generates field types when you index the first document (dynamic mapping).

With mappings: You define field types up front for better control (e.g., setting text vs keyword).

curl -X PUT http://localhost:9200/ramayana_characters -H "Content-Type: application/json" -d '
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "description": { "type": "text" }
    }
  }
}'

OUTPUT

{"acknowledged":true,"shards_acknowledged":true,"index":"ramayana_characters"}
Insert Document
curl -X POST http://localhost:9200/ramayana_characters/_doc -H "Content-Type: application/json" -d '
{
  "name": "Rama",
  "description": "Hero of the Ramayana, seventh avatar of Vishnu."
}'

OUTPUT

{"_index":"ramayana_characters","_id":"_g1qMpYBhtVSA9-yauE0","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}

COPY ID FROM ABOVE OUTPUT "_id":"_g1qMpYBhtVSA9-yauE0" FOR NEXT QUERIES

Select All
curl -X GET 'http://localhost:9200/ramayana_characters/_search?pretty'

OUTPUT

{
  "took" : 154,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "ramayana_characters",
        "_id" : "_g1qMpYBhtVSA9-yauE0",
        "_score" : 1.0,
        "_source" : {
          "name" : "Rama",
          "description" : "Hero of the Ramayana, seventh avatar of Vishnu."
        }
      }
    ]
  }
}
Select by ID

Replace the ID from the previous OUTPUTS

export DOC_ID=_g1qMpYBhtVSA9-yauE0;
curl -X GET "http://localhost:9200/ramayana_characters/_doc/${DOC_ID}?pretty"

OUTPUT

{
  "_index" : "ramayana_characters",
  "_id" : "_g1qMpYBhtVSA9-yauE0",
  "_version" : 2,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "Raama",
    "description" : "Hero of the Ramayana, seventh avatar of Vishnu."
  }
}
Update Document
curl -X POST "http://localhost:9200/ramayana_characters/_update/${DOC_ID}?pretty" -H "Content-Type: application/json" -d '
{
  "doc": {
    "name": "Raama"
  }
}'

OUTPUT

{
  "_index" : "ramayana_characters",
  "_id" : "_g1qMpYBhtVSA9-yauE0",
  "_version" : 2,
  "result" : "noop",
  "_shards" : {
    "total" : 0,
    "successful" : 0,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

Try the GET call again to see the updated value.

Delete Document
curl -X DELETE "http://localhost:9200/ramayana_characters/_doc/${DOC_ID}?pretty"

OUTPUT

{
  "_index" : "ramayana_characters",
  "_id" : "_g1qMpYBhtVSA9-yauE0",
  "_version" : 3,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

Homework

Deploy & Explore

Run the Docker Compose setup and use curl commands to explore APIs (nodes, health, indices). This builds confidence.

Create & Query

Create a simple index, insert documents, and run basic queries (_search, get by ID). Understand JSON structure.

Understand Mappings

Compare behavior with and without mappings to grasp how Elasticsearch treats data.

Check the Cluster Health, it turns yellow

Investigate the reason behind the yellow status of a cluster after creating the first index. Understand the concept of primary shards and replica shards.

Conclusion

With this setup, you can quickly spin up a single-node Elasticsearch and Kibana stack for development or learning purposes, and start exploring powerful search and analytics capabilities using RESTful APIs.