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.
- Install Docker or Podman
- 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.