Elasticsearch的简单使用

2019-04-203401
刘振杰
Java后台

① Elasticsearch 搭建

  • Elasticsearch是一个实时的分布式搜索和分析引擎。下面简称es,它可以帮助你用前所未有的速度去处理大规模数据。 它可以用于全文搜索,结构化搜索以及分析,当然你也可以将这三者进行组合。
    附带Elasticsearch: 权威指南(中文)

    一. 拉取es镜像

    本次使用版本5.6,在服务器终端,执行:
    docker pull elasticsearch:5.6

    二. 创建各个节点的配置文件和设置JVM线程数限制数量

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的默认端口:

  • 9200端口:ES节点和外部通讯使用,是http协议的RESTful接口

  • 9300端口ES节点之间通讯使用,是tcp通讯端口,集群间和TCPClient都走的它

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前端框架

  • 拉取镜像

    docker pull mobz/elasticsearch-head:5
  • 启动容器

    docker run -d -p 8400:9100 --name es-manager  mobz/elasticsearch-head:5
  • 浏览器访问http://127.0.0.1:8400/ 输入http://127.0.0.1:8201/ 连接

    五. 添加ik分词器插件

    es自带分词对中文会进行每个字的拆分,不太合适,所以一般会安装中文分词插件。这里使用的是 ik,ik分词器有两个分词策略,分别为ik_smart 和 ik_max_word

  • k_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;

  • ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。

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

1.在线下载安装:

  • 进入es容器内部目录

    //这里ES01为容器名字也可以改为对应的CONTAINER ID
    docker exec -it ES01 /bin/bash 
  • 在线安装

    ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.6.16/elasticsearch-analysis-ik-5.6.16.zip
  • 退出容器并重启指定容器

    exit
    docker restart ES01

    2.离线安装:

    先去下载对应版本的zip,解压复制到容器的/usr/share/elasticsearch/plugins,再重启es

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.简单查询

  • 检测集群时候健康:GET /_cat/health?v

    • 绿色表示一切正常, 黄色表示所有的数据可用但是部分副本还没有分配,红色表示部分数据因为某些原因不可用.
  • 获取集群的节点列表:GET /_cat/nodes?v

  • 列出所有索引:GET /_cat/indices?v

    • 更多cat API
      /_cat/allocation # 返回分片分配和磁盘使用的信息 
      /_cat/shards # 返回关于分片的信息 
      /_cat/shards/{index} 
      /_cat/master # 返回当选主节点信息 
      /_cat/nodes # 返回集群拓扑相关信息 
      /_cat/tasks 
      /_cat/indices # 返回所有索引信息 
      /_cat/indices/{index} 
      /_cat/segments # 索引段包括分片布局的API信息 
      /_cat/segments/{index} 
      /_cat/count # 为所有索引返回文档个数的信息 
      /_cat/count/{index} 
      /_cat/recovery # 返回还原过程的视图 
      /_cat/recovery/{index} 
      /_cat/health # 集群健康度 
      /_cat/pending_tasks # 正在等待执行任务信息 
      /_cat/aliases # 返回有关别名信息 
      /_cat/aliases/{alias} 
      /_cat/thread_pool #集群范围内的线程池统计信息 
      /_cat/thread_pool/{thread_pools} 
      /_cat/plugins # 插件信息 
      /_cat/fielddata # 字段数据信息使用堆内存 
      /_cat/fielddata/{fields} 
      /_cat/nodeattrs # 输出显示自定义节点属性 
      /_cat/repositories # 输出集群中注册快照存储库 
      /_cat/snapshots/{repository} # 输出属于指定仓库的快照信息 
      /_cat/templates # 输出当前正在存在的模板信
  • 匹配索引中所有的数据:POST /Index/Type/_search

    {
    "query": {
      "match_all": {}
    },
    "sort": {
      "id": {
        "order": "desc"
      }
    },
    "from": 0,
    "size": 10
    }
  • 返回指定的字段(id和number):POST /Index/Type/_search

    {
    "query": {
      "match_all": {}
    },
    "_source": [
      "id",
      "number"
    ]
    }
  • 返回content中包含测试的所有数据:POST /Index/Type/_search

    {
    "query": {
      "match": {
        "content": "测试"
      }
    }
    }
  • match:match会被分词

  • term:term不分词,完全匹配

  • match_phrase会被分词且需要必须包含所有分词

  • multi_match两多个字段进行匹配如:

