Elasticsearch 8.0.0 集群部署文档
2023-01-05
14 min read
📚 Elasticsearch 8.0.0 三节点集群部署文档
版本:v1.1
编写日期:2025年9月7日
目标:搭建高可用 ES 集群(3节点)
部署方式:Tarball + 自定义脚本管理
环境:Linux(Ubuntu/CentOS 类)
一、操作目标
- 部署 3 个 Elasticsearch 8.0.0 节点,组成高可用集群
- 实现节点间自动发现、主节点选举、数据分片分配
- 提供统一的启停脚本,便于运维管理
- 验证集群健康状态
二、操作环境
节点 | 主机名 | IP 地址 | 角色 |
---|---|---|---|
1 | 121-es1 |
172.31.7.121 |
master/data/ingest |
2 | 122-es2 |
172.31.7.122 |
master/data/ingest |
3 | 123-es3 |
172.31.7.123 |
master/data/ingest |
所有节点配置相同,均为 master-eligible。
三、操作步骤(✅ 你执行的动作)
1. 分发软件包(所有节点)
# 在 121 上执行
scp elasticsearch-8.0.0-linux-x86_64.tar.gz 172.31.7.122:/apps
scp elasticsearch-8.0.0-linux-x86_64.tar.gz 172.31.7.123:/apps
2. 安装与目录准备(所有节点)
cd /apps
tar xf elasticsearch-8.0.0-linux-x86_64.tar.gz
ln -sv elasticsearch-8.0.0 elasticsearch
3. 创建专用用户(所有节点)
groupadd es
useradd es -g es
4. 创建数据与日志目录(所有节点)
mkdir -p /data/elasticsearch/data
mkdir -p /data/elasticsearch/logs
chown -R es:es /apps/elasticsearch
chown -R es:es /data/elasticsearch
5. 配置 elasticsearch.yml
(所有节点)
vim /apps/elasticsearch/config/elasticsearch.yml
配置内容(示例:121-es1
)
# =================================== 集群配置 ===================================
# 集群名称(所有节点必须一致)
# 同一个网络内,相同 cluster.name 的节点会自动组成集群
cluster.name: elasticsearch
# 节点名称(每个节点必须唯一!)
# ❗ 在 node-1、node-2、node-3 上分别设置为:
# node-1: node.name: node-1
# node-2: node.name: node-2
# node-3: node.name: node-3
node.name: node-1
# 节点角色定义(默认已启用 master/data/ingest)
# 可选值:master, data, ingest, remote_cluster_client, ml, voting_only 等
# 当前为通用节点,承担主节点选举、数据存储、数据预处理
node.roles: [master, data, ingest]
# =================================== 网络配置 ===================================
# 绑定的网络接口,0.0.0.0 表示监听所有网卡
network.host: 0.0.0.0
# HTTP 服务端口(默认 9200),用于 REST API
http.port: 9200
# Transport 端口(默认 9300),用于节点间通信
transport.port: 9300
# =================================== 发现与集群形成 ===================================
# 初始主节点候选列表(仅在集群首次启动时生效!)
# ❗ 首次启动后必须注释或删除此行,否则重启可能出错
# ❗ 所有 master-eligible 节点的 node.name 必须在此列表中
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
# 集群种子主机列表(所有节点都需配置)
# 格式:["ip:port", "ip:port", ...]
# 用于节点发现和集群组建
# ❗ 所有 master-eligible 节点的 IP:9300 都应在此列出
discovery.seed_hosts:
- "172.31.7.121:9300"
- "172.31.7.122:9300"
- "172.31.7.123:9300"
# =================================== 数据与日志路径 ===================================
# 数据存储路径(建议独立磁盘)
path.data: /data/elasticsearch/data
# 日志存储路径
path.logs: /data/elasticsearch/logs
# =================================== 安全配置(测试环境关闭) ===================================
# ❌ 测试环境关闭安全功能(生产环境必须开启)
xpack.security.enabled: false
# ❌ 关闭 HTTPS 和传输层 SSL 加密(生产环境必须开启)
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
# ❌ 关闭监控数据收集(可选)
xpack.monitoring.collection.enabled: false
# =================================== JVM 与性能调优(可选) ===================================
# 堆内存大小(建议不超过物理内存 50%,且不超过 32GB)
# 修改位置:config/jvm.options
# 示例:-Xms4g
# -Xmx4g
# 文件描述符限制(需系统配置)
# 确保系统 ulimit -n >= 65536
# 最大映射数量(必须设置)
# sysctl -w vm.max_map_count=262144
🔁 注意:
node.name
每台机器唯一(node-1
,node-2
,node-3
)cluster.initial_master_nodes
仅在首次启动时配置
6. 调整系统参数(所有节点)
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
sysctl -p
四、为什么要写启动脚本?
❓ 问题
- Elasticsearch 以
java
进程运行,直接启动不易管理 - 需要以
es
用户运行,不能用root
启动 - 缺少
start
/stop
/status
统一接口 - 无法快速判断进程状态和 API 可达性
✅ 解决方案:编写 start_es.sh
脚本
功能 | 说明 |
---|---|
start |
以 es 用户后台启动 ES |
stop |
安全停止进程,支持优雅关闭 |
status |
检查进程 + API + 集群健康 |
restart |
重启服务 |
五、脚本设计思路
功能 | 实现方式 |
---|---|
启动 | su - es -c "nohup ./elasticsearch -d" |
停止 | pgrep -f elasticsearch + kill -15 |
状态 | 检查进程 + curl 测试 API + 集群健康 |
用户 | 固定为 es ,避免权限问题 |
日志 | 输出彩色信息,便于识别 |
六、启动脚本内容(/root/start_es.sh
)
#!/bin/bash
# ========================================
# Elasticsearch 管理脚本
# 支持: start | stop | status
# 日志路径: /data/elasticsearch/logs
# ========================================
# 配置变量
ES_USER="es"
ES_HOME="/apps/elasticsearch"
ES_LOG_DIR="/data/elasticsearch/logs"
ES_PID_FILE="/var/run/elasticsearch.pid" # PID 文件位置
ES_CMD="cd ${ES_HOME} && ./bin/elasticsearch -d"
# 颜色输出
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 确保日志目录存在(可选)
ensure_log_dir() {
if ! su - ${ES_USER} -c "test -d ${ES_LOG_DIR}"; then
echo -e "${YELLOW}警告: 日志目录 ${ES_LOG_DIR} 不存在,尝试创建...${NC}"
mkdir -p ${ES_LOG_DIR}
chown ${ES_USER}:${ES_USER} ${ES_LOG_DIR}
chmod 755 ${ES_USER} ${ES_LOG_DIR}
fi
}
# 检查 es 用户家目录
ensure_home_dir() {
if [ ! -d "/home/es" ]; then
echo "创建 es 用户家目录 /home/es"
mkdir -p /home/es
chown ${ES_USER}:${ES_USER} /home/es
chmod 755 /home/es
fi
}
# 启动 Elasticsearch
start() {
ensure_home_dir
ensure_log_dir
if pgrep -u ${ES_USER} elasticsearch > /dev/null; then
echo -e "${YELLOW}Elasticsearch 已在运行。${NC}"
status
exit 1
fi
echo "正在以用户 ${ES_USER} 启动 Elasticsearch..."
if su - ${ES_USER} -c "${ES_CMD}"; then
# 等待 PID 文件或进程稳定
sleep 3
local pid=$(pgrep -u ${ES_USER} elasticsearch)
if [ -n "$pid" ]; then
echo $pid > ${ES_PID_FILE}
chown ${ES_USER}:${ES_USER} ${ES_PID_FILE} 2>/dev/null || true
echo -e "${GREEN}✅ Elasticsearch 已成功启动,PID: ${pid}${NC}"
else
echo -e "${RED}❌ 启动成功但无法获取 PID,请检查日志。${NC}"
fi
else
echo -e "${RED}❌ 启动失败,请检查日志: ${ES_LOG_DIR}${NC}"
exit 1
fi
}
# 停止 Elasticsearch
stop() {
# 使用 -f 匹配命令行中的 elasticsearch
local pids=($(pgrep -u ${ES_USER} -f elasticsearch))
if [ ${#pids[@]} -eq 0 ]; then
echo -e "${YELLOW}Elasticsearch 未运行。${NC}"
return 0
fi
echo -e "${YELLOW}发现 ${#pids[@]} 个 Elasticsearch 进程:${pids[*]}${NC}"
# 尝试优雅停止
for pid in "${pids[@]}"; do
echo "正在停止 PID: $pid"
kill -15 $pid
done
# 等待最多 30 秒
for i in {1..30}; do
local running=0
for pid in "${pids[@]}"; do
if kill -0 $pid 2>/dev/null; then
running=1
fi
done
if [ $running -eq 0 ]; then
echo -e "${GREEN}✅ 所有 Elasticsearch 进程已停止。${NC}"
rm -f ${ES_PID_FILE}
return 0
fi
sleep 1
done
# 超时,强制终止
echo -e "${RED}超时,正在强制终止...${NC}"
for pid in "${pids[@]}"; do
if kill -0 $pid 2>/dev/null; then
kill -9 $pid
echo "已强制终止 PID: $pid"
fi
done
rm -f ${ES_PID_FILE}
echo -e "${GREEN}✅ 强制停止完成。${NC}"
}
# 查看状态:本地进程 + 集群健康
status() {
echo -e "${YELLOW}🔍 正在检查 Elasticsearch 状态...${NC}"
# 使用 pgrep -f 匹配命令行,支持 java -cp ... elasticsearch
local pids=($(pgrep -u ${ES_USER} -f elasticsearch 2>/dev/null))
# 检查是否有运行中的进程
if [ ${#pids[@]} -gt 0 ]; then
local main_pid=${pids[0]}
if [ ${#pids[@]} -eq 1 ]; then
echo -e "${GREEN}🟢 Elasticsearch 正在运行${NC}"
echo -e " PID: ${main_pid}"
else
echo -e "${YELLOW}🟡 检测到多个 Elasticsearch 进程(可能存在残留)${NC}"
printf " PID 列表: "
printf '%s ' "${pids[@]}"
echo
echo -e " 主 PID: ${main_pid}"
fi
# 检查 REST API 是否响应
local http_url="http://localhost:9200"
echo -e "\n${YELLOW}📡 正在连接 REST API: ${http_url}${NC}"
if ! command -v curl &> /dev/null; then
echo -e "${RED}❌ 错误: curl 未安装,无法检查 API 状态${NC}"
return 1
fi
# 尝试获取根端点
if curl -s --connect-timeout 5 --max-time 10 "${http_url}" > /dev/null; then
echo -e "${GREEN}✅ REST API 可访问${NC}"
# 尝试获取集群健康状态
echo -e "\n${YELLOW}📊 集群健康状态:${NC}"
local health_output=$(curl -s -X GET "${http_url}/_cluster/health?pretty" 2>/dev/null)
local status_code=$(echo "$health_output" | grep -o '"status" *: *"[^"]*"' | head -1 | cut -d '"' -f4)
if [ -n "$status_code" ]; then
echo "$health_output" | sed 's/^/ | /'
else
local error_reason=$(echo "$health_output" | grep -o '"reason" *: *[^,}]*' | head -1 | cut -d ':' -f2- | xargs || echo "unknown")
echo " | ❌ 集群状态异常: $error_reason"
echo " | 建议: 检查 elasticsearch.yml 中的 discovery 配置"
echo " | 常见修复: 添加 discovery.type: single-node(单节点模式)"
fi
# 获取节点列表
echo -e "\n${YELLOW}🔍 集群节点信息:${NC}"
local nodes_output=$(curl -s -X GET "${http_url}/_cat/nodes?v" 2>/dev/null)
if echo "$nodes_output" | grep -q "master_not_discovered_exception"; then
echo " | ❌ 无法获取节点信息: master_not_discovered_exception"
else
echo "$nodes_output" | sed 's/^/ | /'
fi
else
echo -e "${RED}❌ REST API 无法访问,请检查服务是否完全启动${NC}"
echo -e "${YELLOW}💡 提示: 可能正在启动中,或配置了安全认证${NC}"
fi
# 显示日志尾部
if [ -d "${ES_LOG_DIR}" ] && [ -n "$(ls ${ES_LOG_DIR}/*.log 2>/dev/null)" ]; then
local log_file=$(ls ${ES_LOG_DIR}/*.log | head -n1)
echo -e "\n${YELLOW}📄 最近日志 (${log_file}):${NC}"
tail -n 5 "${log_file}" | sed 's/^/ | /'
else
echo -e "\n${YELLOW}📄 日志目录: ${ES_LOG_DIR} 不存在或无日志文件${NC}"
fi
else
# 没有找到进程
if [ -f "${ES_PID_FILE}" ]; then
local old_pid=$(cat "${ES_PID_FILE}")
echo -e "${RED}❌ Elasticsearch 未运行,但存在 PID 文件: ${old_pid}${NC}"
echo -e "${YELLOW}💡 请检查是否残留或手动 kill 进程${NC}"
else
echo -e "${YELLOW}⚪ Elasticsearch 未运行${NC}"
fi
fi
}
# 主逻辑
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
sleep 2
start
;;
*)
echo "用法: $0 {start|stop|status|restart}"
exit 1
;;
esac
exit 0
赋予权限:
chmod +x /root/start_es.sh
七、启动集群(操作步骤)
1. 清空数据目录(首次启动)
rm -rf /data/elasticsearch/data/*
2. 启动所有节点(同时)
/root/start_es.sh start
八、验证与展示步骤(✅ 查看结果)
1. 检查状态(122-es2
输出)
./start_es.sh status
✅ 执行结果:
🔍 正在检查 Elasticsearch 状态...
🟡 检测到多个 Elasticsearch 进程(可能存在残留)
PID 列表: 152116 152172
主 PID: 152116
📡 正在连接 REST API: http://localhost:9200
✅ REST API 可访问
📊 集群健康状态:
| {
| "cluster_name" : "elasticsearch",
| "status" : "green",
| "timed_out" : false,
| "number_of_nodes" : 3,
| "number_of_data_nodes" : 3,
| "active_primary_shards" : 0,
| "active_shards" : 0,
| "relocating_shards" : 0,
| "initializing_shards" : 0,
| "unassigned_shards" : 0,
| "delayed_unassigned_shards" : 0,
| "number_of_pending_tasks" : 0,
| "number_of_in_flight_fetch" : 0,
| "task_max_waiting_in_queue_millis" : 0,
| "active_shards_percent_as_number" : 100.0
| }
🔍 集群节点信息:
| ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
| 172.31.7.123 8 98 1 0.98 0.28 0.11 cdfhilmrstw - node-3
| 172.31.7.122 8 98 2 0.75 0.31 0.15 cdfhilmrstw - node-2
| 172.31.7.121 17 97 1 0.56 0.22 0.15 cdfhilmrstw * node-1
📄 最近日志 (/data/elasticsearch/logs/elasticsearch.log):
| at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:776)
| at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:26)
| at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
| at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
| at java.lang.Thread.run(Thread.java:833)
九、结果分析
项目 | 结论 |
---|---|
集群名称 | elasticsearch |
节点数 | ✅ 3 个节点正常加入 |
集群状态 | ✅ green (健康) |
主节点 | ✅ node-1 (* 标记) |
分片分配 | ✅ unassigned_shards: 0 |
进程状态 | ✅ 多 PID 为 Java 正常线程 |
日志 | ✅ 无错误,线程运行正常 |
十、结论
- ✅ Elasticsearch 8.0.0 三节点集群已成功部署
- ✅ 集群状态为
green
,所有节点正常通信 - ✅ 启停脚本功能完整,支持日常运维
- ✅ 当前为空集群,可开始写入数据
十一、后续建议
- 创建测试索引,验证写入与分片分配
- 模拟节点宕机,测试高可用性
- 生产环境开启安全功能
- 配置 Kibana 或监控系统