灯下哥谭 灯下哥谭
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

灯下哥谭

灯还亮着
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

  • Redis

  • 高性能KV

  • TiDB

  • Elasticsearch

    • Elasticsearch 运维知识地图:从安装配置到排障加速恢复
    • Elasticsearch 集群安装:RPM 裸机生产部署 vs docker-compose 快速起集群
      • 1. 选型对比表
      • 2. 方案一:RPM 裸机生产部署
        • 2.1 RPM 安装
        • 2.2 JVM 配置 /etc/elasticsearch/jvm.options
        • 2.3 Elasticsearch 配置 /etc/elasticsearch/elasticsearch.yml
        • 2.4 生产模式与启动检查(bootstrap checks)
        • 2.5 Systemd 配置 /usr/lib/systemd/system/elasticsearch.service
        • 2.6 生成证书与设置密码
      • 3. 方案二:docker-compose 快速起集群
        • 3.1 docker-compose.yml
        • 3.2 .env 环境变量
        • 3.3 启动命令
        • 3.4 容器化部署的原理
      • 4. 7.x 与 8.x 的安全默认值差异
      • 5. 坑与边界
        • 5.1 thread_pool.write.size 配置不当
        • 5.2 fielddata 断路器风险
      • 6. 验证
        • 6.1 RPM 部署验证
        • 6.2 docker-compose 验证
        • 6.3 常见故障
    • 给Elasticsearch集群添加用户密码
    • Elasticsearch 分片和副本:容量怎么规划,改分片数为什么这么麻烦
    • Elasticsearch集群节点磁盘使用分配不均解决办法
    • Elasticsearch 索引模板与映射:Composable 模板、mapping 与动态模板
    • Elasticsearch 分页查询三种方案:from/size、search_after、scroll 怎么选
    • Elasticsearch字符串搜索方式
    • Elasticsearch使用wildcard字段模糊匹配
    • Elasticsearch 数据迁移方案对比:esm vs Logstash
    • Nginx Mirror 模块实现三套ES写入网关
    • ES排障两件套:慢查询日志阈值配置 + tcpdump 抓包看真实请求
    • ES 集群恢复太慢?三个参数加速节点/分片恢复
    • Elasticsearch 常用 DSL 语句(速查表)
    • ES 集群 Yellow 复盘:1023 个副本永远分配不出去,问题不在磁盘
  • 数据管道

  • 其他数据库

  • 数据库
  • Elasticsearch
灯下哥谭
2022-03-10
目录

Elasticsearch 集群安装:RPM 裸机生产部署 vs docker-compose 快速起集群

部署 Elasticsearch 集群有两种常见方式:RPM 包裸机安装适合生产环境长期运行,docker-compose 适合本地测试或快速验证。7.x 与 8.x 在安全默认值上存在显著差异——7.x 需手动开启 xpack 并生成证书,8.x 则默认启用 TLS 和密码且无法匿名启动。本文覆盖两种部署形态的全量配置、安全差异、验证步骤以及两个必须知道的性能坑。

版本说明

本文原写于 2022-03,2026-09 重写。
RPM 部署基于 Elasticsearch 7.17.9;docker-compose 基于 8.1.2。在 8.x 上的差异已单独成章说明。

# 1. 选型对比表

维度 RPM 裸机生产部署 docker-compose 快速起集群
部署形态 systemd 托管的长期稳定集群 容器化的临时/开发环境
安全默认值 7.x 需手动开启 xpack.security 8.x 默认开启 TLS + 密码,无法匿名
资源隔离 依赖 OS 级 cgroup/limits 容器 mem_limit 可精确约束
升级方式 逐个节点 yum upgrade + 滚动重启 改 .env 版本号重新 up
适用场景 生产长期运行、需要精细调优 本地测试、CI/CD、快速验证

# 2. 方案一:RPM 裸机生产部署

基于 Elasticsearch 7.17.9 的 RPM 包安装,适用于生产环境三节点集群。

# 2.1 RPM 安装

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.9-x86_64.rpm
yum install elasticsearch-7.17.9-x86_64.rpm
1
2

# 2.2 JVM 配置 /etc/elasticsearch/jvm.options

