① Elasticsearch 搭建

1. 创建配置文件

es一般是集群使用,本次会在一台测试服务器上搭建三个es节点,每个节点需要一个配置文件在/disk1/elasticsearch/config/ 路径下创建3个文件夹es-node1、es-node2、es-node3,每个文件夹上分别创建每个节点对应的配置文件:es-node1.yml、es-node2.yml、 es-node3.yml

es-node1.yml

#集群名称
cluster.name: elasticsearch-cluster         

#本node节点的名称        
node.name: es-node1 

#设置可以访问的ip,可以是ipv4或ipv6的,默认为0.0.0.0,这里全部设置通过
network.bind_host: 0.0.0.0  

#设置其它结点和该结点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址
network.publish_host: 127.0.0.1 

#设置对外服务的http端口,默认为9200
http.port: 8201 

#设置节点之间交互的tcp端口,默认是9300
transport.tcp.port: 8301 

#是否允许跨域REST请求
http.cors.enabled: true 

#允许 REST 请求来自何处
http.cors.allow-origin: "*" 

#是否可以为主节点。这个属性表示节点是否具有成为主节点的资格注意
node.master: true 

#这个属性表示节点是否存储数据
node.data: true   

#设置集群列表
discovery.zen.ping.unicast.hosts: ["127.0.0.1:8301","127.0.0.1:8302","127.0.0.1:8303"] 

#配置当前集群中最少的主节点数,防止脑裂。
discovery.zen.minimum_master_nodes: 2 

es-node2.yml

cluster.name: elasticsearch-cluster
node.name: es-node2
network.bind_host: 0.0.0.0
network.publish_host: 127.0.0.1
http.port: 8202
transport.tcp.port: 8302
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true  
discovery.zen.ping.unicast.hosts: ["127.0.0.1:8301","127.0.0.1:8302","127.0.0.1:8303"]
discovery.zen.minimum_master_nodes: 2

es-node3.yml

cluster.name: elasticsearch-cluster
node.name: es-node3
network.bind_host: 0.0.0.0
network.publish_host: 127.0.0.1
http.port: 8203
transport.tcp.port: 8303
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true  
discovery.zen.ping.unicast.hosts: ["127.0.0.1:8301","127.0.0.1:8302","127.0.0.1:8303"]
discovery.zen.minimum_master_nodes: 2

三个配置其实就是端口和节点名称略有不同,如果不搭集群,只用单个es配置可以删除discovery.zen.ping.unicast.hosts和discovery.zen.minimum_master_nodes

2. 调高JVM线程数限制数量

一般启动时会报错:ootstrap checks failed max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144] 这时候就应该修改配置sysctl.conf

vim /etc/sysctl.conf

加入下面内容:

vm.max_map_count=262144

启动配置:

sysctl -p

三. 启动es集群容器

实际就是启动docker镜像,执行下面命令:

docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 8201:8201 -p 8301:8301 -v /disk1/elasticsearch/config/es-node1/es-node1.yml:/usr/share/elasticsearch/config/elasticsearch.yml --name ES01 elasticsearch:5.6
docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 8202:8202 -p 8302:8302 -v /disk1/elasticsearch/config/es-node2/es-node2.yml:/usr/share/elasticsearch/config/elasticsearch.yml --name ES02 elasticsearch:5.6
docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 8203:8203 -p 8303:8303 -v /disk1/elasticsearch/config/es-node3/es-node3.yml:/usr/share/elasticsearch/config/elasticsearch.yml --name ES03 elasticsearch:5.6

说明一下es的默认端口:

