乐趣区

公司ES升级带来的坑怎么填?

前言
公司的 ES 最近需要全部进行升级,目的是方便维护和统一管理。以前的版本不统一,这次准备统一升级到一个固定的版本。
同时还会给 ES 加上权限控制,虽然都是部署在内网,为了防止误操作,加上权限还是有必要的。
带来的问题就是我这边的程序得改了,目前用的是 Spring Data Elasticsearch 来操作 ES。
问题
首先版本从 5.x 升级到 6.4.0,我这边用的 Spring Boot 是 2.0.1 版本,这块是兼容的,没有影响。唯一导致我这边要改动的就是权限这块。
在 Spring Boot 的文档中,提供了三种操作 ES 的框架,有两种是走 Http 协议的,也就是操作 9200 端口,是可以直接支持用户名和密码配置的。
elasticsearch-rest-client:
spring.elasticsearch.rest.uris=http://search.example.com:9200
spring.elasticsearch.rest.username=user
spring.elasticsearch.rest.password=secret
JestClient:
spring.elasticsearch.jest.uris=http://search.example.com:9200
spring.elasticsearch.jest.read-timeout=10000
spring.elasticsearch.jest.username=user
spring.elasticsearch.jest.password=secret
偏偏我用的是第三种 Spring Data Elasticsearch,没有认证信息的配置,但是有一个扩展属性 properties
@ConfigurationProperties(prefix = “spring.data.elasticsearch”)
public class ElasticsearchProperties {

/**
* Elasticsearch cluster name.
*/
private String clusterName = “elasticsearch”;

/**
* Comma-separated list of cluster node addresses.
*/
private String clusterNodes;

/**
* Additional properties used to configure the client.
*/
private Map<String, String> properties = new HashMap<>();
}
在 TransportClientFactoryBean 中初始化 Settings 的时候,会取 properties 中值
private Settings settings() {
if (properties != null) {
Settings.Builder builder = Settings.builder();

properties.forEach((key, value) -> {
builder.put(key.toString(), value.toString());
});

return builder.build();
}
return Settings.builder()
.put(“cluster.name”, clusterName)
.put(“client.transport.sniff”, clientTransportSniff)
.put(“client.transport.ignore_cluster_name”, clientIgnoreClusterName)
.put(“client.transport.ping_timeout”, clientPingTimeout)
.put(“client.transport.nodes_sampler_interval”, clientNodesSamplerInterval)
.build();
}
于是我在 properties 中加上认证信息的配置发现还是不行,因为这个全新认证是扩展的,需要增加 x -pack-transport 才行。
<!– add the x-pack jar as a dependency –>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>x-pack-transport</artifactId>
<version>6.4.2</version>
</dependency>
恶心的是中央仓库没有,还得指定仓库:
<repositories>
<!– add the elasticsearch repo –>
<repository>
<id>elasticsearch-releases</id>
<url>https://artifacts.elastic.co/maven</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
当你加入这些依赖之后你会发现,还是不能采用 spring.data.elasticsearch.xxx 这种方式直接配置认证信息,因为底层不是用的 xpack 扩展的 client 构造的,用的是 PreBuiltTransportClient,看下代码:
protected void buildClient() throws Exception {

client = new PreBuiltTransportClient(settings());

clusterNodes.stream() //
.peek(it -> logger.info(“Adding transport node : ” + it.toString())) //
.forEach(client::addTransportAddress);

client.connectedNodes();
}
最终还是放弃了自动配置的方式,自己手动配置定义 Client 来支持权限认证。
@Bean
public Client client() {
try {
Settings.Builder builder = Settings.builder()
.put(“client.transport.ping_timeout”, pingTimeout)
.put(“cluster.name”, clusterName)
.put(“xpack.security.user”, username + “:” + password)
.put(“xpack.security.transport.ssl.enabled”, “true”)
.put(“xpack.security.transport.ssl.truststore.path”, keystorePath)
.put(“xpack.security.transport.ssl.keystore.path”, keystorePath)
.put(“xpack.security.transport.ssl.verification_mode”, “certificate”);
Settings settings = builder.build();
String[] nodes = clusterNodes.split(“,”);
TransportAddress[] addressArray = new TransportAddress[nodes.length];
for (int i = 0; i < nodes.length; i++) {
String[] nodeArray = nodes[i].split(“:”);
addressArray[i] = new TransportAddress(InetAddress.getByName(nodeArray[0]), Integer.parseInt(nodeArray[1]));
}
return new PreBuiltXPackTransportClient(settings).addTransportAddresses(addressArray);
} catch (Exception e) {
logger.error(“ 初始化 ESClient 异常 ”, e);
}
return null;
}

username: 用户名
password: 密码
keystorePath: 证书地址,会有一个.p12 的证书

不知大家发现没有,看上去我们自定义的代码也没什么特别,关键点在于 PreBuiltXPackTransportClient,框架中用的是 PreBuiltTransportClient,所以我们才需要自定义。
配置完了你会发现还是不行,各种 jar 冲突,Spring Boot 的版本还需要升级,于是只能升到目前最新的 2.1.0 版本。升级完之后又有坑了。
升级之前 Data 中的注解,要指定类型,keyword 变成了 Keyword
@Field(type=FieldType.Keyword)
ES 的这个 Field 注解没有别名映射的属性,就是我 es 中存的 u_name, 实体类中写的是 username, 这个确实不太方便,像 data mongodb 中都有这样的功能,有知道怎么解决的要给我留言哈,学习下。
然后就是 security 的一个坑了,升级之后 security 版本也升级了,下载下来的 jar 包用不了,错误如下:

一开始以为是网络原因,没下载完,然后重新删了再下,试了 5 次还是不行,最后没办法,我手动下载了 spring-security-config 这个包,替换了本地仓库的 jar。
下载地址:https://mvnrepository.com/art…
以上就是这次升级过程中踩过的坑,分享给大家。这次只是客户端这块的改变,至于 ES 是怎么开启权限认证的我这边就不做讲解了,因为这块不是我弄的,所以我也不熟悉,等后面有机会我也去研究研究可以给大家分享,反正是基于 xpack 搞的。
欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

退出移动版