-Xms30g
-Xmx30g
-XX:+UnlockDiagnosticVMOptions
-Xlog:gc+heap+coops
14-:-XX:+UseG1GC
14-:-XX:G1ReservePercent=25
14-:-XX:InitiatingHeapOccupancyPercent=30
14-:-XX:MaxGCPauseMillis=50
-Djava.io.tmpdir=${ES_TMPDIR}
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/es
-XX:ErrorFile=/data/es/hs_err_pid%p.log
8:-XX:+PrintGCDetails
8:-XX:+PrintGCDateStamps
8:-XX:+PrintTenuringDistribution
8:-XX:+PrintGCApplicationStoppedTime
8:-Xloggc:/data/es/gc.log
8:-XX:+UseGCLogFileRotation
8:-XX:NumberOfGCLogFiles=32
8:-XX:GCLogFileSize=64m
9-:-Xlog:gc*,gc+age=trace,safepoint:file=/data/es/gc.log:utctime,pid,tags:filecount=32,filesize=64m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

JVM 堆与容器内存三元配置:

  • -Xms30g -Xmx30g 仅约束 JVM 堆内存
  • 堆外内存:Lucene 段缓存、网络缓冲区、JNI 调用等不走 JVM 堆
  • 容器场景下:容器内存限制(mem_limit 或 systemd LimitAS)应 ≥ 1.5 ~ 2 × JVM 堆
  • 若不设容器内存限制,30GB 堆 + 无上限堆外可能导致容器 OOM 被 Kill

为什么 -Xms30g -Xmx30g 卡在 30GB 而不是更大:

JVM 的压缩普通对象指针(compressed oops)在堆超过约 32GB 时会失效,指针从 4 字节变成 8 字节,导致可寻址对象数量反而变少、GC 压力上升。因此在单节点场景下,30-31GB 是经验上的堆内存上限。如果机器内存更大,应该通过增加节点数来水平扩容,而不是继续增大单个节点的堆。另外,-Xms 与 -Xmx 必须设置为相同值,避免运行时因扩堆而引发的 GC 停顿。

# 2.3 Elasticsearch 配置 /etc/elasticsearch/elasticsearch.yml

cluster.name: test-es-cluster
node.name: es-master01
node.master: true
node.data: true
node.ingest: true
node.attr.rack_id: rack_es-master01
cluster.routing.allocation.awareness.attributes: rack_id
cluster.routing.allocation.same_shard.host: true
path.data: /data/es/data
path.logs: /data/es/logs
bootstrap.memory_lock: true
indices.memory.index_buffer_size: 17%
indices.recovery.max_bytes_per_sec: 1g
network.host: 0.0.0.0
network.publish_host: 192.0.2.11
http.port: 9200
transport.tcp.port: 9300
discovery.seed_hosts: ['192.0.2.11:9300', '192.0.2.12:9300', '192.0.2.13:9300']
cluster.initial_master_nodes: ['192.0.2.11', '192.0.2.12', '192.0.2.13']
cluster.fault_detection.leader_check.interval: 20s
discovery.cluster_formation_warning_timeout: 30s
cluster.join.timeout: 120s
cluster.publish.timeout: 90s
action.destructive_requires_name: true
xpack.ml.enabled: false
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.keystore.type: PKCS12
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.type: PKCS12
xpack.security.audit.enabled: true
thread_pool:
    write:
        size: 17  # 建议设置为 CPU 核数;若机器 8 核却设 17,会造成线程浪费
indices.fielddata.cache.size: 17%
indices.breaker.fielddata.limit: 30%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

为什么这些配置项这么设:

bootstrap.memory_lock: true 是为了防止 JVM 堆内存被操作系统交换到 swap。一旦堆被换出,GC 扫描时会触发磁盘 IO,延迟从毫秒级直接崩到秒级。开启它需要在 systemd unit 里配套设置 LimitMEMLOCK=infinity,两者是一对:前者是 ES 进程请求锁定内存,后者是 OS 允许它这么做。

cluster.initial_master_nodes 只在集群首次启动时用于引导形成集群,一旦集群形成后就不再生效。重启节点时不应依赖此配置。候选 master 节点取奇数(如 3 个)是为了让多数派投票可以达成明确结论,避免脑裂场景下出现多个 master。