ps:设置-e ES_JAVA_OPTS="-Xms512m -Xmx512m" 是因为/etc/elasticsearch/jvm.options 默认jvm最大最小内存是2G,也可以直接进去容器修改配置(-Xms512m #总堆空间的初始大小,主要是改这里和下面的参数,所占大小尽量大。 -Xmx512m #总堆空间的最大大小,如我们是64G的内存初始就是32G,官网推荐最多是物理内存的一半)启动容器后可用docker stats命令查看

四. 验证是否搭建成功

1. 在浏览器地址栏访问http://127.0.0.1:8201/_cat/nodes?pretty 查看节点状态

127.0.0.1 32 99 6 1.00 1.44 1.52 mdi - es-node1
127.0.0.1 81 99 6 1.00 1.44 1.52 mdi * es-node2
127.0.0.1 58 99 6 1.00 1.44 1.52 mdi - es-node3
PS:节点名称带\表示为主节点*

不带任何参数表示访问单独节点:http://127.0.0.1:8201

2.使用elasticsearch-head前端框架

安装分词器需要根据es版本选择对应版本,有两种方法安装:

1.在线下载安装:

ps:采取第一种方法时重启报错,提示版本号不一致,故我这边采取第二种方法

3.检查:

在创建index和type后(下面有说明),添加数据可以查看分词效果

$ curl -X GET 'http://127.0.0.1:8201/project/_analyze?field=content&text=我爱中国'

如果不是每个字都拆开说明不是使用默认分词器

② Elasticsearch 使用

一. 基本概念

使用es前需要理解一下基本概念:

1.Node 与 Cluster

es 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。 单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。

2.Index

Elastic 数据管理的顶层单位就叫做 Index(索引)。类型等同于传统的关系型数据库的名称。每个 Index (即数据库)的名字必须是小写。

3.Type

类型是索引内部的逻辑分区(category/partition),然而其意义完全取决于用户需求。类型等同于传统的关系型数据库的表

4.Document

Index 里面单条的记录称为 Document(文档)。基于JSON格式进行表示,类型等同于传统的关系型数据库的列

5.Mapping

Mapping 是定义document,其包含的字段,字段存储,字段类型和索引

6.Shard

Shard是分片:因为 ES 是个分布式的搜索引擎, 所以索引通常都会分解成不同部分, 而这些分布在不同节点的数据就是分片,默认为5

6.Replica

Replica是副本:ES 默认为一个索引创建 5 个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由 5 个主分片成本, 而每个主分片都相应的有一个 copy。

Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。

二. 增删改查

ps:第二点主要介绍用API进行增删改查,一般不会重点使用,而是把es集成到springboot中代码进行增删改查

es提供基于restful风格的API接口来进行增删改查

1.新建一个Index和Type

新建一个 Index,指定需要分词的字段。这一步根据数据结构而异,下面的命令只针对本文。基本上,凡是需要搜索的中文字段,都要单独设置一下。

$ curl -X PUT 'http://127.0.0.1:8201/project' -d '
{
  "mappings": {
    "tb_elasticsearch_test": {
      "properties": {
        "id": {
          "type": "long"
        },
        "number": {
          "type": "float"
        },
        "createTime": {
          "type": "long"
        },
        "updateTime": {
          "type": "long"
        },
        "content": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        },
        "elaseicsearchTestId": {
          "type": "long"
        }
      }
    }
  }
}'

上面代码中,首先新建一个名称为project的 Index,里面有一个名称为tb_elasticsearch_test的 Type。tb_elasticsearch_test有六个字段。 相当于创建数据库和表,其他操作只需更改方法类型(GET,PUT,DELETE,POST)

1.新建一个Document(插入一条数据)

向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向/project/tb_elasticsearch_test发送请求,就可以新增一条记录。

$ curl -X PUT 'http://127.0.0.1:8201/project/tb_elasticsearch_test/1' -d '
{
  "id": 1,
  "elasticsearchTestId": 1,
  "content": null,
  "number": 0.05,
  "createTime": 1555059048000,
  "updateTime": 1555059050000
}'

服务器返回的 JSON 对象,会给出 Index、Type、Id、Version 等信息

{
  "_index":"project",
  "_type":"tb_elasticsearch_test",
  "_id":"1",
  "_version":1,
  "result":"created",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":true
}

此时请求路径指定了id,/project/tb_elasticsearch_test/1,如不指定 Id,这时要改成 POST 请求,_id字段就是一个随机字符串。

2.查询一条数据

向指定的 /Index/Type 发送 GET 请求

$ curl 'http://127.0.0.1:8201/project/tb_elasticsearch_test/1?pretty=true'

pretty=true表示以易读的格式返回。 返回的数据中,found字段true表示查询成功,查不到数据,found字段就是false,_source字段返回原始记录。

{
  "_index" : "project",
  "_type" : "tb_elasticsearch_test",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "id" : 1,
    "elasticsearchTestId" : 1,
    "content" : null,
    "number" : 0.05,
    "createTime" : 1555059048000,
    "updateTime" : 1555059050000
  }
}

3.更新数据

向指定的 /Index/Type/id 发送 PUT 请求

$ curl -X PUT 'http://127.0.0.1:8201/project/tb_elasticsearch_test/1' -d '
{
  "id": 1,
  "elasticsearchTestId": 1,
  "content": "aaa",
  "number": 0.06,
  "createTime": 1555059048000,
  "updateTime": 1555059050000
}'

返回

{
    "_index": "project",
    "_type": "tb_elasticsearch_test",
    "_id": "1",
    "_version": 2,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 2,
        "failed": 0
    },
    "created": false
}

4.删除一条记录

