ES 集群安全加固 & ES9 部署 & Zookeeper 集群
ES 集群安全加固 & ES9 部署 & Zookeeper 集群
[TOC]
ES7 集群启用 HTTPS
在上一篇笔记中,我们通过 xpack.security.enabled 在 传输层(9300)启用了 TLS 加密——节点间通信已加密,需要用户名+密码才能访问 API
但 HTTP 层(9200)仍然是明文传输,存在风险
本章用自建 CA 签发证书的方式,为 ES 的 9200 端口启用 HTTPS
自建 CA 并签发证书
1)自建 CA 证书root@Elk01 ~# /usr/share/elasticsearch/bin/elasticsearch-certutil ca --out /etc/elasticsearch/elastic-stack-ca.p12 --pass "" --days 36500--pass "": # 空密码,生产环境建议设密码--days 36500: # 100 年有效期root@Elk01 ~# ls -l /etc/elasticsearch/elastic-stack-ca.p12-rw------- 1 root elasticsearch 2672 Aug 2 09:08 elastic-stack-ca.p12
2)基于自建 CA 生成 ES HTTPS 证书root@Elk01 ~# /usr/share/elasticsearch/bin/elasticsearch-certutil cert \ --ca /etc/elasticsearch/elastic-stack-ca.p12 \ --out /etc/elasticsearch/elastic-certificates-https.p12 \ --pass "" --days 36500 --ca-pass ""root@Elk01 ~# ls -l /etc/elasticsearch/elastic-*.p12-rw------- 1 root elasticsearch 3596 Aug 2 09:08 elastic-certificates-https.p12 # HTTPS-rw-r----- 1 root elasticsearch 3596 Aug 1 09:31 elastic-certificates.p12 # transport(已有)-rw------- 1 root elasticsearch 2672 Aug 2 09:08 elastic-stack-ca.p12 # CA
3)修改权限root@Elk01 ~# chmod 640 /etc/elasticsearch/elastic-certificates-https.p12# CA 证书只给 root 用(签发新证书时),ES 进程不读它;保持默认的 600 就行Elasticsearch 进程以 elasticsearch 用户运行,证书文件必须让该用户可读
属主 root、属组 elasticsearch、权限 640 即可
==与 transport 层证书的区别==
| transport (9300) | http (9200) | |
|---|---|---|
| 证书 | elastic-certificates.p12 | elastic-certificates-https.p12 |
| 作用 | 节点间加密通信 | 客户端(Kibana/Filebeat/curl)加密通信 |
| 配置项 | xpack.security.transport.ssl.* | xpack.security.http.ssl.* |
| 生成方式 | 直接 cert 即可(自签名) | 需要先建 CA(ca),再基于 CA 签发(cert --ca) |
| 验证模式 | certificate | 浏览器/curl 用 -k 跳过 |
修改 ES 集群配置
root@Elk01 ~# vim /etc/elasticsearch/elasticsearch.yml# 在文件末尾追加:xpack.security.http.ssl.enabled: truexpack.security.http.ssl.keystore.path: elastic-certificates-https.p12| 参数 | 作用 |
|---|---|
xpack.security.http.ssl.enabled | 启用 HTTP 层 SSL/TLS 加密 |
xpack.security.http.ssl.keystore.path | 证书路径(相对于 ES 的 config 目录) |
同步配置与证书到其他节点
1)拷贝证书文件 & 配置文件(三台必须一致)root@Elk01 ~# scp -p /etc/elasticsearch/elastic{-certificates-https.p12,search.yml} 10.0.0.7:/etc/elasticsearch/# CA 证书只在签发 HTTPS 证书时用到,签完后其他节点不需要它root@Elk01 ~# scp -p /etc/elasticsearch/elastic{-certificates-https.p12,search.yml} 10.0.0.8:/etc/elasticsearch/-p: # 保留权限
2)Elk02/03 确认权限root@Elk02 ~# ls -l /etc/elasticsearch/elastic-certificates-https.p12-rw-r----- 1 root elasticsearch 3596 Aug 2 09:08 elastic-certificates-https.p12重启集群并验证
1)三台同时重启root@Elk01 ~# systemctl restart elasticsearch.serviceroot@Elk02 ~# systemctl restart elasticsearch.serviceroot@Elk03 ~# systemctl restart elasticsearch.service
2)使用 HTTPS 访问root@Elk01 ~# curl -s -u elastic:passwd -k https://10.0.0.6:9200/_cat/nodes?v-s: # 静默,不显示 curl 进度条和连接信息-k: # 跳过自签名证书校验ip heap.percent ram.percent cpu node.role master name10.0.0.7 54 77 24 cdfhilmrstw - Elk0210.0.0.6 31 92 21 cdfhilmrstw * Elk0110.0.0.8 72 76 32 cdfhilmrstw - Elk03✅️ 3 节点在线,HTTPS 已生效
3)普通 HTTP 已不可用root@Elk01 ~# curl http://10.0.0.6:9200/curl: (52) Empty reply from server# HTTP 返回空连接——TLS 已接管 9200--insecure 和 -k 等价,都是跳过证书校验
生产环境应该配置客户端信任 CA,而不是用 -k 跳过
Kibana 对接 ES HTTPS 集群
1)修改 Kibana 配置root@Elk01 ~# vim /etc/kibana/kibana.ymlserver.host: "0.0.0.0"# 将 elasticsearch.hosts 的协议改为 https,再追加跳过证书校验:elasticsearch.hosts: ["https://10.0.0.6:9200","https://10.0.0.7:9200","https://10.0.0.8:9200"]elasticsearch.ssl.verificationMode: nonei18n.locale: "zh-CN" # 中文界面elasticsearch.username: "kibana_system"elasticsearch.password: "iYLp0QpWVR0IUnpidbi6"# elasticsearch.username / elasticsearch.password 保持不变| 配置项 | 值 | 说明 |
|---|---|---|
elasticsearch.hosts | https://... | 改为 HTTPS 协议 |
elasticsearch.ssl.verificationMode | none | 跳过自签名证书校验 |
2)重启 Kibanaroot@Elk01 ~# systemctl restart kibana.serviceroot@Elk01 ~# ss -ntl | grep 5601LISTEN 0 511 0.0.0.0:5601 0.0.0.0:*
3)验证状态root@Elk01 ~# curl -s -u elastic:passwd 'http://10.0.0.6:5601/api/status' | jq '.status.overall.state'"green"✅️ Kibana 已通过 HTTPS 对接 ES 集群# 下图也能说明 --> 成功对接
💡 除了命令行创建 api-key,也可以 WebUI 操作:Kibana → Stack Management → 安全 → API密钥 → 创建
如果已启用 HTTPS,api-key 功能默认已开启,无需额外配置 ✅
Filebeat 基于 api-key 认证
为什么用 api-key 而非用户名/密码?
- api-key ==不能登录 Kibana==,即使泄露也无法进入管理界面
- 可以按 api-key 粒度控制索引级权限
- 可以随时吊销,不影响其他组件
1)创建 api-key(赋予写入 kpyun-apikey-fb* 的权限)root@Elk01 ~# curl -s -u elastic:passwd -k -X POST 'https://10.0.0.6:9200/_security/api_key' \ -H 'Content-Type: application/json' \ -d '{ "name": "kpyun-apikey-fb", "role_descriptors": { "filebeat_writer": { "cluster": ["monitor", "manage_index_templates", "manage_ilm"], "index": [{"names": ["kpyun-apikey-fb*"], "privileges": ["create_index", "create_doc", "index", "read"]}] } }}' | jq# 下面是输出结果{ "id": "aT1lwZ8BC8dvYVpT5Imd", "name": "kpyun-apikey-fb", "api_key": "kyxEBSQmS_aqOvKUJXUORg", "encoded": "YVQxbHdaOEJDOGR2WVZwVDVJbWQ6a3l4RUJTUW1TX2FxT3ZLVUpYVU9SZw=="}💡 cluster 集群权限选 monitor + manage_index_templates + manage_ilm 就够了:
monitor— 查看集群状态manage_index_templates— 加载索引模板(Filebeat 启动时需要)manage_ilm— 管理索引生命周期
💡 索引权限沿用上一篇笔记的 RBAC 组合:create_index、create_doc、index、read
api-key ==不能登录 Kibana==,即使泄露也进不了管理界面,所以权限可以适当放宽
- ⚠️ 已创建的 api-key ==不能修改权限==,只能新建一个
- 所以创建前想清楚需要什么权限,避免重复劳动
2)api-key 的三种格式| 格式 | 示例 | 用途 |
|---|---|---|
| beats 格式 | aT1lwZ8BC8dvYVpT5Imd:kyxEBSQmS_aqOvKUJXUORg | Filebeat api_key 字段 |
| logstash 格式 | aT1lwZ8BC8dvYVpT5Imd:kyxEBSQmS_aqOvKUJXUORg | Logstash api_key 字段 |
| base64 格式 | YVQxbHdaOEJDOGR2WVZwVDVJbWQ6... | 部分工具 / HTTP Header |
| JSON 格式 | {"id":"...","api_key":"..."} | 原始返回 |
💡 beats 格式和 logstash 格式的值本身完全一样(都是 id:api_key)
- 只是写配置文件时的字段语法不同
- Filebeat 用 YAML(
api_key: "xxx"),Logstash 用 Ruby DSL(api_key => "xxx")
- Filebeat 用 YAML(
3)解码 base64 验证root@Elk01 ~# echo YVQxbHdaOEJDOGR2WVZwVDVJbWQ6a3l4RUJTUW1TX2FxT3ZLVUpYVU9SZw== | base64 -d; echoaT1lwZ8BC8dvYVpT5Imd:kyxEBSQmS_aqOvKUJXUORg# base64 解码 = id : api_key
4)编写 Filebeat 配置root@Elk02 ~# vim /etc/filebeat/config/tcp-to-es_api-key.yamlfilebeat.inputs:- type: tcp host: "0.0.0.0:9000"
output.elasticsearch: hosts: - "https://10.0.0.6:9200" - "https://10.0.0.7:9200" - "https://10.0.0.8:9200" # username: "elastic" # password: "passwd" # ↑ 注释掉这两行即可 # 基于api_key方式认证,相比于上面的用户/密码认证更安全(生产环境推荐) api_key: "aT1lwZ8BC8dvYVpT5Imd:kyxEBSQmS_aqOvKUJXUORg" index: "kpyun-apikey-fb-%{+yyyy-MM-dd}" ssl.verification_mode: none # 跳过证书校验
setup.ilm.enabled: falsesetup.template.name: "kpyun-apikey-fb"setup.template.pattern: "kpyun-apikey-fb*"setup.template.overwrite: falsesetup.template.settings: index.number_of_shards: 3 index.number_of_replicas: 0
5)启动 Filebeat 并发送测试数据root@Elk02 ~# killall -9 filebeatroot@Elk02 ~# nohup filebeat -e -c /etc/filebeat/config/tcp-to-es_api-key.yaml > /tmp/fb-api-key.log 2>&1 &root@Elk02 ~# tail -1 /tmp/fb-api-key.logConnection to backoff(elasticsearch(https://10.0.0.7:9200)) establishedroot@Elk02 ~# echo 'hello api_key test' | nc -w 1 10.0.0.7 9000
6)验证数据写入root@Elk01 ~# curl -s -u elastic:passwd -k 'https://10.0.0.6:9200/_cat/indices/kpyun-apikey-fb*?v'health status index docs.countgreen open kpyun-apikey-fb-2026-08-02 1✅️ Filebeat 通过 api_key 认证 → HTTPS → ES 集群,数据写入成功Logstash 基于 api-key 访问 ES 集群
1)创建 Logstash 专用的 api-keyroot@Elk01 ~# curl -s -u elastic:passwd -k -X POST 'https://10.0.0.6:9200/_security/api_key' \ -H 'Content-Type: application/json' \ -d '{ "name": "kpyun-apikey-lg", "role_descriptors": { "logstash_writer": { "cluster": ["monitor", "manage_index_templates", "manage_ilm"], "index": [{"names": ["kpyun-apikey-lg*"], "privileges": ["create_index", "create_doc", "index", "read"]}] } }}' | jq# 下面是输出结果{ "id": "az1zwZ8BC8dvYVpTColQ", "name": "kpyun-apikey-lg", "api_key": "nJdBvTx4RkypYb7PUI0yTA", "encoded": "YXoxendaOEJDOGR2WVZwVENvbFE6bkpkQnZUeDRSa3lwWWI3UFVJMHlUQQ=="}
2)编写 Logstash 配置root@Elk03 ~# vim /etc/logstash/conf.d/tcp-to-es_api-key.confinput { tcp { port => 8888 }}
filter { mutate { remove_field => [ "@version", "port", "host" ] }}
output { elasticsearch { hosts => ["https://10.0.0.6:9200","https://10.0.0.7:9200","https://10.0.0.8:9200"] index => "kpyun-apikey-lg-%{+yyyy-MM-dd}"# user => "elastic"# password => "passwd"# ↑ logstash 用 user/password,不是 username/password# 同样注释掉
# 指定api-key的方式认证 api_key => "az1zwZ8BC8dvYVpTColQ:nJdBvTx4RkypYb7PUI0yTA" # 使用api-key则必须启动ssl ssl => true # 跳过ssl证书验证 ssl_certificate_verification => false }}
3)启动 Logstash 并测试root@Elk03 ~# logstash -f /etc/logstash/conf.d/tcp-to-es_api-key.conf --config.test_and_exitConfiguration OK✅️ 配置语法检查通过root@Elk03 ~# nohup logstash -f /etc/logstash/conf.d/tcp-to-es_api-key.conf > /tmp/ls-api-key.log 2>&1 &root@Elk03 ~# tail -1 /tmp/ls-api-key.log:count=>1, :running_pipelines=>[:main]root@Elk03 ~# echo 'logstash api_key test' | nc -w 1 10.0.0.8 8888
4)验证root@Elk01 ~# curl -s -u elastic:passwd -k 'https://10.0.0.6:9200/_cat/indices/kpyun-apikey-lg*?v'health status index docs.countgreen open kpyun-apikey-lg-2026-08-02 1✅️ Logstash 通过 api_key 写入 ES 集群成功⚠️ 三组件认证字段名不同
| 组件 | 认证字段 | 示例 |
|---|---|---|
| Filebeat | username: / password: | username: "elastic" |
| Logstash | user => / password => | user => "elastic" |
| Kibana | elasticsearch.username: / elasticsearch.password: | elasticsearch.username: "kibana_system" |
💡 再加上 api-key 认证时,Filebeat 和 Logstash 都叫 api_key,Kibana 不支持 api-key——容易搞混
ES7 集群优化
JVM 堆内存调优
1)查看当前 JVM 堆大小root@Elk01 ~# ps -ef | grep elasticsearch | egrep "Xmx|Xms"-Xms512m-Xmx512mroot@Elk01 ~# free -h | grep MemMem: 1.8Gi 1.4Gi 128Mi 527Mi 416Mi# 当前是 512m(在 Elk01 时手动设的),内存依然偏紧
2)创建子目录 & 子配置文件root@Elk01 ~# mkdir -p /etc/elasticsearch/jvm.options.d⚠️ '每台VM都要创建这个目录'# ES 的启动脚本会扫描 jvm.options.d/ 并合并其中的内容# 所以不用改主配置文件(/etc/elasticsearch/jvm.options)root@Elk01 ~# echo -e "-Xms512m\n-Xmx512m" > /etc/elasticsearch/jvm.options.d/heap.options
3)保持 512m 无需调整root@Elk01 ~# systemctl restart elasticsearch`别忘记重启elasticsearch服务`root@Elk01 ~# egrep 'Xms|Xmx' /etc/elasticsearch/jvm.options.d/heap.options-Xms512m-Xmx512m✅️ `-Xms` 和 `-Xmx` 设成相同值,避免运行时堆扩展带来的性能抖动📌 ES 默认行为:自动将 JVM 堆设为物理内存的 ==50%==(上限 32GB)
- 这台 VM 有 2G 内存 → 若没手动设,ES 会吃 ~1GB,系统直接 OOM
- 所以我们在 Elk01 部署时就手动设了
-Xms512m -Xmx512m
官方建议:
- 堆内存不要超过 ==32GB==(超过后 JVM 指针压缩失效,性能反而下降)
- 推荐设 ==26GB== 左右,给 OS 留足文件系统缓存——Lucene 搜索依赖 heap 外的 page cache
- 生产环境 64G 内存通常设
-Xms31g -Xmx31g
禁用通配符删除索引
root@Elk01 ~# curl -s -u elastic:passwd -k -X DELETE 'https://10.0.0.6:9200/kpyun-test*'{"acknowledged":true}# ES 7.x 版本默认是可以使用通配符全部删除# ES 8+(包括9.x) 已经默认禁止使用
1)修改配置root@Elk01 ~# cat >> /etc/elasticsearch/elasticsearch.yml <<EOFaction.destructive_requires_name: trueEOF# 禁止使用通配符 * 或 _all 删除索引,防止误操作
2)同步到其他节点 + 重启root@Elk01 ~# scp /etc/elasticsearch/elasticsearch.yml 10.0.0.7:/etc/elasticsearch/root@Elk01 ~# scp /etc/elasticsearch/elasticsearch.yml 10.0.0.8:/etc/elasticsearch/root@Elk01 ~# systemctl restart elasticsearch# 三台同时重启
3)验证root@Elk01 ~# curl -s -u elastic:passwd -k -X DELETE 'https://10.0.0.6:9200/kpyun-test*'{"error":{"type":"illegal_argument_exception","reason":"Wildcard expressions or all indices are not allowed"},"status":400}✅️ 通配符删除已被拦截关闭自动创建索引
root@Elk01 ~# curl -s -u elastic:passwd -k -X POST 'https://10.0.0.6:9200/kpyun-test-1/_doc' \ -H 'Content-Type: application/json' -d '{"msg":"test"}' | jq{ "_index": "kpyun-test-1", "_type": "_doc", "_id": "wK5hwp8BkORV4nxJNCYI", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1}
1)修改配置root@Elk01 ~# cat >> /etc/elasticsearch/elasticsearch.yml <<EOFaction.auto_create_index: falseEOF# 禁止自动创建不存在的索引
2)同步 + 重启root@Elk01 ~# scp /etc/elasticsearch/elasticsearch.yml 10.0.0.7:/etc/elasticsearch/root@Elk01 ~# scp /etc/elasticsearch/elasticsearch.yml 10.0.0.8:/etc/elasticsearch/root@Elk01 ~# systemctl restart elasticsearch# 三台同时重启
3)验证# 这次是kpyun-test-2root@Elk01 ~# curl -s -u elastic:passwd -k -X POST 'https://10.0.0.6:9200/kpyun-test-2/_doc' \ -H 'Content-Type: application/json' -d '{"msg":"test"}' | jq{ "error": { "root_cause": [ "type": "index_not_found_exception", "reason": "no such index [kpyun-test-2] and [action.auto_create_index] is [false]", "index_uuid": "_na_", "index": "kpyun-test-2" }, "status": 404}✅️ `索引不存在时拒绝写入,而非自动创建`
4)手动创建索引后,方可写入root@Elk01 ~# curl -s -u elastic:passwd -k -X PUT 'https://10.0.0.6:9200/kpyun-test-2' \ -H 'Content-Type: application/json' | jq{ "acknowledged": true, "shards_acknowledged": true, "index": "kpyun-test-2"}root@Elk01 ~# curl -s -u elastic:passwd -k -X POST 'https://10.0.0.6:9200/kpyun-test-2/_doc' \ -H 'Content-Type: application/json' -d '{"msg":"test"}' | jq{ "_index": "kpyun-test-2", ...... "result": "created", ......# %{+yyyy-MM-dd} 是 Logstash/Filebeat 的日期占位符,Logstash 输出到 ES 时会自动解析成实际日期⚠️ 但 curl 和 ES REST API 不认识这个语法用 shell 的 date 命令生成实际日期字符串:root@Elk01 ~# curl -s -u elastic:passwd -k -X PUT \ "https://10.0.0.6:9200/kpyun-es-apikey-haha-$(date +%Y-%m-%d)" \ -H "Content-Type: application/json"# $(date +%Y-%m-%d) 会在 shell 层面被替换为 2026-08-06 这样的实际日期📌 三条优化总结
| 优化项 | 配置 | 作用 |
|---|---|---|
| JVM 堆 | -Xms256m -Xmx256m | 防止 OOM,节省内存 |
| 禁用通配符删除 | action.destructive_requires_name: true | 防止 DELETE /xxx* 误删大量索引 |
| 关闭自动创建索引 | action.auto_create_index: false | 必须手动创建索引才能写入,防止索引膨胀 |
ES9 集群部署
==ES7 vs ES8/9 关键差异==
| 特性 | ES7 | ES8+ / ES9 |
|---|---|---|
| 默认 HTTPS | ❌ 需手动配置 | ✅ 安装时自动生成 TLS 证书 |
| 默认认证 | ❌ 需手动启用 xpack.security.enabled | ✅ 安装时自动生成 elastic 密码 |
| 重置密码 | elasticsearch-setup-passwords auto | elasticsearch-reset-password -u elastic |
| 节点加入 | 配置 discovery.seed_hosts 即可 | 需要 enrollment token(elasticsearch-reconfigure-node) |
| Kibana 对接 | 手动配 elasticsearch.hosts + 密码 | 用 enrollment token + verification code |
| 索引模式 | 必须先创建索引模式才能看数据 | 无需索引模式,自动生成临时视图 |
环境准备
| 主机 | IP | 角色 | 配置 |
|---|---|---|---|
| ESnew-01 | 10.0.0.9 | ES9 + Kibana9 | 2C / 4G / 30G |
| ESnew-02 | 10.0.0.10 | ES9 | 2C / 4G / 30G |
| ESnew-03 | 10.0.0.11 | ES9 | 2C / 4G / 30G |
ES9 单点部署
1)下载软件包jiuzhao@Ubuntu ~$ wget -P /home/jiuzhao/下载 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-9.4.4-amd64.deb
2)拷贝到主机并安装jiuzhao@Ubuntu ~$ scp elasticsearch-9.4.4-amd64.deb ESnew-01:/tmproot@ESnew-01 ~# dpkg -i /tmp/elasticsearch-9.4.4-amd64.debSelecting previously unselected package elasticsearch....-------- Security autoconfiguration information -------- # 安全配置摘要Authentication and authorization are enabled. # 认证已启用TLS for the transport and HTTP layers is enabled and configured. # transport + HTTP 均已加密The generated password for the elastic built-in superuser is : N2-zXzCrxgf7AH+wbsR0# ↑ 自动生成的 elastic 密码,和 ES7 不同——不需要 elasticsearch-setup-passwords📌 对比 ES7:安装完就有 HTTPS + 认证 + TLS 证书,不需要一堆手动配置 ES9.4.4 安装时会自动输出安全配置信息:
-
elastic内置用户的密码(一次性的,安装日志中能看到) -
elasticsearch-reset-password -u elastic重置 elastic 密码的命令 -
elasticsearch-create-enrollment-token -s kibana/node为 Kibana/Node 生成 token 的命令
3)修改网络配置root@ESnew-01 ~# grep network.host /etc/elasticsearch/elasticsearch.yml#network.host: 192.168.0.1root@ESnew-01 ~# sed -i 's@#network.host: 192.168.0.1@network.host: 0.0.0.0@' /etc/elasticsearch/elasticsearch.yml
4)限制 JVM 堆(2G 内存必须做)root@ESnew-01 ~# ls -lhd /etc/elasticsearch/jvm.options.d/# ES-9.x 默认有这个子目录(无需手动创建)root@ESnew-01 ~# echo -e '-Xms512m\n-Xmx512m' > /etc/elasticsearch/jvm.options.d/heap.options
5)启动服务root@ESnew-01 ~# systemctl enable --now elasticsearch.serviceroot@ESnew-01 ~# ps -ef | grep elastic | egrep 'Xms|Xmx'... -Xms512m -Xmx512m ...root@ESnew-01 ~# ss -lntup | grep -E '9200|9300'LISTEN 0 4096 *:9200 *:*LISTEN 0 4096 *:9300 *:*📌 ES9 默认 elasticsearch.yml 与 ES7 的差异
# egrep -v '^#|^$' /etc/elasticsearch/elasticsearch.yml
# ES9 安装后自带的配置(无需手动添加)xpack.security.enabled: true # 认证已启用xpack.security.enrollment.enabled: true # enrollment token 已启用xpack.security.http.ssl: # HTTPS 已启用 enabled: true keystore.path: certs/http.p12 # TLS 证书(自动生成)xpack.security.transport.ssl: # transport 层 TLS enabled: true verification_mode: certificate keystore.path: certs/transport.p12 truststore.path: certs/transport.p12💡 ES9 开箱即安全——安装完毕就是 HTTPS + 认证,不像 ES7 需要一大堆手动配置
6)验证单点root@ESnew-01 ~# echo y | /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic# 输入 y 确认,重置 elastic 密码New value: lvMEbeFwna3K+BTbjux*
root@ESnew-01 ~# curl -s -k -u elastic:lvMEbeFwna3K+BTbjux* https://10.0.0.9:9200/_cat/nodes10.0.0.9 51 94 32 cdfhilmrstw * ESnew-01✅️ ES9 单点运行正常ES9 集群部署
1)在另外两台安装 ES9(同样装完即可,不要改配置)root@ESnew-02 ~# dpkg -i /tmp/elasticsearch-9.4.4-amd64.debroot@ESnew-03 ~# dpkg -i /tmp/elasticsearch-9.4.4-amd64.deb
2)ESnew-01:添加集群配置root@ESnew-01 ~# vim /etc/elasticsearch/elasticsearch.yml# 追加以下内容:cluster.name: kpyun-ES # 集群名称discovery.seed_hosts: ["10.0.0.9", "10.0.0.10", "10.0.0.11"] # 集群节点列表cluster.initial_master_nodes: ["ESnew-01", "ESnew-02", "ESnew-03"] # 初始主节点候选# 初始化集群列表:仅在集群首次启动时需要# 避免脑裂,告诉集群初始化的时候有哪些节点有资格竞选Master# 集群组建成功后,新加入的节点不需要配置此项!⚠️ ES9 的 cluster.initial_master_nodes 必须用主机名,不能用 IP
ES9 安装时根据主机名生成了 TLS 证书,节点名由主机名决定 如果用 IP,节点发现时 hostname 匹配不上,集群组建失败
path.data: /var/lib/elasticsearchpath.logs: /var/log/elasticsearchnetwork.host: 0.0.0.0xpack.security.enabled: truexpack.security.enrollment.enabled: truexpack.security.http.ssl: enabled: true keystore.path: certs/http.p12xpack.security.transport.ssl: enabled: true verification_mode: certificate keystore.path: certs/transport.p12 truststore.path: certs/transport.p12cluster.name: kpyun-ESdiscovery.seed_hosts: ["10.0.0.9", "10.0.0.10", "10.0.0.11"]cluster.initial_master_nodes: ["ESnew-01", "ESnew-02", "ESnew-03"]http.host: 0.0.0.0💡 三台都要配 /etc/hosts 做主机名解析:
root@ESnew-01 ~# cat >> /etc/hosts <<EOF10.0.0.9 ESnew-0110.0.0.10 ESnew-0210.0.0.11 ESnew-03EOF# 三台都要加!
# 测试验证root@ESnew-03 ~# ping -W1 -c2 ESnew-01PING ESnew-01 (10.0.0.9) 56(84) bytes of data.64 bytes from ESnew-01 (10.0.0.9): icmp_seq=1 ttl=64 time=0.398 ms64 bytes from ESnew-01 (10.0.0.9): icmp_seq=2 ttl=64 time=0.376 ms
--- ESnew-01 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1064msrtt min/avg/max/mdev = 0.376/0.387/0.398/0.011 ms3)拷贝 ESnew-01 的配置与证书到其他节点root@ESnew-01 ~# scp /etc/elasticsearch/elasticsearch.yml ESnew-02:/etc/elasticsearch/root@ESnew-01 ~# scp /etc/elasticsearch/elasticsearch.yml ESnew-03:/etc/elasticsearch/# TLS 证书(certs/ 目录 + elasticsearch.keystore)也要同步root@ESnew-01 ~# scp -r /etc/elasticsearch/certs ESnew-02:/etc/elasticsearch/root@ESnew-01 ~# scp /etc/elasticsearch/elasticsearch.keystore ESnew-02:/etc/elasticsearch/root@ESnew-01 ~# scp -r /etc/elasticsearch/certs ESnew-03:/etc/elasticsearch/root@ESnew-01 ~# scp /etc/elasticsearch/elasticsearch.keystore ESnew-03:/etc/elasticsearch/
5)三台同时清数据 + 设置 JVM + 启动root@ESnew-01 ~# echo -e '-Xms512m\n-Xmx512m' > /etc/elasticsearch/jvm.options.d/heap.optionsroot@ESnew-02 ~# echo -e '-Xms512m\n-Xmx512m' > /etc/elasticsearch/jvm.options.d/heap.optionsroot@ESnew-03 ~# echo -e '-Xms512m\n-Xmx512m' > /etc/elasticsearch/jvm.options.d/heap.options
root@ESnew-01 ~# rm -rf /var/{log,lib}/elasticsearch/* && systemctl restart elasticsearch.service# 把数据和日志全删除了 --> 相当于我没有启动过root@ESnew-02 ~# rm -rf /var/{log,lib}/elasticsearch/* && systemctl enable --now elasticsearch.serviceroot@ESnew-03 ~# rm -rf /var/{log,lib}/elasticsearch/* && systemctl enable --now elasticsearch.service⚠️ 三台同时启动,避免脑裂⚠️ ES9 集群组建的坑点:
- 三台必须同时启动,否则先启动的节点会自举为单节点集群
cluster.initial_master_nodes必须用主机名- 仅在集群首次启动时需要,新加入的节点不需要配置此项(避免脑裂)
/etc/hosts必须有主机名解析- TLS 证书必须一致(从第一台拷贝到其他节点)
6)重置密码并验证集群root@ESnew-01 ~# echo y | /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elasticNew value: UF+Q8qcdqvUQF8i=7ESk
root@ESnew-01 ~# curl -s -k -u elastic:UF+Q8qcdqvUQF8i=7ESk https://10.0.0.9:9200/_cat/nodes?vip heap.percent ram.percent cpu node.role master name10.0.0.10 75 60 38 cdfhilmrstw * ESnew-0210.0.0.11 81 58 35 cdfhilmrstw - ESnew-0310.0.0.9 75 55 24 cdfhilmrstw - ESnew-01✅️ 3 节点集群就绪,ESnew-02 被选为主节点
root@ESnew-01 ~# curl -s -k -u elastic:UF+Q8qcdqvUQF8i=7ESk https://10.0.0.9:9200/_cat/health1785635069 01:44:29 elasticsearch green 3 3 6 3 0 0 0 0 - 100.0%# green ✅️7)改管理员密码为简单好记的root@ESnew-01 ~# curl -s -k -u elastic:UF+Q8qcdqvUQF8i=7ESk \ -XPUT 'https://10.0.0.9:9200/_security/user/elastic/_password' \ -H 'Content-Type: application/json' -d '{"password":"passwd"}'# 返回 {} = 成功
root@ESnew-01 ~# curl -s -k -u elastic:passwd https://10.0.0.9:9200/_cat/nodes | wc -l3✅️ 新密码生效验证 ES9 集群高可用
1)查看当前主节点root@ESnew-01 ~# curl -s -k -u elastic:passwd https://10.0.0.9:9200/_cat/masterqZZAe2XpS7aSYVLyZguqrA 10.0.0.10 10.0.0.10 ESnew-02# ESnew-02 是 master
2)停止 master 节点root@ESnew-02 ~# systemctl stop elasticsearch.service
3)观察自动切换root@ESnew-01 ~# curl -s -k -u elastic:passwd https://10.0.0.9:9200/_cat/masterVZdqXATfRFGBSHkkrJ780w 10.0.0.9 10.0.0.9 ESnew-01✅️ ESnew-01 自动接管为 master
root@ESnew-01 ~# curl -s -k -u elastic:passwd https://10.0.0.9:9200/_cat/healthyellow 2 2 4 3 0 0 2 0 - 66.7%# yellow:因为只有 2/3 节点存活💡 一个 ES 集群,若想容忍 N 个节点故障,最少需要 ==2N+1== 个节点
- 容忍 1 台故障 → 3 台(如本例,坏 2 台就不可用了)
- 容忍 2 台故障 → 5 台
- 过半以上需要存活,否则集群 ==read-only==(无法选举 master)
- 无法形成法定人数(quorum),选举不出新 master
- 无法选举出新 master 时,集群拒绝写入,只保留读能力
4)恢复 ESnew-02root@ESnew-02 ~# systemctl start elasticsearch.serviceroot@ESnew-01 ~# curl -s -k -u elastic:passwd https://10.0.0.9:9200/_cat/masterVZdqXATfRFGBSHkkrJ780w 10.0.0.9 10.0.0.9 ESnew-01# 非抢占式,master 依旧是ESnew-01root@ESnew-01 ~# curl -s -k -u elastic:passwd https://10.0.0.9:9200/_cat/healthgreen 3 3 6 3 0 0 0 0 - 100.0%✅️ 恢复 greenKibana9 对接 ES9 集群
1)安装 Kibana9jiuzhao@Ubuntu ~$ scp kibana-9.4.4-amd64.deb ESnew-01:/tmproot@ESnew-01 ~# dpkg -i /tmp/kibana-9.4.4-amd64.deb
2)基础配置(只需加两行,其余保持默认)root@ESnew-01 ~# egrep -v '^#|^$' /etc/kibana/kibana.ymllogging: appenders: file: type: file fileName: /var/log/kibana/kibana.log # Kibana 自身日志 → JSON 格式 layout: type: json root: appenders: - default # 控制台输出 - file # 上面的日志文件pid.file: /run/kibana/kibana.pid # systemd 判断 Kibana 是否存活server.host: "0.0.0.0" # ← 手动添加i18n.locale: "zh-CN" # ← 手动添加# ES9 的 Kibana 不需要手动配 elasticsearch.hosts 和密码# 通过 enrollment token + verification code 自动对接 ✅️
3)生成加密密钥(ES9 Kibana 必配)# ES9 的 Kibana 比 ES7 多了加密密钥要求,否则 cases / fleet / reporting 等插件报错root@ESnew-01 ~# /usr/share/kibana/bin/kibana-encryption-keys generate...Settings:...xpack.encryptedSavedObjects.encryptionKey: ba1a8f57b65545d60e87ffdb48de7bebf4c4aeb31548ba397922161324cc0be9xpack.reporting.encryptionKey: 240a397f6cb9126ca6f6b24a6e7b099e0eb4cf32abed7479828db415a51e4774xpack.security.encryptionKey: fa9c723e88d0952cb12fe22bb1388c497cd1bc61ad36367f5c3dbfbd8f8ae865# ↑ 三个 key 分别加密存储对象 / 报表 / 会话,必须手动写回 kibana.yml ⚠️root@ESnew-01 ~# vim /etc/kibana/kibana.yml# 加密密钥不会被 enrollment 自动回填——enrollment 只负责 ES 连接信息
4)启动 Kibanaroot@ESnew-01 ~# systemctl enable --now kibana.serviceroot@ESnew-01 ~# ss -lntup | grep 5601LISTEN 0 511 0.0.0.0:5601 0.0.0.0:*
5)生成 Kibana enrollment tokenroot@ESnew-01 ~# /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibanaeyJ2ZXIiOiI4LjE0LjAiLCJhZHIiOlsiMTAuMC4wLjk6OTIwMCJdLCJmZ3IiOiI5MmQzYzEzOWUwNzBkMmRhMzI3MDYzNWI1NTM5NzYwNzlhZWYwYjFlNDBmMDQ0YTY3MjlmMDk2OGUyMzAxYWNmIiwia2V5IjoiYTZQSHhaOEJJZUI4N3pXdHpoLUg6a1AtZXhhWHBST19ub0xheWszVnltUSJ9
6)获取 Kibana verification coderoot@ESnew-01 ~# /usr/share/kibana/bin/kibana-verification-codeYour verification code is: 034 336
7)访问 WebUI# 浏览器打开 http://10.0.0.9:5601/# ① 输入 enrollment token → ② 输入验证码 034 336 → ③ 登录 elastic:passwd===============================================完成后 Kibana 自动回写 kibana.yml: elasticsearch.hosts: [https://10.0.0.9:9200] # ES 地址 elasticsearch.serviceAccountToken: AAEAAWVsYXN0aWMv... # 服务账户 token elasticsearch.ssl.certificateAuthorities: [/var/lib/kibana/...] # CA 证书路径 xpack.fleet.outputs: [...] # Fleet 输出配置# ↑ 这些全都是 enrollment 自动回填的,不需要手动写💡 重装 Kibana 步骤
systemctl stop kibana.servicedpkg -P kibana# 确认干净rm -rf /etc/kibana/ /var/lib/kibana/ /var/log/kibana/userdel -r kibana 2>/dev/null; groupdel kibana 2>/dev/null
# 重装dpkg -i /tmp/kibana-9.4.4-amd64.deb完整的 kibana 配置文件
root@ESnew-01 ~# cat /etc/kibana/kibana.ymllogging: appenders: file: type: file fileName: /var/log/kibana/kibana.log # Kibana 自身日志 → JSON 格式 layout: type: json root: appenders: - default # 控制台输出 - file # 上面的日志文件pid.file: /run/kibana/kibana.pid # systemd 判断 Kibana 是否存活server.host: "0.0.0.0" # ← 手动添加i18n.locale: "zh-CN" # ← 手动添加
# ES9 的 Kibana 需要额外设置加密密钥,否则 cases 插件报错xpack.encryptedSavedObjects.encryptionKey: ba1a8f57b65545d60e87ffdb48de7bebf4c4aeb31548ba397922161324cc0be9xpack.reporting.encryptionKey: 240a397f6cb9126ca6f6b24a6e7b099e0eb4cf32abed7479828db415a51e4774xpack.security.encryptionKey: fa9c723e88d0952cb12fe22bb1388c497cd1bc61ad36367f5c3dbfbd8f8ae865
# This section was automatically generated during setup.elasticsearch.hosts: [https://10.0.0.9:9200]elasticsearch.serviceAccountToken: AAEAAWVsYXN0aWMva2liYW5hL2Vucm9sbC1wcm9jZXNzLXRva2VuLTE3ODU3Mjk3MDQ1MTU6SUppcW4ybjZUenk5dzZqdS1xNDBoUQelasticsearch.ssl.certificateAuthorities: [/var/lib/kibana/ca_1785729704793.crt]xpack.fleet.outputs: [{id: fleet-default-output, name: default, is_default: true, is_default_monitoring: true, type: elasticsearch, hosts: [https://10.0.0.9:9200], ca_trusted_fingerprint: 92d3c139e070d2da3270635b553976079aef0b1e40f044a6729f0968e2301acf}]Zookeeper 集群部署
📌 什么是 Zookeeper
Zookeeper 是一个分布式协调服务,维护配置信息、命名服务、分布式同步
主要的应用场景:Kafka、HBase、HDFS HA、YARN HA、Solr
单点部署
1)下载软件包jiuzhao@Ubuntu ~$ wget -P /home/jiuzhao/下载 https://dlcdn.apache.org/zookeeper/zookeeper-3.8.6/apache-zookeeper-3.8.6-bin.tar.gz
2)拷贝并解压jiuzhao@Ubuntu ~$ scp apache-zookeeper-3.8.6-bin.tar.gz Elk01:/tmproot@Elk01 ~# tar xf /tmp/apache-zookeeper-3.8.6-bin.tar.gz -C /usr/local/
3)配置环境变量root@Elk01 ~# vim /etc/profile.d/zk.sh#!/bin/bashexport ZK_HOME=/usr/local/apache-zookeeper-3.8.6-binexport JAVA_HOME=/usr/share/elasticsearch/jdkexport PATH=$PATH:${ZK_HOME}/bin:${JAVA_HOME}/bin# 复用 ES7 自带的 JDK,不需要单独安装 Java
root@Elk01 ~# source /etc/profile.d/zk.shroot@Elk01 ~# java --versionopenjdk 22.0.2 2024-07-16
4)准备配置文件root@Elk01 ~# cp /usr/local/apache-zookeeper-3.8.6-bin/conf/zoo_sample.cfg /usr/local/apache-zookeeper-3.8.6-bin/conf/zoo.cfg
5)启动 + 验证root@Elk01 ~# zkServer.sh startStarting zookeeper ... STARTED
root@Elk01 ~# zkServer.sh statusMode: standalone基本使用
📌 Zookeeper 的数据模型类似文件系统的层级路径,每个节点(Znode)是一个 ==key==(路径),可以存储一个 ==value==(数据)
create /school Redhat # key=/school, value=Redhat(create = mkdir + echo 合一)create /empty # value 不是必需的,为空则 get 返回 null# 但实际使用中一般都会赋值和文件系统一样,/school 既是数据容器,也能挂载子节点 /school/class(层级结构)
| 文件系统 | Zookeeper |
|---|---|
mkdir /school | create /school Redhat |
ls / | ls / |
cat /school | get /school |
echo kpyun > /school | set /school kpyun |
rm /school | delete /school |
💡 ZK 的 create = mkdir + echo 合一,路径和数据一步写完
1)创建节点root@Elk01 ~# zkCli.sh -server 10.0.0.6:2181
[zk: 10.0.0.6:2181(CONNECTED) 0] create /school RedhatCreated /school# key=/school,value=Redhat
2)查看节点列表[zk: 10.0.0.6:2181(CONNECTED) 1] ls /[school, zookeeper]
3)查看节点数据[zk: 10.0.0.6:2181(CONNECTED) 2] get /schoolRedhat
4)修改节点数据[zk: 10.0.0.6:2181(CONNECTED) 3] set /school kpyun[zk: 10.0.0.6:2181(CONNECTED) 4] get /schoolkpyun
5)删除节点[zk: 10.0.0.6:2181(CONNECTED) 5] delete /school[zk: 10.0.0.6:2181(CONNECTED) 6] ls /[zookeeper]
6)创建层级节点[zk: 10.0.0.6:2181(CONNECTED) 7] create /school Redhat[zk: 10.0.0.6:2181(CONNECTED) 8] create /school/class test01# /school/class 是 /school 的子节点,路径层级用 '/' 分隔[zk: 10.0.0.6:2181(CONNECTED) 9] ls /school[class]
7)递归删除(节点下有子节点时,普通 delete 会报错)[zk: 10.0.0.6:2181(CONNECTED) 10] delete /schoolNode not empty: /school # ❌ 不能删除非空节点[zk: 10.0.0.6:2181(CONNECTED) 11] deleteall /school# deleteall 会递归删除该节点及其所有子节点[zk: 10.0.0.6:2181(CONNECTED) 12] ls /[zookeeper]Zookeeper 集群部署
2888 仅 leader 监听(follower → leader 数据同步),3888 全部节点监听(选举投票)
| 端口 | 谁监听 | 作用 |
|---|---|---|
2181 | 全部节点 | 客户端连接端口,供应用程序连接使用的端口,所有节点均对外提供服务; |
2888 | 仅 leader | **集群内部通信端口(follower → leader)**数据同步、事务请求转发 |
3888 | 全部节点 | 集群选举端口,选举投票通信,Leader 宕机时用于重新选举 |
1)停单点root@Elk01 ~# zkServer.sh stop
2)修改集群配置root@Elk01 ~# vim /usr/local/apache-zookeeper-3.8.6-bin/conf/zoo.cfgtickTime=2000initLimit=10syncLimit=5dataDir=/var/lib/zookeeper# 修改数据目录clientPort=2181server.1=10.0.0.6:2888:3888server.2=10.0.0.7:2888:3888server.3=10.0.0.8:2888:3888
3)同步程序到其他节点root@Elk01 ~# scp -r /usr/local/apache-zookeeper-3.8.6-bin/ 10.0.0.7:/usr/local/# 我一个tar包 -C /usr/local/ 解压在了这里(东西都在这)root@Elk01 ~# scp -r /usr/local/apache-zookeeper-3.8.6-bin/ 10.0.0.8:/usr/local/root@Elk01 ~# scp /etc/profile.d/zk.sh 10.0.0.7:/etc/profile.d/root@Elk01 ~# scp /etc/profile.d/zk.sh 10.0.0.8:/etc/profile.d/
4)各节点准备 myid(与 zoo.cfg 中的 server.N 对应)root@Elk01 ~# mkdir /var/lib/zookeeper && echo 1 > /var/lib/zookeeper/myidroot@Elk02 ~# mkdir /var/lib/zookeeper && echo 2 > /var/lib/zookeeper/myidroot@Elk03 ~# mkdir /var/lib/zookeeper && echo 3 > /var/lib/zookeeper/myid📌 myid 中的数字必须和 zoo.cfg 中 server.N 的 N 一致
server.1=10.0.0.6 → Elk01 的 /var/lib/zookeeper/myid = 1
5)三台同时启动root@Elk01 ~# source /etc/profile.d/zk.sh && zkServer.sh startroot@Elk02 ~# source /etc/profile.d/zk.sh && zkServer.sh startroot@Elk03 ~# source /etc/profile.d/zk.sh && zkServer.sh start
6)查看集群状态root@Elk01 ~# zkServer.sh statusMode: followerroot@Elk02 ~# zkServer.sh statusMode: leaderroot@Elk02 ~# ss -ntl | egrep "2181|2888|3888"LISTEN 0 50 [::ffff:10.0.0.7]:2888 *:*LISTEN 0 50 *:2181 *:*LISTEN 0 50 [::ffff:10.0.0.7]:3888 *:*# 2888 仅 leader 监听,Elk02 是 leaderroot@Elk03 ~# zkServer.sh statusMode: follower# Elk02 先于 Elk03 启动,完成了选举——启动顺序也会影响 leader 归属✅️ 1 leader + 2 follower,ZK 集群就绪💡 -server 连接单个节点 vs 集群:
# 仅连一个节点(挂了就断了)zkCli.sh -server 10.0.0.6:2181
# 连集群(当前节点挂了自动切到下一个)zkCli.sh -server 10.0.0.6:2181,10.0.0.7:2181,10.0.0.8:2181客户端拿到列表后依次尝试,==连上哪个算哪个==,生产环境必须写完整集群地址保证高可用
7)客户端连接测试root@Elk01 ~# zkCli.sh -server 10.0.0.6:2181,10.0.0.7:2181,10.0.0.8:2181[zk: 10.0.0.6:2181,10.0.0.7:2181,10.0.0.8:2181(CONNECTED) 0] ls /[zookeeper]
# 在 Elk01 上创建数据[zk: 10.0.0.6:2181,10.0.0.7:2181,10.0.0.8:2181(CONNECTED) 1] create /kpyun-zk test-dataCreated /kpyun-zk
# 在 Elk02 上读取(跨节点数据一致)root@Elk02 ~# zkCli.sh -server 10.0.0.7:2181[zk: 10.0.0.7:2181(CONNECTED) 0] get /kpyun-zktest-data✅️ 数据在集群所有节点间自动同步
8)高可用验证root@Elk02 ~# zkServer.sh stop# 把leader杀死 --> 触发选举root@Elk03 ~# zkServer.sh statusZooKeeper JMX enabled by defaultUsing config: /usr/local/apache-zookeeper-3.8.6-bin/bin/../conf/zoo.cfgClient port found: 2181. Client address: localhost. Client SSL: false.Mode: leaderroot@Elk03 ~# ss -ntl | egrep "2181|2888|3888"LISTEN 0 50 [::ffff:10.0.0.8]:2888 *:*LISTEN 0 50 *:2181 *:*LISTEN 0 50 [::ffff:10.0.0.8]:3888 *:*root@Elk01 ~# zkCli.sh -server 10.0.0.6:2181,10.0.0.8:2181# 这里连接的是一整个集群[zk: 10.0.0.6:2181,10.0.0.8:2181(CONNECTED) 0] ls /[kpyun-zk, zookeeper]# 暂停了一个节点后服务依旧可以写入数据[zk: 10.0.0.6:2181,10.0.0.8:2181(CONNECTED) 1] create /Class C413Created /Class[zk: 10.0.0.6:2181,10.0.0.8:2181(CONNECTED) 2] ls /[Class, kpyun-zk, zookeeper]Leader 选举机制
📌 选举规则(两种场景)
| 场景 | 决定性因素 |
|---|---|
| 集群首次启动 | 启动顺序 + myid + zxid |
| Leader 宕机重选 | ==只有 myid 和 zxid==(节点同时感知,无启动顺序干扰) |
- 先比较 zxid(事务 ID),==越大越优先==
- zxid 相同时,比较 myid,==越大越优先==
- 当半数以上节点参与选举完成,leader 确认
🌰 本例:Elk02 宕机后,Elk03(myid=3)凭借最大 myid 当选新 leader
💡 集群节点数必须为奇数
一个集群如果要容忍 N 台故障,需要 2N + 1 台节点
- 容忍 1 台故障 → 3 台
- 容忍 2 台故障 → 5 台
Znode 类型
| 类型 | 创建命令 | 特征 |
|---|---|---|
| 永久节点 | create /path data | 会话断开后不删除 |
| 临时节点 | create -e /path data | 会话断开 30s 后自动删除 |
1)创建临时节点[zk: ...(CONNECTED) 1] create -e /office https://www.baidu.comCreated /office
2)查看节点元数据[zk: ...(CONNECTED) 2] stat /officeephemeralOwner = 0x2100009cac2d0000 # 当前 session ID,断开 30s 后自动删除[zk: ...(CONNECTED) 3] stat /kpyun-zkephemeralOwner = 0x0 # 0 = 永久节点Watch 机制(了解)
1)终端 1:监听 /kpyun-zk 子节点变化root@Elk01 ~# zkCli.sh -server 10.0.0.8:2181[zk: ...(CONNECTED) 0] ls -w /kpyun-zk[]# -w 参数 = 对该路径的子节点变化进行监听
2)终端 2:在 /kpyun-zk 下创建新节点root@Elk03 ~# zkCli.sh -server 10.0.0.6:2181[zk: ...(CONNECTED) 0] create /kpyun-zk/testCreated /kpyun-zk/test
3)终端 1 自动收到通知WATCHER::WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/kpyun-zk✅️ 检测到子节点变化课后练习
1)编写 systemd 服务文件(三台一样,放在 /etc/systemd/system/)root@Elk01 ~# cat > /etc/systemd/system/zookeeper.service <<"EOF"[Unit]# 服务描述Description=Apache Zookeeper Server# 官方文档地址Documentation=https://zookeeper.apache.org/# 等待网络就绪后再启动After=network-online.target# 主动声明依赖网络在线目标Wants=network-online.target
[Service]# zkServer.sh 内部 fork 出 java 守护进程,用 forkingType=forking# 环境变量:ZK_HOME / JAVA_HOME(复用 ES 自带 JDK)Environment=ZK_HOME=/usr/local/apache-zookeeper-3.8.6-binEnvironment=JAVA_HOME=/usr/share/elasticsearch/jdkEnvironment=PATH=/usr/local/apache-zookeeper-3.8.6-bin/bin:/usr/share/elasticsearch/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin# 启动命令ExecStart=/usr/local/apache-zookeeper-3.8.6-bin/bin/zkServer.sh start# 停止命令ExecStop=/usr/local/apache-zookeeper-3.8.6-bin/bin/zkServer.sh stop# 进程异常退出时(非 0 退出码或被信号kill杀死),systemd 自动拉起来Restart=on-failure# 重启间隔 3 秒RestartSec=3
[Install]# 开机自启WantedBy=multi-user.targetEOF
2)同步到其他节点root@Elk01 ~# scp /etc/systemd/system/zookeeper.service 10.0.0.7:/etc/systemd/system/root@Elk01 ~# scp /etc/systemd/system/zookeeper.service 10.0.0.8:/etc/systemd/system/
3)三台手动停进程 → 转 systemd 接管root@Elk01 ~# zkServer.sh stoproot@Elk01 ~# systemctl daemon-reload && systemctl enable --now zookeeperroot@Elk01 ~# systemctl status zookeeper | grep Active Active: active (running)✅️ 服务由 systemd 接管,开机自启# Elk02 / Elk03 执行相同操作
4)验证root@Elk02 ~# systemctl is-active zookeeperactiveroot@Elk02 ~# zkServer.sh status | grep ModeMode: leader💡 服务文件放 /etc/systemd/system/ 还是 /usr/lib/systemd/system/?
/etc/systemd/system/:系统管理员自建服务的推荐位置,优先级更高,便于管理/usr/lib/systemd/system/:软件包安装时自带的服务位置- 两者 systemd 都能识别,功能等价;自建服务放
/etc更规范 Type=forking:zkServer.sh 内部会 fork 出 java 守护进程,systemd 用 forking 判断”fork 成功 = 已启动”
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!















