Published on

Elasticsearch Docker

Authors
  • avatar
    Name
    Shelton Ma
    Twitter

0. 最佳实践

1. 生产环境建议

  • 至少 3 个 Master(不能是 2 个)
  • node.roles 明确区分 Master / Data / Coordinator
  • 启用 xpack.security 避免未授权访问

1. docker搭建

  1. 拉取并运行 Elasticsearch

    # 参数解释:
    # -d:后台运行容器
    # --name elasticsearch:给容器命名
    # -p 9200:9200:映射 REST API 端口
    # -p 9300:9300:映射集群通信端口
    # -e "discovery.type=single-node":单节点模式(适用于开发)
    # -e "ES_JAVA_OPTS=-Xms512m -Xmx512m":限制内存,防止占用过多资源
    
    docker run -d --name elasticsearch \
      -p 9200:9200 -p 9300:9300 \
      -e "discovery.type=single-node" \
      -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
      docker.elastic.co/elasticsearch/elasticsearch:6.8.13
    
  2. 拉取并运行 Kibana

    docker run -d --name kibana \
      -p 5601:5601 --link elasticsearch:elasticsearch \
      docker.elastic.co/kibana/kibana:6.12.0
    

2. docker compose 开发环境搭建, es单节点

1. 创建网络

docker network create es_network

2. 启动时使用es_network网络

  1. docker_compose.yml

    version: "3.8"
    
    services:
      elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
        container_name: elasticsearch
        environment:
          - discovery.type=single-node  # 单节点模式
          - xpack.security.enabled=false # 关闭认证(测试环境)
          - ES_JAVA_OPTS=-Xms512m -Xmx512m # 限制内存
        ports:
          - "9200:9200"
          - "9300:9300"
        volumes:
          - es_data:/usr/share/elasticsearch/data
    
      kibana:
        image: docker.elastic.co/kibana/kibana:8.12.0
        container_name: kibana
        environment:
          - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
        ports:
          - "5601:5601"
        depends_on:
          - elasticsearch
    
    volumes:
      es_data:
        driver: local
    
    networks:
      default:
        name: es_network
        external: true
    
  2. 启动命令 docker-compose -f docker-compose.dev.yml up -d

  3. 访问地址:

3. 生产环境, 高可用集群

  1. 适用于 Kubernetes(EKS)或 Docker Swarm

    • es master节点设置为奇数, 避免split-brain问题
    • 持久化存储(Volumes)
    • 使用统一网络
    • 开启 Heap Dump 以排查 OOM
  2. docker-compose.pod.yml

      version: "3.8"
    
      services:
        es-master:
          image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
          container_name: es-master
          environment:
            - node.name=es-master
            - cluster.name=es-cluster
            - node.roles=master
            - discovery.seed_hosts=es-node1,es-node2
            - cluster.initial_master_nodes=es-master
            - ELASTIC_PASSWORD=changeme  # 生产环境建议更改
            - xpack.security.enabled=true # 启用认证
            - bootstrap.memory_lock=true  # 避免内存交换影响性能
            - ES_JAVA_OPTS=-Xms1g -Xmx1g
          ulimits:
            memlock:
              soft: -1
              hard: -1
          ports:
            - "9200:9200"
          volumes:
            - es_master_data:/usr/share/elasticsearch/data
    
        es-node1:
          image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
          container_name: es-node1
          environment:
            - node.name=es-node1
            - cluster.name=es-cluster
            - node.roles=data
            - discovery.seed_hosts=es-master,es-node2
            - cluster.initial_master_nodes=es-master
            - ELASTIC_PASSWORD=changeme
            - xpack.security.enabled=true
            - bootstrap.memory_lock=true
            - ES_JAVA_OPTS=-Xms1g -Xmx1g
          volumes:
            - es_node1_data:/usr/share/elasticsearch/data
    
        es-node2:
          image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
          container_name: es-node2
          environment:
            - node.name=es-node2
            - cluster.name=es-cluster
            - node.roles=data
            - discovery.seed_hosts=es-master,es-node1
            - cluster.initial_master_nodes=es-master
            - ELASTIC_PASSWORD=changeme
            - xpack.security.enabled=true
            - bootstrap.memory_lock=true
            - ES_JAVA_OPTS=-Xms1g -Xmx1g
          volumes:
            - es_node2_data:/usr/share/elasticsearch/data
    
        kibana:
          image: docker.elastic.co/kibana/kibana:8.12.0
          container_name: kibana
          environment:
            - ELASTICSEARCH_HOSTS=<https://es-master:9200>
            - ELASTICSEARCH_USERNAME=elastic
            - ELASTICSEARCH_PASSWORD=changeme
            - SERVER_SSL_ENABLED=false
          ports:
            - "5601:5601"
          depends_on:
            - es-master
    
      volumes:
        es_master_data:
          driver: local
        es_node1_data:
          driver: local
        es_node2_data:
          driver: local
    
      networks:
        default:
          name: es_network
          external: true
    
      # 开启 Heap Dump 以排查 OOM
      environment: 
        - ES_JAVA_OPTS=-Xms2g -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/share/elasticsearch/logs
    
    
  3. 启动 docker-compose -f docker-compose.prod.yml up -d

4. 背景

1. 什么是脑裂(split brain)问题

在 Elasticsearch(ES)集群 中,Split-Brain(脑裂) 发生在 主节点(Master)竞争 过程中, 网络分区(Network Partition)导致集群分裂为两个或多个独立部分.

后果:

  • 多个主节点同时存在 → 数据更新冲突,导致数据不一致.
  • 部分节点无法访问其他节点 → 影响查询或写入,部分数据丢失.
  • 举个例子: 假设有 3 个节点的集群:node1(Master)、node2、node3, node1 和 node2 突然失去与 node3 的网络连接, node3 认为 node1 挂了,于是自己选举为 Master, 现在 node1 和 node3 都是 Master(脑裂!), 这两个 Master 可能会分别接受写入数据,导致数据不一致

2. 如何解决脑裂问题

Elasticsearch 采用 Zen Discovery(7.x 及以下)和 Cluster Coordination(8.x 及以上)来防止脑裂问题,主要有以下方案:

  1. 确保 Master 节点数量为奇数

    原理:奇数个 Master 通过 "过半数投票" 来避免多个 Master, 3、5、7 个 Master 节点(推荐)

    environment:
      - discovery.seed_hosts=es-master1,es-master2,es-master3
      - cluster.initial_master_nodes=es-master1,es-master2,es-master3
    
  2. 只允许特定节点选举 Master 原理:限制选举 Master 的范围 设置 node.roles=master 只让 Master 角色的节点被选举.- node.roles=master

  3. 配置 minimum_master_nodes(7.x 及以下) 原理:需要至少 N 个 Master 参与选举, 计算公式:minimum_master_nodes = (N / 2) + 1 - discovery.zen.minimum_master_nodes=2