使用Docker部署用于学习的ElasticSearch集群

原创 吴就业 104 0 2020-03-08

本文为博主原创文章,未经博主允许不得转载。

本文链接:https://wujiuye.com/article/bbb5ab12b7674d0cb391ae7a7eeb2269

作者:吴就业
链接:https://wujiuye.com/article/bbb5ab12b7674d0cb391ae7a7eeb2269
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。

在Linux服务器上使用 Docker安装ElasticSearch集群。

安装Docker和安装Docker Compose

安装Docker略。

由于是部署伪集群,以及需要安装kibana,因此还需要安装Docker-ComposeDocker-Compose负责实现对Docker容器集群的快速编排。

Docker-Compose项目是由Python编写的,而pipPython包管理工具,该工具提供了对Python包的查找、下载、安装、卸载的功能。因此,安装Docker-Compose之前,需要先安装Python环境,以及安装pip,再通过pip安装Docker-Compose

我其实并不懂Python,但是知其然知其所以然,还是要了解一下,为什么要使用pip安装Docker-Compose的。

使用yum安装pip

yum -y install python-pip

使用pip安装docker-compose

pip install docker-compose

这是我从网上找的一篇博客介绍的docker-compose的安装教程,可能这篇博客是很早以前写的,因此并不能安装成功。我跟着提示弄了大概一个多小时,过程就略过了。原因是python版本太低,需要使用yum安装新版本的pythonpip。我升级到3.4版本之后还是提示版本过低,安装不了。

RuntimeError: Python 3.5 or later is required

提示需要python3.5或更高的版本。根据提示,我又卸载了3.4版本,重新安装了3.6版本。

## 安装EPEL和IUS软件源
yum -y install epel-release
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
## 安装python和pip
yum -y install python36u
yum -y install python36u-pip

关于3.6版本的安装,可以参考这篇博客:Centos7 通过yum安装python3,及virtualenv基本使用。

查看python3.6是否安装成功

[root@wujiuye01 data]# ls -la /usr/bin/python*
lrwxrwxrwx. 1 root root     7 Oct  8 17:14 /usr/bin/python -> python2
lrwxrwxrwx. 1 root root     9 Oct  8 17:14 /usr/bin/python2 -> python2.7
-rwxr-xr-x. 1 root root  7216 Aug  7  2019 /usr/bin/python2.7
lrwxrwxrwx  1 root root     9 Mar  8 16:39 /usr/bin/python3 -> python3.6
-rwxr-xr-x  2 root root 11408 Aug  8  2019 /usr/bin/python3.6
....

pip对应也是3.6版本

[root@wujiuye01 data]# ls -la /usr/bin/pip*
-rwxr-xr-x 1 root root 223 Mar  8 16:28 /usr/bin/pip
-rwxr-xr-x 1 root root 224 Mar  8 15:57 /usr/bin/pip2
-rwxr-xr-x 1 root root 224 Mar  8 15:57 /usr/bin/pip2.7
lrwxrwxrwx 1 root root   9 Mar  8 16:39 /usr/bin/pip-3 -> ./pip-3.6 #软链接
lrwxrwxrwx 1 root root   8 Mar  8 16:39 /usr/bin/pip-3.6 -> ./pip3.6 #软链接
-rwxr-xr-x 1 root root 407 Aug  8  2019 /usr/bin/pip3.6

因为我只是想安装docker-compose,就不想改pip软链接到pip3.6了,而是直接使用pip3.6安装。

pip-3.6 install docker-compose

如果想要卸载docker-compose,也是很简单。

pip-3.6 uninstall docker-compose

编写docker-compose.yml

Docker-Compose的工程配置文件默认为docker-compose.yml。我需要启动一个cerebro服务容器、一个kibana服务容器、两个elasticsearch服务容器,因此docker-compose.yml的配置如下。

来源于:https://github.com/onebirdrocks/geektime-ELK,稍有改动:

version: '2.2'
services:
  # cerebro
  cerebro:
    image: lmenezes/cerebro:0.8.3
    container_name: cerebro
    ports:
      - "9000:9000"
    command:
      - -Dhosts.0.host=http://【外网访问的es集群的ip或域名】:9200
    networks:
      - wjy-es-net
  # kibana
  kibana:
    image: docker.elastic.co/kibana/kibana:7.1.0
    container_name: kibana
    environment:
      - I18N_LOCALE=zh-CN
      - XPACK_GRAPH_ENABLED=true
      - TIMELION_ENABLED=true
      - XPACK_MONITORING_COLLECTION_ENABLED="true"
    ports:
      - "5601:5601"
    networks:
      - wjy-es-net
  # elasticsearch节点1
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
    container_name: es-node-01
    environment:
      - cluster.name=wjy-es-stu-cluster
      - node.name=es-node-01
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - discovery.seed_hosts=es-node-01,es-node-02
      - cluster.initial_master_nodes=es-node-01,es-node-02
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - "/data/docker/es7cluster/es-node1-data:/usr/share/elasticsearch/data"
    ports:
      - "9200:9200"
    networks:
      - wjy-es-net
  # elasticsearch节点2
  elasticsearch2:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
    container_name: es-node-02
    environment:
      - cluster.name=wjy-es-stu-cluster
      - node.name=es-node-02
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - discovery.seed_hosts=es-node-01,es-node-02
      - cluster.initial_master_nodes=es-node-01,es-node-02
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - "/data/docker/es7cluster/es-node2-data:/usr/share/elasticsearch/data"
    networks:
      - wjy-es-net

