On this page

Skip to content

Installing Elasticsearch and Kibana with Docker Compose

It has been a month since my last note; I've been busy with exercise and fitness, feeling a bit lazy.

I've been wanting to practice with Elasticsearch recently, but I don't want to install these services directly on my local machine. As usual, I'm using Docker to build the environment. Here is a single-node configuration modified from the official Elastic GitHub Docker-Compose example.

Environment Setup

Create Data Directories

First, create the necessary data directories and set the correct permissions to prevent the service from failing to start due to permission issues.

bash
# Create data directory
mkdir -p volumes/elasticsearch/data

# Set permissions (1000 is the user ID inside the Elasticsearch container)
sudo chown -R 1000:1000 volumes

TIP

  • I intentionally did not create a volume for logs, as permission issues with log files can cause startup failures when upgrading or migrating Elasticsearch.
  • Kibana does not store critical data, so no data volume was created for it.

Configuration Files

Environment Variable Settings (.env)

Create a .env file to manage environment variables:

env
# Password for the 'elastic' user (at least 6 characters)
ELASTIC_PASSWORD=YourPassword

# Password for the 'kibana_system' user (at least 6 characters)
KIBANA_PASSWORD=Wing1205

# Version of Elastic products
STACK_VERSION=9.1.4

# Set the cluster name
CLUSTER_NAME=docker-cluster

# Set to 'basic' or 'trial' to automatically start the 30-day trial
LICENSE=basic
#LICENSE=trial

# Port to expose Elasticsearch HTTP API to the host
ES_PORT=9200
#ES_PORT=9200

# Port to expose Kibana to the host
KIBANA_PORT=5601
#KIBANA_PORT=80

# Increase or decrease based on the available host memory (in bytes)
# 1GB = 1073741824 bytes
MEM_LIMIT=2147483648

Docker Compose Configuration

Create a docker-compose.yml file:

yaml
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    container_name: elasticsearch
    restart: always
    environment:
      - node.name=elasticsearch
      - cluster.name=${CLUSTER_NAME}
      - discovery.type=single-node
      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false
      - xpack.security.transport.ssl.enabled=false
      - xpack.license.self_generated.type=${LICENSE}
      - ES_JAVA_OPTS=-Xms512m -Xmx512m -Xlog:gc:stdout:time,level,tags
    volumes:
      - ./volumes/elasticsearch/data:/usr/share/elasticsearch/data
    ports:
      - ${ES_PORT}:9200
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test: ["CMD-SHELL", "curl -s -u elastic:${ELASTIC_PASSWORD} http://localhost:9200/_cluster/health | grep -q 'yellow\\|green'"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s

  kibana:
    depends_on:
      elasticsearch:
        condition: service_healthy
    image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
    container_name: kibana
    restart: always
    environment:
      - SERVER_NAME=kibana
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
    ports:
      - ${KIBANA_PORT}:5601
    mem_limit: ${MEM_LIMIT}
    healthcheck:
      test: ["CMD-SHELL", "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s

  setup:
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    container_name: elasticsearch-setup
    user: "0"
    command: >
      bash -c '
        echo "Waiting for Elasticsearch to start...";
        until curl -s -u elastic:${ELASTIC_PASSWORD} http://elasticsearch:9200/_cluster/health?pretty | grep -q "yellow\|green"; do
          echo "Elasticsearch is not ready yet, waiting...";
          sleep 10;
        done;
        echo "Setting password for kibana_system user...";
        curl -s -X POST -u elastic:${ELASTIC_PASSWORD} -H "Content-Type: application/json" \
          http://elasticsearch:9200/_security/user/kibana_system/_password \
          -d "{\"password\":\"${KIBANA_PASSWORD}\"}";
        echo "Initialization complete!";
      '
    depends_on:
      elasticsearch:
        condition: service_healthy

Configuration Details

Settings

  • Single-node mode: discovery.type=single-node is suitable for development environments.
  • SSL disabled: To simplify configuration, SSL for both HTTP and Transport layers has been disabled.
  • Memory locking: bootstrap.memory_lock=true prevents the JVM heap from being swapped to disk.
  • Health check: Ensures that dependent services only start after the primary service is running normally.
  • kibana_system password: Elasticsearch automatically creates the kibana_system account, but the password is a random string. Therefore, the setup service uses the API to set a specified password.

Common Issues and Solutions

  • Insufficient memory:

    • Adjust MEM_LIMIT in .env or modify ES_JAVA_OPTS.
    • It is recommended to set the JVM Heap to about 50% of the host's memory.
  • Permission issues:

    • Verify that volumes/elasticsearch/data has UID 1000:1000 permissions.
    • If errors persist, you can try sudo chmod -R 777 volumes/elasticsearch/data for testing (development environments only).

Changelog

  • 2025-09-24 Initial document creation.
  • 2025-11-04 Fixed missing restart configuration in the YAML file, which prevented automatic startup after a reboot.