Setting Up Elasticsearch with Docker

Series: Elasticsearch 101 | Article: 02


Overview

Running Elasticsearch locally should not require an AWS account, an Elastic Cloud trial, or a multi-node cluster. A single-node Docker Compose stack with Kibana covers everything needed for local development and most testing scenarios.

This article sets up a local environment that I use as the baseline for all subsequent articles in this series.


Prerequisites

  • Docker Desktop (or Docker Engine + Docker Compose plugin)

  • At least 4 GB of memory allocated to Docker — Elasticsearch's JVM needs headroom

  • curl or any HTTP client (HTTPie, Bruno, Postman all work fine)


Single-Node Docker Compose Setup

Create a project directory and a docker-compose.yml file:

# docker-compose.yml
version: "3.8"

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=local-dev
      - discovery.type=single-node
      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD:-changeme}
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false   # HTTP only for local dev
      - xpack.security.transport.ssl.enabled=false
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    healthcheck:
      test: >
        curl -s -u elastic:${ELASTIC_PASSWORD:-changeme}
        http://localhost:9200/_cluster/health
        | grep -qE '"status":"(green|yellow)"'
      interval: 15s
      timeout: 10s
      retries: 8
      start_period: 30s

  kibana:
    image: docker.elastic.co/kibana/kibana:8.17.0
    container_name: kibana01
    depends_on:
      elasticsearch:
        condition: service_healthy
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD:-changeme}
    ports:
      - "5601:5601"

volumes:
  es_data:
    driver: local

Create a .env file alongside it:

Note: These are plain HTTP credentials for local development. In production, always enable TLS and use strong generated passwords.


Starting the Stack

Watch the logs until both services are up:

Elasticsearch is ready when you see a log line like:

(Yellow is expected on a single-node cluster because primary shards have no replicas to assign.)


Verifying Elasticsearch

Expected response:

Check cluster health:

Yellow status on a single-node cluster means all primary shards are assigned but replicas cannot be (there is only one node). This is fine for development.


Setting Up the Kibana System User

When security is enabled, Kibana uses the kibana_system user to communicate with Elasticsearch. This user's password needs to match KIBANA_PASSWORD in the Compose file. Set it via the API:

Then restart Kibana:

Access Kibana at http://localhost:5601. Log in with elastic / changeme.


Kibana Dev Tools

Kibana's Dev Tools console (Menu → Management → Dev Tools) is the most convenient way to run Elasticsearch queries interactively. It auto-completes API paths and request bodies, and handles authentication transparently.

Example interaction in Dev Tools:

I use Dev Tools for exploring queries during development, then translate them to Go code once the query shape is correct.


Common Memory Issue

Elasticsearch requires vm.max_map_count to be at least 262144 on Linux hosts. On macOS with Docker Desktop this is handled transparently. On Linux, run:

To persist it:

If Elasticsearch exits immediately with max virtual memory areas vm.max_map_count [65530] is too low, this is the fix.


Stopping and Cleaning Up

Stop the stack without losing data:

Remove the stack and all data:


Pinning Versions

Always pin image versions in docker-compose.yml. Elastic moves quickly between minor versions and occasionally introduces breaking mapping or query behavior changes. I use the same version locally as I deploy to production. Mismatches between the client library version and the server version have caused me subtle issues that were hard to trace.

Use the same minor version across elasticsearch, kibana, and the go-elasticsearch client module.


Summary

  • A single-node Elasticsearch + Kibana stack runs cleanly on Docker Compose.

  • discovery.type=single-node bypasses the multi-node leader election requirement.

  • Yellow cluster status on single-node is expected — not an error.

  • Use Kibana Dev Tools for interactive query development before writing application code.

  • Pin major/minor versions across the stack.


Previous: What is Elasticsearch and When to Use It | Next: Indexing Documents and Mappings

Last updated