networks:
  wjy-es-net:
    driver: bridge

关于docker-compose.yml配置文件:

让服务后台运行,并查询容器启动情况

docker-compose相关命令:

 # 启动
 docker-compose up
 # 后台启动
 docker-compose up -d
 # 停止
 docker-compose down
 # 停止容器并且移除数据
docker-compose down -v

第一次执行docker-compose up会很久,因为需要从远程拉取镜像文件,大概又是一个多小时。

可能出现问题一:

es7_01            | "stacktrace": ["org.elasticsearch.bootstrap.StartupException: ElasticsearchException[failed to bind service]; nested: AccessDeniedException[/usr/share/elasticsearch/data/nodes];",
......
"Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes",
.....

容器卷本地目录没有权限访问,需要给目录添加写权限。

可能出现问题二:

es_node_02        | ERROR: [1] bootstrap checks failed
es_node_02        | [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

elasticsearch用户拥有的内存权限太小,至少需要262144

## 切换到root用户,执行命令:
sysctl -w vm.max_map_count=262144

使用docker-compose up -d启动服务,让所有容器能够后台运行。使用docker命令查询容器。

[root@wujiuye01 es7cluster]# docker container ls
CONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                              NAMES
04f51ce794f9        docker.elastic.co/kibana/kibana:7.1.0                 "/usr/local/bin/kiba…"   8 minutes ago       Up 3 minutes        0.0.0.0:5601->5601/tcp             kibana
ad50d72184d6        lmenezes/cerebro:0.8.3                                "/opt/cerebro/bin/ce…"   8 minutes ago       Up 3 minutes        0.0.0.0:9000->9000/tcp             cerebro
ea3c3e0aee7d        docker.elastic.co/elasticsearch/elasticsearch:7.1.0   "/usr/local/bin/dock…"   8 minutes ago       Up 3 minutes        9200/tcp, 9300/tcp                 es-node-02
a14d52910fe6        docker.elastic.co/elasticsearch/elasticsearch:7.1.0   "/usr/local/bin/dock…"   8 minutes ago       Up 3 minutes        0.0.0.0:9200->9200/tcp, 9300/tcp   es-node-01

访问

服务器安全组记得开放相应的端口。

http://【ip或域名】:9200

http://【ip或域名】:9000

img

http://【ip或域名】:5601

img

后记

docker-compose.yml配置文件中,只配置了第一个ES节点的端口,第二个节点并没有配置端口,而是使用默认端口9300。这个docker-compose.yml文件我是从github找来的,当时我就有个疑问,就是第二个ES节点是怎么加入到集群的?

我们熟悉的微服务框架dubbo、消息中间件kafka等都是基于一个第三方服务实现注册发现的,如使用zookeeper。在dubbo中,其实还提供了一个基于广播的注册中心,dubbo的使用入门例子就是用的广播注册中心。而ES的集群发现则是使用其内置的发现模块。

ES集群发现机制有两种,分别是Zen DiscoveryEC2 discovery。其中zen discoveryES默认使用的内置发现模块,它提供了多播和单播两种发现方式。

使用组播(多播),我们只需要在每个节点配置好集群名称、节点名称。节点会根据ES自定义的服务发现协议去按照多播的方式来寻找网络上配置在同样集群内的节点。

虽然组播仍然作为插件提供,但不应该在生产环境使用。

单播发现需要一个主机列表充作路由列表。这些主机可以是主机名称也可以是IP地址,在每次ping的时候主机名称会相应地被解析为对应的ip地址。

7.x之前的版本,配置参数为discovery.zen.ping.unicast.hosts,Zen Discovery的官方文档中描述:

img

hosts配置多个需要用逗号隔开,每一项都是host:port,如果只有host,则默认端口号为93007.1版本的配置参数为:discovery.seed_hosts

单播发现是使用传输(transport)模块实现的,就不是使用UDP协议了。传输(transport)模块用于集群内节点之间的内部通信。ES集群内部,从一个节点到另一个节点的每个调用都使用传输模块。

最后介绍一下组播的实现,以此了解为什么ES默认禁用组播方式,以及dubbo的基于广播实现的注册中心为什么只能适用于本地测试。

public class MulticastSocketMain {

    /**
     * 接收
     */
    public void startRevice() throws IOException {
        // 组播地址
        InetAddress boradcastAddrss = InetAddress.getByName("239.255.255.255");

        // 创建MulticastSocket对象
        MulticastSocket mSocket = new MulticastSocket(3006);
        // 将该MulticastSocket加入到组播
        mSocket.joinGroup(boradcastAddrss);
        // 设置本MulticastSocket发送的数据报会被回送到自身
        // true表示不会回送(本机测试需要设置为false)
        mSocket.setLoopbackMode(false);

        // 创建相关的DatagramPacket,用于接受数据
        byte[] inBuff = new byte[1024];
        DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);

        while (!Thread.interrupted()) {
            // 等待接收数据
            mSocket.receive(inPacket);
            String recevieMsgStr = new String(inBuff, 0, inPacket.getLength());
            System.out.println("接收到广播消息:" + recevieMsgStr);
        }
    }

    /**
     * 发送
     */
    public void startSend() throws IOException {
        // 组播地址
        InetAddress boradcastAddrss = InetAddress.getByName("239.255.255.255");

        // 创建MulticastSocket对象
        MulticastSocket mSocket = new MulticastSocket(3006);
        // 将该MulticastSocket加入到组播地址中
        mSocket.joinGroup(boradcastAddrss);
        // 设置本MulticastSocket发送的数据报会被回送到自身
        // true表示不会回送(本机测试需要设置为false)
        mSocket.setLoopbackMode(false);

        // 创建用于发送数据的DatagramPacket
        byte[] inBuff = new byte[1024];
        DatagramPacket outPacket = new DatagramPacket(inBuff, inBuff.length, boradcastAddrss, 3006);

        // 从控制台读取一行字符串发送
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            byte[] outBuff = sc.nextLine().getBytes();
            outPacket.setData(outBuff);
            // 发送数据
            mSocket.send(outPacket);
        }
    }

    public static void main(String[] args) throws IOException {
        MulticastSocketSendMain multicastSocketSendMain = new MulticastSocketSendMain();
        // 接收
        new Thread() {
            @Override
            public void run() {
                try {
                    multicastSocketSendMain.startRevice();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        // 发送
        new Thread() {
            @Override
            public void run() {
                try {
                    multicastSocketSendMain.startSend();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

}

demo要运行需要配置VM参数:

-Djava.net.preferIPv4Stack=true

IPV4的广播地址范围是: 224.0.0.0 - 239.255.255.255dubbo的广播注册中心使用的是239.255.255.255,所以例子中我就使用239.255.255.255做测试了。

如果将上面例子MulticastSocketMain启动多个进程,那么在任意一个接收者上发送消息其它进程都能接收到。想看测试结果,可将上面代码复制下来运行。

如果当前是线上环境,我突然启动一个服务,但并不想加入到集群中,但是节点启动就发广播,线上的服务接收到广播就认为你要新增节点了。这样得到的结果就是一个节点意外的加入到了生产环境,仅仅是因为一个错误的组播信号。

因此ES默认被配置为使用单播发现,以防止节点无意中加入集群。

#后端

声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。

文章推荐

教你如何写出高性能的Mybatis分页插件

本篇介绍是什么原因导致的`mybatis-plus`分页插件性能下降,以及如何通过使用`JsqlParser`这个开源的`sql`解析工具包与`mybatis-plus`提供的自定义`sql`优化器功能,自己实现高性能的分页插件。

一道很有意思的Redis面试题,关于Bitmap算法,我选出了一些优质评论

起源于我在一个短视频中分享的一道面试题,当然,这道面试题我确实在工作中用过,只是业务场景不同。

一篇文章说清楚Java的全局异常处理,深入到hotspot源码

本篇将介绍如何使用Java提供的全局异常处理,以及分析一点hotspot虚拟机的源码,让大家了解虚拟机是如何将异常交给全局异常处理器处理的。

使用Mybatis-Plus提高开发效率

使用`mybatis-plus`可以少写很多常用的`SQL`,通过继承`BaseMapper`使用,还可以动态拼接`SQL`。第一眼看到我还以为是`JPA`。

ElasticSearch高版本API的使用姿势

如何在`Java`项目中使用`elasticsearch-rest-high-level-client`。

64位JVM的Java对象头详解

在学习并发编程知识`synchronized`时,我们总是难以理解其实现原理,因为偏向锁、轻量级锁、重量级锁都涉及到对象头,所以了解`java`对象头是我们深入了解`synchronized`的前提条件。