删除记录就是发出 DELETE 请求。

$ curl -X DELETE 'http://127.0.0.1:8201/project/tb_elasticsearch_test/1'

返回

{
    "found": true,
    "_index": "project",
    "_type": "tb_elasticsearch_test",
    "_id": "1",
    "_version": 3,
    "result": "deleted",
    "_shards": {
        "total": 2,
        "successful": 2,
        "failed": 0
    }
}

5.简单查询

{
  "query": {
    "multi_match": {
      "query": "测试",
      "fields": [
        "content",
        "number"
      ],
      "tie_breaker": 0.3
    }
  }
}

三. springboot集成es

1.添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2.配置文件添加:

和es配置文件对应

spring:
    data:
        elasticsearch:
            cluster-name: elasticsearch-cluster
            cluster-nodes: 127.0.0.1:8301,127.0.0.1:8302,127.0.0.1:8303
            repositories:
                enabled: true

3.创建对应实体类:

创建ElasticsearchTestEntity.class并添加注解@Document(indexName = "project", type = "tb_elasticsearch_test")

import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import javax.persistence.Id;
import java.math.BigDecimal;
import java.util.Date;

@Document(indexName = "project", type = "tb_elasticsearch_test")
@Data
public class ElasticsearchTestEntity {
    @Id //主键只能叫id,@Id注解加上后,在Elasticsearch里相应于该列就是主键了,在查询时就可以直接用主键查询
    private Integer id;

    private Integer elasticsearchTestId;

    @Field(searchAnalyzer = "ik_max_word", analyzer = "ik_max_word", type = FieldType.Text)
    private String content;

    private BigDecimal number = BigDecimal.ZERO;

    private Date createTime = new Date();

    private Date updateTime = new Date();
}

@Document注解里面的几个属性,类比mysql

Ⅰ @Document注解

String indexName();//索引库的名称,建议以项目的名称命名
String type() default "";//类型,建议以实体的名称命名
short shards() default 5;//默认分区数
short replicas() default 1;//每个分区默认的备份数
String refreshInterval() default "1s";//刷新间隔
String indexStoreType() default "fs";//索引文件存储类型
Ⅱ @Field注解
public @interface Field {
FieldType type() default FieldType.Auto;#自动检测属性的类型
FieldIndex index() default FieldIndex.analyzed;#默认情况下分词
DateFormat format() default DateFormat.none;
boolean fileddata() default false;#默认不把字段数据全部读取到内存中进行操作
String pattern() default "";
boolean store() default false;#默认情况下不存储原文
String searchAnalyzer() default "";#指定字段搜索时使用的分词器
String indexAnalyzer() default "";#指定字段建立索引时指定的分词器
String[] ignoreFields() default {};#如果某个字段需要被忽略
boolean includeInParent() default false;
}

重点说明一下type中的text和keyword 一般用于字符串类型

Ⅲ @MultiField注解

该字段使用text时如果进行分组查询,会根据分词后的内容分组,而不是完整的内容分组,如:想用“国泰君安”聚合,结果使用“国泰”,“君安”聚合 如果想要根据所有内容分组,就需要用@MultiField,把内容改为:

import lombok.Data;
import org.springframework.data.elasticsearch.annotations.*;

import javax.persistence.Id;
import java.math.BigDecimal;
import java.util.Date;

@Document(indexName = "project", type = "tb_elasticsearch_test")
@Data
public class ElasticsearchTestEntity {
    @Id
    private Integer id;

    private Integer elasticsearchTestId;

    @MultiField(
            mainField = @Field(searchAnalyzer = "ik_max_word", analyzer = "ik_max_word", type = FieldType.Text, fielddata = true),
            otherFields = {@InnerField(suffix = "raw", type = FieldType.Keyword)})
    private String content;

    private BigDecimal number = BigDecimal.ZERO;

    private Date createTime = new Date();

    private Date updateTime = new Date();
}

这样需要分词列名可以使用content,不需要分词时列名可以使用content.raw

*ps:字段的分词器创建不能更改,所以需要考虑清楚使用哪种分词器

4.创建es对应DAO:

和jpa基本类型,继承ElasticsearchRepository接口

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.jpa.repository.Modifying;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Optional;

public interface ElasticsearchTestEntityDao extends ElasticsearchRepository<ElasticsearchTestEntity, Integer> {

    Page<ElasticsearchTestEntity> findByContent(String content, Pageable pageable);

    Page<ElasticsearchTestEntity> findByCreateTimeBetween(Date startTime, Date endTime, Pageable pageable);

    Page<ElasticsearchTestEntity> findByNumber(BigDecimal Number, Pageable pageable);

