1. 故障背景
我们维护了一个由 3 个节点组成的 Elasticsearch 集群(版本为 7.x/8.x),开启了 X-Pack 安全认证(TLS 通信)。
故障现象:
日常维护中,我重启了其中一个节点(es-node-01),结果该节点启动后无法加入集群。查看集群状态,另外两个节点(es-node-02, es-node-03)依然处于运行状态,但集群状态变为 Yellow/Red,且缺少了一个节点。
2. 问题排查
查看 es-node-01 的启动日志,发现了大量报错,核心堆栈如下:
[WARN ][o.e.t.TcpTransport] [es-node-01] exception caught on transport layer ..., closing connection
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: PKIX path validation failed: validity check failed
...
Caused by: java.security.cert.CertificateExpiredException: NotAfter: Sun Nov 19 18:05:03 CST 2023
关键信息提取:
PKIX path validation failed: 证书路径验证失败。CertificateExpiredException: NotAfter: ... 2023: 最致命的错误。证书在 2023 年就已经过期了,而当前时间是 2026 年。
3. 深度分析:为什么另外两个节点还活着?
这是一个典型的**“僵尸集群”**状态。
- 存活节点(Node 02/03):它们之间的 TCP 长连接是在证书过期之前建立的。只要连接不断开,通信就能维持。
- 重启节点(Node 01):重启意味着 TCP 连接断开。当它尝试重新连接集群时,必须进行 SSL 握手。此时系统检查证书有效期,发现已过期,因此直接拒绝连接。
面临的困境(死锁):
如果只给 Node 01 换新证书,它去连 Node 02,Node 02 出示的还是旧证书,握手依然失败。
如果此时重启 Node 02/03,它们也会立刻报错起不来。
结论: 必须申请停机窗口,进行全集群重启(Full Cluster Restart),一次性替换所有节点的证书。
4. 解决方案
4.1 环境确认
检查 elasticsearch.yml 配置,确认当前使用的是 PEM 格式(.crt, .key)证书:
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.key: certs/node.key
xpack.security.transport.ssl.certificate: certs/node.crt
xpack.security.transport.ssl.certificate_authorities: [ "certs/ca.crt" ]
4.2 制作新证书
在任意节点上,准备一个 instances.yml 文件,定义集群所有节点信息:
instances:
- name: "es-node-01"
ip: ["10.x.x.1"]
- name: "es-node-02"
ip: ["10.x.x.2"]
- name: "es-node-03"
ip: ["10.x.x.3"]
使用 elasticsearch-certutil 工具重新生成 CA 和节点证书(有效期设置为 10 年,避免短期再次过期):
# 1. 生成新的 CA (根证书)
./bin/elasticsearch-certutil ca --pem --out ca.zip --days 3650
unzip ca.zip -d ca_temp
# 2. 基于新 CA 生成节点证书
./bin/elasticsearch-certutil cert --pem --ca-cert ca_temp/ca/ca.crt --ca-key ca_temp/ca/ca.key --in instances.yml --out certs.zip --days 3650
unzip certs.zip -d new_certs
4.3 替换与重启(关键步骤)
为了打破证书信任死锁,我执行了以下操作:
- 停止集群:停止 Node 02 和 Node 03 的服务(Node 01 已经是停止状态)。
- 分发证书:将生成的
ca.crt以及各节点对应的.crt和.key文件分发到三台服务器的config/certs/目录下,覆盖原文件。- 注意:文件名必须与配置文件中定义的一致。
- 依次启动:
- 先启动 Node 02(作为主节点候选)。
- 观察日志,确认无 SSL 报错,状态为
started。 - 依次启动 Node 03 和 Node 01。
5. 结果验证
所有节点启动后,查看集群节点状态:
curl -X GET "localhost:9200/_cat/nodes?v"
输出显示 3 个节点全部在线(* 表示主节点):
ip heap.percent ram.percent cpu load_1m name
10.x.x.2 45 60 5 0.20 es-node-02 *
10.x.x.3 40 58 3 0.15 es-node-03
10.x.x.1 10 55 8 0.45 es-node-01
登录 Kibana 查看,集群状态由 Red 转为 Yellow,最终变为 Green,分片正在进行 Rebalancing(再平衡),数据同步恢复正常。
6. 经验总结
- 监控证书有效期:SSL 证书过期是隐形杀手,建议将证书有效期加入监控告警(如使用 Prometheus 的
ssl_exporter)。 - 生成证书时预留足够时间:对于内部集群,建议生成证书时使用
--days 3650(10年),减少维护成本。 - 冷静应对僵尸状态:当发现部分节点因证书过期无法加入时,不要试图“修补”单个节点,果断进行全集群维护才是最高效的解法。