node.attr.rack_id + cluster.routing.allocation.awareness.attributes 的组合用于强制让主分片与副本分片分布在不同机架。这样单机架掉电或网络中断时,不会同时失去主副本两份数据。cluster.routing.allocation.same_shard.host: true 是同一逻辑在单机层面的实现——确保同一分片的主副本不会落在同一台物理机上。

indices.memory.index_buffer_size: 17% 控制写入缓冲占 JVM 堆的比例,写入密集场景可适当调大,让更多数据在内存中缓冲后再刷盘。**indices.recovery.max_bytes_per_sec: 1g`** 则是分片恢复时的带宽限速,默认值在万兆网络下会让恢复变得过慢,但调太大又会挤占正常读写带宽——这是一个此消彼长的权衡点,不是越大越好。

# 2.4 生产模式与启动检查(bootstrap checks)

本文的 network.host: 0.0.0.0 配置是一个关键开关:ES 只要监听非回环地址,就认定自己处于生产模式,此时一组启动检查(bootstrap checks)从「警告」升级为「硬性拒绝启动」。开发模式(仅监听 127.0.0.1)下这些检查只打日志。这是很多人「本地跑得好好的,上生产起不来」的直接原因。

检查项 要求 配置方式
vm.max_map_count ≥ 262144 sysctl -w vm.max_map_count=262144,持久化写入 /etc/sysctl.conf
文件描述符 nofile ≥ 65535 systemd unit 中的 LimitNOFILE=65535(本文 2.5 节的 unit 文件已包含)
最大线程数 ≥ 4096 systemd unit 中的 LimitNPROC=65535(本文 unit 已包含)
内存锁定 必须成功锁定 bootstrap.memory_lock: true 要求 LimitMEMLOCK=infinity,两者缺一,节点要么起不来,要么锁不住内存
堆大小一致性 Xms 必须等于 Xmx 本文 jvm.options 中的 -Xms30g -Xmx30g 就是满足这条
发现配置 至少配置 discovery 或 initial_master 之一 discovery.seed_hosts 与 cluster.initial_master_nodes 至少配置一个,否则生产模式拒绝启动

排障入口:启动失败时错误信息统一带 bootstrap check failure 前缀,日志会逐条列出未通过的检查。直接按提示修改即可,不要盲目关闭安全特性绕过。

# 2.5 Systemd 配置 /usr/lib/systemd/system/elasticsearch.service

[Unit]
Description=Elasticsearch
Documentation=https://www.elastic.co
Wants=network-online.target
After=network-online.target

[Service]
Type=notify
RuntimeDirectory=elasticsearch
PrivateTmp=true
Environment=ES_HOME=/usr/share/elasticsearch
Environment=ES_PATH_CONF=/etc/elasticsearch
Environment=PID_DIR=/var/run/elasticsearch
Environment=ES_SD_NOTIFY=true
EnvironmentFile=-/etc/sysconfig/elasticsearch
WorkingDirectory=/usr/share/elasticsearch
User=elasticsearch
Group=elasticsearch
ExecStart=/usr/share/elasticsearch/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid --quiet
StandardOutput=journal
StandardError=inherit
LimitNOFILE=65535
LimitMEMLOCK=infinity
LimitNPROC=65535
LimitAS=infinity
LimitFSIZE=infinity
TimeoutStopSec=0
KillSignal=SIGTERM
KillMode=process
SendSIGKILL=no
SuccessExitStatus=143
TimeoutStartSec=575

[Install]
WantedBy=multi-user.target
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 2.6 生成证书与设置密码

export PATH=$PATH:/usr/share/elasticsearch/bin
elasticsearch-certutil ca
elasticsearch-certutil cert --ca elastic-stack-ca.p12
# 将生成的证书复制到各节点 config 目录

# 设置各内置用户密码
elasticsearch-setup-passwords interactive
1
2
3
4
5
6
7

# 3. 方案二:docker-compose 快速起集群

基于 Elasticsearch 8.x,适用于本地测试或快速验证三节点集群。

# 3.1 docker-compose.yml

version: "2.2"

services:
  setup:
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
    user: "0"
    command: >
      bash -c '
        if [ x${ELASTIC_PASSWORD} == x ]; then
          echo "Set the ELASTIC_PASSWORD environment variable in the .env file";
          exit 1;
        elif [ x${KIBANA_PASSWORD} == x ]; then
          echo "Set the KIBANA_PASSWORD environment variable in the .env file";
          exit 1;
        fi;
        if [ ! -f certs/ca.zip ]; then
          echo "Creating CA";
          bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
          unzip config/certs/ca.zip -d config/certs;
        fi;
        if [ ! -f certs/certs.zip ]; then
          echo "Creating certs";
          echo -ne \\
          "instances:\\n"\\
          "  - name: es01\\n"\\
          "    dns:\\n"\\
          "      - es01\\n"\\
          "      - localhost\\n"\\
          "    ip:\\n"\\
          "      - 127.0.0.1\\n"\\
          "  - name: es02\\n"\\
          "    dns:\\n"\\
          "      - es02\\n"\\
          "      - localhost\\n"\\
          "    ip:\\n"\\
          "      - 127.0.0.1\\n"\\
          "  - name: es03\\n"\\
          "    dns:\\n"\\
          "      - es03\\n"\\
          "      - localhost\\n"\\
          "    ip:\\n"\\
          "      - 127.0.0.1\\n"\\
          > config/certs/instances.yml;
          bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
          unzip config/certs/certs.zip -d config/certs;
        fi;
        echo "Setting file permissions";
        chown -R root:root config/certs;
        find . -type d -exec chmod 750 \\{} \\;;
        find . -type f -exec chmod 640 \\{} \\;;
        echo "Waiting for Elasticsearch availability";
        until curl -s --cacert config/certs/ca/ca.crt https://es01:9200/_cluster/health | grep -q '"status":"\\(green\\|yellow\\)"'; do sleep 30; done;
        echo "Setting kibana_system password";
        until curl -s -X POST --cacert config/certs/ca/ca.crt -u elastic:${ELASTIC_PASSWORD} -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done;
        echo "All done!";
      '
    healthcheck:
      test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"]
      interval: 1s
      timeout: 5s
      retries: 120

  es01:
    depends_on:
      setup:
        condition: service_healthy
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
      - esdata01:/usr/share/elasticsearch/data
    ports:
      - ${ES_PORT}:9200
    environment:
      - node.name=es01
      - cluster.name=${CLUSTER_NAME}
      - cluster.initial_master_nodes=es01,es02,es03
      - discovery.seed_hosts=es02,es03
      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=certs/es01/es01.key
      - xpack.security.http.ssl.certificate=certs/es01/es01.crt
      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.http.ssl.verification_mode=certificate
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.key=certs/es01/es01.key
      - xpack.security.transport.ssl.certificate=certs/es01/es01.crt
      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.license.self_generated.type=${LICENSE}
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

  es02:
    depends_on:
      - es01
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
      - esdata02:/usr/share/elasticsearch/data
    environment:
      - node.name=es02
      - cluster.name=${CLUSTER_NAME}
      - cluster.initial_master_nodes=es01,es02,es03
      - discovery.seed_hosts=es01,es03
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=certs/es02/es02.key
      - xpack.security.http.ssl.certificate=certs/es02/es02.crt
      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.http.ssl.verification_mode=certificate
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.key=certs/es02/es02.key
      - xpack.security.transport.ssl.certificate=certs/es02/es02.crt
      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.license.self_generated.type=${LICENSE}
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

  es03:
    depends_on:
      - es02
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
      - esdata03:/usr/share/elasticsearch/data
    environment:
      - node.name=es03
      - cluster.name=${CLUSTER_NAME}
      - cluster.initial_master_nodes=es01,es02,es03
      - discovery.seed_hosts=es01,es02
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=certs/es03/es03.key
      - xpack.security.http.ssl.certificate=certs/es03/es03.crt
      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.http.ssl.verification_mode=certificate
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.key=certs/es03/es03.key
      - xpack.security.transport.ssl.certificate=certs/es03/es03.crt
      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.license.self_generated.type=${LICENSE}
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

  kibana:
    depends_on:
      es01:
        condition: service_healthy
      es02:
        condition: service_healthy
      es03:
        condition: service_healthy
    image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
    volumes:
      - certs:/usr/share/kibana/config/certs
      - kibanadata:/usr/share/kibana/data
    ports:
      - ${KIBANA_PORT}:5601
    environment:
      - SERVERNAME=kibana
      - ELASTICSEARCH_HOSTS=https://es01:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
      - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
    mem_limit: ${MEM_LIMIT}
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

volumes:
  certs:
    driver: local
  esdata01:
    driver: local
  esdata02:
    driver: local
  esdata03:
    driver: local
  kibanadata:
    driver: local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

# 3.2 .env 环境变量

# ⚠️ 以下密码请自行设置为强密码,不要用示例值
ELASTIC_PASSWORD=<设置一个强密码>
KIBANA_PASSWORD=<设置一个强密码>
STACK_VERSION=8.1.2
CLUSTER_NAME=escluster
ES_PORT=9200
KIBANA_PORT=5601
LICENSE=basic
MEM_LIMIT=1073741824
1
2
3
4
5
6
7
8
9

内存配比提醒:MEM_LIMIT=1073741824(1GB)仅适用于测试环境。生产环境建议容器内存 ≥ 2 × JVM 堆大小。

# 3.3 启动命令

# 启动
docker-compose up -d

# 若有 vm.max_map_count 报错则执行
sysctl -w vm.max_map_count=262144

# 然后重启
docker-compose restart
1
2
3
4
5
6
7
8

# 3.4 容器化部署的原理

为什么 setup 容器要单独存在:在 8.x 中,TLS 证书必须在节点启动前就位。setup 容器是一个一次性任务容器,负责生成 CA 和各节点的证书、写入共享 volume,然后通过 healthcheck 让 es01 的 depends_on 卡住,直到证书就绪。这是为了避免「节点起来了证书还没生成好」的竞态条件。

容器里 memlock 与堆的关系:容器场景下,JVM 堆之外还有 Lucene 段缓存、网络缓冲、JIT 元空间等堆外开销。容器内存限制 mem_limit 应该留到堆的 1.5~2 倍裕量,否则容器会被 OOM Kill,而 ES 日志里看不到任何信息。

# 4. 7.x 与 8.x 的安全默认值差异

安全特性 7.x(RPM 部署) 8.x(docker-compose)
xpack.security.enabled 默认 false,需手动设为 true 默认 true,无法匿名启动
TLS 证书 需手动生成(elasticsearch-certutil) 首次启动自动生成,或挂载自定义证书
内置用户密码 初始无密码,需 elasticsearch-setup-passwords 设置 首次启动自动生成 elastic 密码,控制台输出
启动方式 可匿名启动,后手动开启安全 必须提供密码或证书,否则拒绝启动

关键差异说明:

  • 7.x 的「先无密码、后手动开启」流程在 8.x 不再适用
  • 8.x 首次启动时,若 ELASTIC_PASSWORD 未设置,setup 容器会报错退出
  • 8.x 的自动生成密码和证书仅适用于单节点或 compose 场景;生产集群仍需手动管理证书生命周期

# 5. 坑与边界

# 5.1 thread_pool.write.size 配置不当

elasticsearch.yml 中 thread_pool.write.size 应根据实际 CPU 核数设置。若机器 8 核却设 17,会造成线程浪费——多余的线程竞争 CPU 时间片,反而降低写入吞吐。

建议:设置为 CPU 核数或略低(留余量给 OS 和其他进程)。

# 5.2 fielddata 断路器风险

indices.breaker.fielddata.limit: 30% 与 indices.fielddata.cache.size: 17% 联动:

  • 当某聚合查询加载的 fielddata 超过堆的 30%,查询直接失败(而非丢弃缓存)
  • 异常信息:CircuitBreakingException: [fielddata] Data too large
  • 修复:改用 keyword 字段做聚合(不启用 fielddata),或增大断路器阈值(需留足堆余量)

# 6. 验证

# 6.1 RPM 部署验证

# 1. 确认集群节点列表
GET _cat/nodes?v

# 2. 确认集群健康(green/yellow 为正常,red 为故障)
GET _cluster/health

# 3. 确认 JVM 参数生效(heap 应与 jvm.options 一致)
GET _nodes/jvm?filter_path=nodes.*.jvm.mem.heap_max_in_bytes

# 4. 确认 thread_pool 配置生效
GET _nodes/settings?filter_path=nodes.*.thread_pool.write

# 5. 检查 fielddata 当前占用(接近 limit 时需警惕)
GET _nodes/stats/fielddata?filter_path=nodes.*.fielddata
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 6.2 docker-compose 验证

# 1. 检查容器状态
docker-compose ps

# 2. 验证 ES 集群健康(返回 green/yellow 为正常)
curl -s --cacert config/certs/ca/ca.crt -u elastic:<密码> https://localhost:9200/_cluster/health | jq .

# 3. 验证节点列表
curl -s --cacert config/certs/ca/ca.crt -u elastic:<密码> https://localhost:9200/_cat/nodes

# 4. 验证 Kibana 可访问(返回 302 重定向到登录页)
curl -s -I http://localhost:5601 | head -1
1
2
3
4
5
6
7
8
9
10
11

# 6.3 常见故障

现象 原因 处置
max virtual memory areas vm.max_map_count [65530] is too low 内核参数不足 执行 sysctl -w vm.max_map_count=262144
ES 容器反复重启 内存不足(1GB 无法支撑 8.x 全功能) 调高 .env 中 MEM_LIMIT
Kibana 无法连接 ES 证书未就绪或密码错误 检查 setup 容器日志:docker-compose logs setup
认证失败 密码错误或证书不受信任 确认使用正确的 elastic 密码,或证书挂载路径正确

ES 集群部署快速参考
{
  "_meta": {
    "doc_version": "1.0",
    "article_id": "es-cluster-install-rpm-docker",
    "profile_context": "elasticsearch-deployment",
    "last_updated": "2026-09"
  },
  "quick_start": {
    "rpm": {
      "install": "yum install elasticsearch-7.17.9-x86_64.rpm",
      "jvm_config": "/etc/elasticsearch/jvm.options",
      "es_config": "/etc/elasticsearch/elasticsearch.yml",
      "systemd": "systemctl start elasticsearch",
      "passwords": "elasticsearch-setup-passwords interactive"
    },
    "docker_compose": {
      "env": ".env (ELASTIC_PASSWORD, KIBANA_PASSWORD, STACK_VERSION)",
      "start": "docker-compose up -d",
      "verify": "curl -s --cacert config/certs/ca/ca.crt -u elastic:<密码> https://localhost:9200/_cluster/health"
    }
  },
  "safety_rules": [
    {"risk": "thread_pool.write.size 与 CPU 核数不匹配", "action": "线程数设为 CPU 核数或略低,避免浪费", "scope": "rpm"},
    {"risk": "fielddata 超过断路器阈值", "action": "查询直接失败 CircuitBreakingException,改用 keyword 聚合或调大阈值", "scope": "all"},
    {"risk": "JVM 堆外内存 OOM", "action": "容器内存限制 ≥ 1.5 ~ 2 × JVM 堆", "scope": "all"},
    {"risk": "8.x 忘记设置 ELASTIC_PASSWORD", "action": "setup 容器会报错退出,必须设置强密码", "scope": "docker"},
    {"risk": "vm.max_map_count 不足", "action": "执行 sysctl -w vm.max_map_count=262144", "scope": "docker"}
  ],
  "verification": {
    "rpm": [
      "GET _cat/nodes?v",
      "GET _cluster/health",
      "GET _nodes/jvm?filter_path=nodes.*.jvm.mem.heap_max_in_bytes",
      "GET _nodes/settings?filter_path=nodes.*.thread_pool.write",
      "GET _nodes/stats/fielddata?filter_path=nodes.*.fielddata"
    ],
    "docker": [
      "docker-compose ps",
      "curl -s --cacert config/certs/ca/ca.crt -u elastic:<密码> https://localhost:9200/_cluster/health",
      "curl -s -I http://localhost:5601"
    ]
  },
  "version_diff": {
    "security_default_7x": "手动开启 xpack.security.enabled + 生成证书",
    "security_default_8x": "默认开启 TLS + 密码,无法匿名启动"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#集群运维#Elasticsearch
上次更新: 9/11/2026

← Elasticsearch 运维知识地图:从安装配置到排障加速恢复 给Elasticsearch集群添加用户密码→

最近更新
01
DeepSeek Harness 实战 06|学习笔记:插件、工具、技能不在同一个维度上 原创
09-11
02
DeepSeek Harness 实战 05|让两个编码 Agent 共用一份长期记忆 原创
09-09
03
DeepSeek Harness 实战 04|学习笔记:从「已知限制」里读出三处设计张力 原创
09-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式