{
  "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

  • indexName –> 索引库的名称,建议以项目的名称命名,就相当于数据库DB
  • type –> 类型,建议以实体的名称命名Table ,就相当于数据库中的表table
  • Document –> row 就相当于某一个具体对象
Ⅰ @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 一般用于字符串类型

  • text:存储数据时候,会自动分词,并生成索引,text不能用来排序,除非设置fileddata为true
  • 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安全插件:

  • 进入es容器内部目录
    //这里ES01为容器名字也可以改为对应的CONTAINER ID
    docker exec -it ES01 /bin/bash 
  • 安装search-guard安全插件:
    //版本号对应es版本号
    bin/elasticsearch-plugin install -b com.floragunn:search-guard-5:5.6.16-19.3
  • 等待下载完成后自动安装,出现下面语句说明已经安装成功 ```
  • Installed search-guard-5

    后面每个es都需要安装该插件,不一一演示

2.生成证书文件

Ⅰ search-guard证书有3种类型:
  • Client certificates(客户端证书)
  • Admin certificates(管理员证书)
  • Node certificates(节点证书)
    客户端证书是TLS证书,用在es 客户端,支持rest client和transport client ; 管理员证书也是客户端证书。客户端证书如果在es配置文件elasticsearch.yml中增加了如下配置,就变成了管理员证书,例如javaapi是客户端证书, 配置完才可以给springboot使用,可以配置多个:
    searchguard.authcz.admin_dn:
    - CN=javaapi,OU=javaapi,O=client,L=Test, C=DE
    - CN=test,OU=client,O=client,L=Test, C=DE
    search-guard配置包括用户,角色,权限等。search-guard提供了sgadmin脚本工具,来往es写入search-guard配置信息。
    节点证书用在es节点。保证es节点之间通信安全。节点证书没有权限限制,即每个操作都是允许的。也不能针对节点证书配置权限。
Ⅱ 证书生成工具

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

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

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

  • gen_client_node_cert.sh 创建客户端证书
    可以修改证书发行者信息

    if [ -z "$DN" ]; then
     DN="CN=$CLIENT_NAME, OU=client, O=client, L=Test, C=DE"
    fi

    其中:CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名 称,ST=州或省份名称,C=单位的两字母国家代码, 对应es配置文件elasticsearch.yml中的searchguard.authcz.admin_dn 如:CN=javaapi,OU=client,O=client,L=Test,C=DE
    可以修改证书的有效期

    "$BIN_PATH" -genkey \
          -alias     $CLIENT_NAME \
          -keystore  $CLIENT_NAME-keystore.jks \
          -keyalg    RSA \
          -keysize   2048 \
          -sigalg SHA256withRSA \
          -validity  712 \
          -keypass $KS_PASS \
          -storepass $KS_PASS \
          -dname "$DN"

    其中validity为有效期,单位是天

  • gen_node_cert.sh 创建节点证书
    可以修改证书发行者信息和修改证书的有效期,与gen_client_node_cert.sh相等

  • gen_root_ca.sh 创建根证书

  • etc/root-ca.conf 根证书配置

  • etc/signing-ca.conf 签名证书配置
    etc/root-ca.conf 和 etc/signing-ca.conf 需要配置相同信息: ```

0.domainComponent = "www.test.com” 域名 1.domainComponent = "www.test.com" 域名 organizationName = "Test" 组织名称 organizationalUnitName = "Test Root CA" 组织单位名称 commonName = "Test Root CA" 通用名称

* example.sh               生成证书脚本
修改为  

#!/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

然后运行脚本后会在该文件夹生成很多的证书:我们主要需要:
* truststore.jks 根证书
* javaapi-keystore.jks 客户端证书,该证书将会配置到es配置文件,做为管理员证书
* node-1-keystore.jks,node-2-keystore.jks,node-3-keystore.jks 3个节点证书

##### Ⅲ 设置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 下:

  • sg_config.yml:主配置文件不需要做改动。

  • sg_internal_users.yml:本地用户文件,定义用户密码以及对应的权限。

  • sg_roles.yml:角色权限配置文件

  • sg_roles_mapping.yml:定义用户角色的映射关系

  • sg_action_groups.yml:定义权限组:

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

五.遇到的问题:

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,再重启容器

参考的网站:

分享
点赞5
打赏
上一篇:Docker常用命令笔记(一)
下一篇:翻译 | 如何评估一API?