    Page<ElasticsearchTestEntity> findByContentOrNumber(String content, BigDecimal number, Pageable pageable);

    Optional<ElasticsearchTestEntity> findByElasticsearchTestId(Integer elasticsearchTestId);

    @Modifying
    int deleteByElasticsearchTestId(Integer elasticsearchTestId);

}

5.根据reporitory的简单增删改查:

这个方法和操作jpa中的普通的方法没什么区别,就是普通的增删改查。 通过自带方法就可以进行简单查询

    <S extends T> S save(S var1);

    <S extends T> Iterable<S> saveAll(Iterable<S> var1);

    Optional<T> findById(ID var1);

    boolean existsById(ID var1);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> var1);

    long count();

    void deleteById(ID var1);

    void delete(T var1);

    void deleteAll(Iterable<? extends T> var1);

    void deleteAll();

ps:es插入新信息时,实体类中的主键id是需要填写,不能通过es自动生成(通过API可以自动生成随机id)不填写会以id为null插入信息

6.es的高级复杂查询:

例子可以查看项目模板(project-templet)

四.es集成search-guard安全插件:

1.安装search-guard安全插件:

2.生成证书文件

Ⅰ search-guard证书有3种类型:
Ⅱ 证书生成工具

需要使用search-guard-ssl中的脚本生成各种证书

#git clone https://github.com/floragunncom/search-guard-ssl.git
#cd search-guard-ssl/example-pki-scripts

example-pki-scripts目录下有这几个脚本文件:

#!/bin/bash
OPENSSL_VER="$(openssl version)"

if [[ $OPENSSL_VER == *"0.9"* ]]; then
        echo "Your OpenSSL version is too old: $OPENSSL_VER"
        echo "Please install version 1.0.1 or later"
        exit -1
else
    echo "Your OpenSSL version is: $OPENSSL_VER"
fi

set -e
./clean.sh
# 第一个参数为CA根证书密码,第二个参数为TS密码(truststore,信任证书密码)
./gen_root_ca.sh aaccbb 123456

# 生成节点证书: 第一个参数为节点编号,第二个参数为keystore文件密码,第三个参数为CA根证书密码。
# 此处我们只生成三个节点证书
./gen_node_cert.sh 1 123456 aaccbb && ./gen_node_cert.sh 2 123456 aaccbb && ./gen_node_cert.sh 3 123456 aaccbb

# 生成客户端证书: 第一个参数为客户端名称, 第二个参数为keystore文件名称,第三个参数为CA根证书名称。
# 生成一个javaapi访问的客户端证书,用于springboot访问es
./gen_client_node_cert.sh javaapi 123456 aaccbb

rm -f ./*tmp*

然后运行脚本后会在该文件夹生成很多的证书:我们主要需要:

Ⅲ 设置es配置

把生成的truststore.jks和javaapi-keystore.jks上传到/disk1/elasticsearch/config/; 各个节点的证书也分别上传到对应的配置文件夹:/disk1/elasticsearch/config/es-node1/;
把管理员证书和根证书和对应的节点证书分别复制到各个es的配置文件夹中:/usr/share/elasticsearch/config/

ES01
docker cp /disk1/elasticsearch/config/truststore.jks ES01:/usr/share/elasticsearch/config/
docker cp /disk1/elasticsearch/config/es-node1/node-1-keystore.jks ES01:/usr/share/elasticsearch/config/
docker cp /disk1/elasticsearch/config/javaapi-keystore.jks ES01:/usr/share/elasticsearch/config/

ES02
docker cp /disk1/elasticsearch/config/truststore.jks ES02:/usr/share/elasticsearch/config/
docker cp /disk1/elasticsearch/config/es-node2/node-2-keystore.jks ES02:/usr/share/elasticsearch/config/
docker cp /disk1/elasticsearch/config/javaapi-keystore.jks ES02:/usr/share/elasticsearch/config/

ES03
docker cp /disk1/elasticsearch/config/truststore.jks ES03:/usr/share/elasticsearch/config/
docker cp /disk1/elasticsearch/config/es-node3/node-3-keystore.jks ES03:/usr/share/elasticsearch/config/
docker cp /disk1/elasticsearch/config/javaapi-keystore.jks ES03:/usr/share/elasticsearch/config/

各个es的配置文件中添加:

es-node1.yml
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
# 配置节点间通信证书,节点间通信使用TLS是强制的
searchguard.ssl.transport.keystore_filepath: node-1-keystore.jks
searchguard.ssl.transport.keystore_password: 123456
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.truststore_password: 123456
# 设置不校验hostname
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.transport.resolve_hostname: false
#配置restful为https访问,此处配置了head插件无法访问,所以一个节点不配置https,用于给head访问,剩下的配置https
searchguard.ssl.http.enabled: false
searchguard.ssl.http.keystore_filepath: node-1-keystore.jks
searchguard.ssl.http.keystore_password: 123456
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.ssl.http.truststore_password: 123456
# 配置管理员证书DN
searchguard.authcz.admin_dn:
  - CN=javaapi,OU=client,O=client,L=Test, C=DE
es-node2.yml
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
# 配置节点间通信证书,节点间通信使用TLS是强制的
searchguard.ssl.transport.keystore_filepath: node-2-keystore.jks
searchguard.ssl.transport.keystore_password: 123456
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.truststore_password: 123456
# 设置不校验hostname
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.transport.resolve_hostname: false

searchguard.ssl.http.enabled: true
searchguard.ssl.http.keystore_filepath: node-2-keystore.jks
searchguard.ssl.http.keystore_password: 123456
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.ssl.http.truststore_password: 123456
# 配置管理员证书DN
searchguard.authcz.admin_dn:
  - CN=javaapi,OU=client,O=client,L=Test, C=DE
es-node3.yml
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
# 配置节点间通信证书,节点间通信使用TLS是强制的
searchguard.ssl.transport.keystore_filepath: node-3-keystore.jks
searchguard.ssl.transport.keystore_password: 123456
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.truststore_password: 123456
# 设置不校验hostname
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.transport.resolve_hostname: false

searchguard.ssl.http.enabled: true
searchguard.ssl.http.keystore_filepath: node-3-keystore.jks
searchguard.ssl.http.keystore_password: 123456
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.ssl.http.truststore_password: 123456
# 配置管理员证书DN
searchguard.authcz.admin_dn:
  - CN=javaapi,OU=client,O=client,L=Test, C=DE

重启es:

docker restart ES01 ES02 ES03 

最后进入各个es内部将search-guard配置写入到es

1 docker exec -it ES01 /bin/bash

2 cd plugins/search-guard-5/tools/ 

//添加权限
3 chmod +x *.sh

//-p 8301  对应elasticsearch transport连接的端口号
//-cn test 为elasticsearch 集群名称 cluster.name
//以后每次调整searchguard 用户,角色和权限都需要执行一次写入search-guard配置操作;
//写入search-guard配置不需要重启Elasticsearch;
4 ./sgadmin.sh -cn elasticsearch-cluster -p 8301 -cd ../sgconfig -ks ../../../config/javaapi-keystore.jks -kspass 123456 -ts ../../../config/truststore.jks -tspass 123456 -nhnv

现在访问随意一个节点的地址http://127.0.0.1:8201/,发现需要输入密码才能访问,输入默认账号和密码:admin,才能访问

Ⅳ search-guard配置文件

searchguard 主要有5个配置文件在plugins/search-guard-5/sgconfig 下:

可以修改对应的配置文件进行修改账号、角色信息

五.遇到的问题:

1.项目中如果有用到redis,springboot启动时会报错:java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]

主要是netty冲突

Ⅰ springboot中添加es配置类:
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;

@Configuration
public class ElasticSearchConfig {
    @PostConstruct
    void init() {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }
}
Ⅱ 启动方法添加

System.setProperty("es.set.netty.runtime.available.processors", "false");:

@EnableSwagger2
@SpringBootApplication
public class CmsApplication {

    public static void main(String[] args) {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
        SpringApplication.run(CmsApplication.class, args);
    }

}

ps:有时第一个方法可以有时第二个方法可以,原因还在排查中

2.springboot启动报错:NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{192.111.222.5}{192.111.222.5:9300}]]

es配置文件添加network.host: 0.0.0.0(网上有说改为本地ip有说改为0.0.0.0)

3.es启动时形成不了集群:not enough master nodes discovered during pinging (found [[Candidate{node={my_node_name}{jRy-sXoCRP6bywdHcptjcA}{9uIaSSb7SEWx4AP6R_crTw}{192.168.58.147}{192.168.58.147:9300}, clusterStateVersion=-1}]], but needed [2]), pinging again

Ⅰ es配置文件中,node.master都设置为true

Ⅱ docker映射的端口设为相等(防止找不到相应的es节点)

4. 途中打开防火墙又关闭防火墙 docker启动容器报错:docker: Error response from daemon: driver failed programming external connectivity on endpoint

原因是docker服务启动时定义的自定义链DOCKER被防火墙清掉,学英语重启docker服务及可重新生成自定义链DOCKER,systmctl restart docker 重启docker,再重启容器

参考的网站: