适用环境:CentOS 7.9 x86_64,16 核 CPU / 32G 内存,100G 系统盘 + 1TB 数据盘(挂载于 /data)
架构形态:混合接入——同时支持业务系统直写 ES、应用发日志到 Logstash、Filebeat 采集三种链路
软件版本:Elasticsearch / Kibana / Logstash / Filebeat 统一使用 7.17.28(版本必须一致)
安全基线:SELinux 保持 Enforcing,防火墙保持开启(按网段白名单放行)
部署方式:tar.gz 安装包 + systemd 管理,示例 IP 为 192.168.1.100(请替换为实际 IP)
目录
- 混合接入架构与规划
- 系统初始化(SELinux 保持开启)
- 数据盘挂载(/data,1TB)
- 安装 Elasticsearch
- 安装 Kibana
- 安装 Logstash(多链路管道)
- Filebeat 安装配置(被采集端)
- 防火墙配置(网段白名单)
- ES 侧统一治理(索引模板 / ILM / 水位线)
- 端到端验证(三条链路)
- 常见问题排查
- 路径与服务管理速查表
1. 混合接入架构与规划
1.1 架构全景
链路 A:业务系统直写 ──────────9200─────────────────────────┐
│
链路 B:应用 TCP/HTTP 直发 ──5045/5046──┐ │
├─ Logstash ─────────┼─→ Elasticsearch ─→ Kibana
链路 C:Filebeat(各被采集端)──5044─────┘ │
| 链路 | 适用场景 | 入口端口 | 说明 |
|---|---|---|---|
| A 直写 ES | 现有老业务,已内置 ES 客户端 | 9200 | 需用 _bulk 批量写入 |
| B 应用 → Logstash | 新业务、容器化等不便落文件的场景 | 5045(TCP) / 5046(HTTP) | Logstash 负责解析与路由 |
| C Filebeat → Logstash | 服务器/中间件日志(nginx、tomcat、系统日志) | 5044 | 可靠性最高,推荐优先使用 |
1.2 内存分配(32G)
| 组件 | 内存 | 说明 |
|---|---|---|
| Elasticsearch 堆 | 10G(-Xms10g/-Xmx10g) | 不超过物理内存一半、不超过 26G |
| Logstash 堆 | 4G(-Xms4g/-Xmx4g) | 默认 1G 偏小 |
| Kibana | 默认(约 1~2G) | Node.js 进程 |
| 系统 + page cache | 约 16G | 写入与查询都依赖文件缓存 |
1.3 磁盘与目录规划
/opt/elk/ ← 系统盘:组件程序本体与配置(共约 2G)
/data/
├── es/data ← ES 数据(最大头)
├── es/logs ← ES 自身日志
├── logstash/data ← Logstash 持久化状态(含 sincedb)
└── logstash/logs ← Logstash 日志
1.4 索引命名全局规范(混合接入的根基)
三条链路统一约定 {业务名}-log-{日期} 命名,例如:
| 链路 | 索引示例 | 命名由谁控制 |
|---|---|---|
| A | order-service-log-2026.08.25 |
业务代码指定 |
| B/C | nginx-log-2026.08.25 |
Logstash output 动态生成 |
统一命名后,索引模板、ILM、Kibana Index Pattern(*-log-*)一次配置全链路生效。
2. 系统初始化(SELinux 保持开启)
以下操作均使用 root 执行。
2.1 SELinux 配置说明
本文全程不关闭 SELinux,保持 Enforcing:
getenforce # 应输出 Enforcing
本方案不受影响的原因:ES / Kibana / Logstash 均为自定义 systemd 服务,运行在 unconfined_service_t 域,绑定 9200/5601/5044 等端口、读写 /opt 和 /data 均不受 SELinux 策略限制,无需额外配置。
如遇异常先查审计日志(正常应为空):
ausearch -m avc -ts recent
若改用 yum/rpm 安装官方包并出现权限报错,用 restorecon 修复文件标签:
restorecon -Rv /etc/elasticsearch /usr/share/elasticsearch
2.2 系统参数(ES 启动检查必需)
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
sysctl -p
cat >> /etc/security/limits.conf << 'EOF'
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
EOF
2.3 关闭 swap(对 ES 性能影响很大)
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
2.4 创建专用用户(ES 禁止 root 启动)
useradd elk
mkdir -p /opt/elk
3. 数据盘挂载(/data,1TB)
假设数据盘为 /dev/sdb(用 lsblk 确认实际盘符):
mkfs.xfs /dev/sdb
mkdir -p /data
mount /dev/sdb /data
# 用 UUID 写入 fstab,防止重启后盘符漂移
blkid /dev/sdb # 查到 UUID
echo "UUID=你的UUID /data xfs defaults 0 0" >> /etc/fstab
mount -a # 验证 fstab 无误,此步报错务必先修正再重启
df -h /data # 确认约 1T
创建数据目录并授权:
mkdir -p /data/es/{data,logs} /data/logstash/{data,logs}
chown -R elk:elk /data/es /data/logstash
4. 安装 Elasticsearch
4.1 下载解压
cd /opt/elk
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.28-linux-x86_64.tar.gz
tar -zxvf elasticsearch-7.17.28-linux-x86_64.tar.gz
chown -R elk:elk /opt/elk/elasticsearch-7.17.28
4.2 配置 config/elasticsearch.yml
cluster.name: elk-cluster
node.name: node-1
path.data: /data/es/data
path.logs: /data/es/logs
network.host: 0.0.0.0
http.port: 9200
discovery.type: single-node
bootstrap.memory_lock: true
# 不启用 xpack 认证,访问控制交由防火墙网段白名单(见第 8 章)
xpack.security.enabled: false
4.3 堆内存 config/jvm.options
-Xms10g
-Xmx10g
两个值必须一致,避免运行中堆伸缩造成停顿。
4.4 systemd 服务
cat > /etc/systemd/system/elasticsearch.service << 'EOF'
[Unit]
Description=Elasticsearch
After=network.target
[Service]
Type=simple
User=elk
Group=elk
ExecStart=/opt/elk/elasticsearch-7.17.28/bin/elasticsearch
LimitNOFILE=65536
LimitNPROC=4096
LimitMEMLOCK=infinity
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now elasticsearch
LimitMEMLOCK=infinity是bootstrap.memory_lock: true生效的前提。
4.5 验证
curl http://127.0.0.1:9200
# 返回 JSON,可见 "number" : "7.17.28" 即成功
# 首次启动需 10~30 秒,失败查看日志:
tail -f /data/es/logs/elk-cluster.log
4.6 关闭副本(单机无副本节点,避免集群一直 yellow)
curl -X PUT "http://127.0.0.1:9200/_settings" -H 'Content-Type: application/json' -d '{
"index.number_of_replicas": 0
}'
5. 安装 Kibana
5.1 下载解压
cd /opt/elk
wget https://artifacts.elastic.co/downloads/kibana/kibana-7.17.28-linux-x86_64.tar.gz
tar -zxvf kibana-7.17.28-linux-x86_64.tar.gz
chown -R elk:elk /opt/elk/kibana-7.17.28-linux-x86_64
5.2 配置 config/kibana.yml
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://192.168.1.100:9200"]
i18n.locale: "zh-CN" # 中文界面
5.3 systemd 服务
cat > /etc/systemd/system/kibana.service << 'EOF'
[Unit]
Description=Kibana
After=network.target elasticsearch.service
[Service]
Type=simple
User=elk
Group=elk
ExecStart=/opt/elk/kibana-7.17.28-linux-x86_64/bin/kibana
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now kibana
浏览器访问 http://192.168.1.100:5601(需先完成第 8 章防火墙放行),能看到 Kibana 界面即成功(启动较慢,约 1~2 分钟)。
6. 安装 Logstash(多链路管道)
6.1 下载解压
cd /opt/elk
wget https://artifacts.elastic.co/downloads/logstash/logstash-7.17.28-linux-x86_64.tar.gz
tar -zxvf logstash-7.17.28-linux-x86_64.tar.gz
mv logstash-7.17.28 logstash
chown -R elk:elk /opt/elk/logstash
6.2 配置 config/logstash.yml(数据路径 + 批处理调优)
path.data: /data/logstash/data
path.logs: /data/logstash/logs
pipeline.workers: 8 # 建议设为 CPU 核数一半
pipeline.batch.size: 1000 # 默认 125,内存充裕时加大提升吞吐
pipeline.batch.delay: 50
6.3 堆内存 config/jvm.options
-Xms4g
-Xmx4g
6.4 混合接入管道 config/main.conf
一条管道同时承载链路 B(TCP/HTTP)和链路 C(Filebeat),按来源打标、动态路由索引:
input {
# 链路 C:Filebeat 接入
beats {
port => 5044
type => "beats"
}
# 链路 B:应用 TCP 直发(每行一条 JSON)
tcp {
port => 5045
codec => json_lines
type => "app-tcp"
}
# 链路 B 备选:应用 HTTP POST
http {
port => 5046
type => "app-http"
}
}
filter {
# Filebeat 来源的日志(原始文本)做 grok 解析;JSON 来源跳过
if [type] == "beats" and [fields][log_format] != "json" {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:log_time} %{LOGLEVEL:level} %{GREEDYDATA:msg}" }
tag_on_failure => ["_grok_skip"] # 解析失败不丢弃,保留原文
}
}
}
output {
elasticsearch {
hosts => ["http://192.168.1.100:9200"]
# 按 Filebeat 传入的 fields.app 或应用传入的 app 字段动态路由索引
# 与链路 A 直写索引遵循同一命名规范 {业务名}-log-{日期}
index => "%{[@metadata][app_name]}-log-%{+YYYY.MM.dd}"
}
# 调试期可开启 stdout,稳定后注释掉(高吞吐下有性能损耗)
# stdout { codec => rubydebug }
}
动态索引名的数据来源:在 output 之前补一个 filter,把不同链路的业务标识统一收敛到 [@metadata][app_name]:
filter {
if [fields][app] { # Filebeat 端 fields.app
mutate { add_field => { "[@metadata][app_name]" => "%{[fields][app]}" } }
} else if [app] { # TCP/HTTP JSON 里的 app 字段
mutate { add_field => { "[@metadata][app_name]" => "%{[app]}" } }
} else {
mutate { add_field => { "[@metadata][app_name]" => "unknown" } }
}
}
把这段 filter 放在 grok 之前。
@metadata字段不会写入 ES,仅用于管道内路由。
6.5 systemd 服务
cat > /etc/systemd/system/logstash.service << 'EOF'
[Unit]
Description=Logstash
After=network.target elasticsearch.service
[Service]
Type=simple
User=elk
Group=elk
ExecStart=/opt/elk/logstash/bin/logstash -f /opt/elk/logstash/config/main.conf
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now logstash
6.6 本机日志采集(可选)
若需要采集本机 /var/log/messages,在 input 中追加 file 插件,并授权:
file {
path => ["/var/log/messages"]
start_position => "beginning"
type => "systemlog"
}
chmod 644 /var/log/messages
systemctl restart logstash
7. Filebeat 安装配置(被采集端)
Filebeat 装在每台需要采集日志的业务服务器上(不是装在 ELK 服务器),仅占几十 MB 内存。
7.1 安装(被采集端执行)
cd /opt
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.17.28-linux-x86_64.tar.gz
tar -zxvf filebeat-7.17.28-linux-x86_64.tar.gz
mv filebeat-7.17.28-linux-x86_64 filebeat
7.2 配置 filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /app/logs/*.log # 业务日志路径,按实际修改
fields:
app: order-service # 业务标识,决定 ES 中的索引名
log_format: text
fields_under_root: true
# Java 异常堆栈等多行日志合并(按日志行首时间戳识别新行)
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after
output.logstash:
hosts: ["192.168.1.100:5044"] # 指向 ELK 服务器的 Logstash
强烈建议业务日志输出 JSON 格式(Java 用 logstash-logback-encoder),此时设置
log_format: json并在 input 中加json.keys_under_root: true,Logstash 端可省去 grok 解析,字段直接可检索。
7.3 systemd 启动(被采集端,root 运行以读取各类日志)
cat > /etc/systemd/system/filebeat.service << 'EOF'
[Unit]
Description=Filebeat
After=network.target
[Service]
Type=simple
ExecStart=/opt/filebeat/filebeat -c /opt/filebeat/filebeat.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now filebeat
8. 防火墙配置(网段白名单)
9200 未启用认证,任何能访问 9200 的人都能读写甚至删除全部索引,必须用防火墙把访问来源限制在业务网段;SELinux 与 firewalld 同时保持开启。
systemctl enable --now firewalld
# 新建独立 zone:按来源网段控制
firewall-cmd --permanent --new-zone=es-write # 业务系统/被采集端写入区
firewall-cmd --permanent --new-zone=elk-admin # 运维访问区
# 业务网段:9200(链路A直写)+ 5044/5045/5046(链路B/C入Logstash)
firewall-cmd --permanent --zone=es-write --add-source=10.0.1.0/24 # 替换为实际网段,可多条
firewall-cmd --permanent --zone=es-write --add-source=10.0.2.0/24
firewall-cmd --permanent --zone=es-write --add-port={9200,5044,5045,5046}/tcp
# 运维/开发网段:5601(Kibana)+ 9200(curl 排查)
firewall-cmd --permanent --zone=elk-admin --add-source=10.0.100.0/24
firewall-cmd --permanent --zone=elk-admin --add-port={5601,9200}/tcp
firewall-cmd --reload
# 确认规则
firewall-cmd --zone=es-write --list-all
firewall-cmd --zone=elk-admin --list-all
source 网段匹配后,该来源只能访问对应 zone 放行的端口;本机 127.0.0.1 不受限制,服务器本机 curl 验证不受影响。
9. ES 侧统一治理(索引模板 / ILM / 水位线)
混合接入没有统一入口管控,索引规范和生命周期必须在 ES 侧统一配置,三条链路自动生效。
9.1 索引模板(所有业务日志索引自动应用)
curl -X PUT "http://127.0.0.1:9200/_template/biz-log" -H 'Content-Type: application/json' -d '{
"index_patterns": ["*-log-*"],
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"index.lifecycle.name": "log-90d"
}
}'
按天滚动的日志索引 1 主分片足够,分片过多反而拖慢集群。
9.2 ILM 自动清理(日志保留 90 天)
curl -X PUT "http://127.0.0.1:9200/_ilm/policy/log-90d" -H 'Content-Type: application/json' -d '{
"policy": {
"phases": {
"hot": { "actions": {} },
"delete": { "min_age": "90d", "actions": { "delete": {} } }
}
}
}'
ILM 按索引创建时间起算 90 天,配合按天命名的索引实现到期自动删除。
容量预估:每天 5G 原始日志入 ES 膨胀约 1.2~1.5 倍(约 7G/天),1TB 可用约 900G,可存 4 个月以上,配合 90 天 ILM 磁盘长期自平衡。
9.3 磁盘水位线(1TB 数据盘)
| 水位线 | 默认值 | 作用 | 建议值 |
|---|---|---|---|
| low | 85% | 停止分配新分片 | 90% |
| high | 90% | 尝试迁移分片(单机意义不大) | 95% |
| flood_stage | 95% | 索引强制只读 | 20gb(绝对值) |
curl -X PUT "http://127.0.0.1:9200/_cluster/settings" -H 'Content-Type: application/json' -d '{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "90%",
"cluster.routing.allocation.disk.watermark.high": "95%",
"cluster.routing.allocation.disk.watermark.flood_stage": "20gb"
}
}'
9.4 链路 A 直写侧规范(需与业务侧约定)
- 按天建索引
业务名-log-日期,禁止写入单一大索引; - 必须使用
_bulk批量接口,禁止一条日志一次 HTTP 请求; - ES 维护重启期间业务侧需有重试或本地缓冲,避免丢日志或拖垮业务线程。
10. 端到端验证(三条链路)
# 0. 确认三个服务存活
systemctl status elasticsearch kibana logstash
# ── 链路 A:模拟业务直写 ──
curl -X POST "http://127.0.0.1:9200/order-service-log-$(date +%Y.%m.%d)/_doc" \
-H 'Content-Type: application/json' \
-d '{"level":"INFO","msg":"direct write test","ts":"'$(date -Is)'"}'
# ── 链路 B:模拟应用 TCP 直发 Logstash(需 nc)──
echo '{"app":"pay-service","level":"INFO","msg":"tcp test"}' | nc 127.0.0.1 5045
# ── 链路 C:在被采集端启动 Filebeat 后,向 /app/logs/ 写入测试日志 ──
echo "2026-08-25 10:00:00 INFO filebeat test message" >> /app/logs/test.log
# ── 统一确认:三个索引均已创建且模板生效(1 主 0 副本)──
curl http://127.0.0.1:9200/_cat/indices?v
# ── 集群健康(green)──
curl http://127.0.0.1:9200/_cluster/health?pretty
# ── 从业务网段机器验证 9200/5044 通、非白名单网段不通 ──
curl http://192.168.1.100:9200
# ── 确认 SELinux 与防火墙均在位 ──
getenforce # Enforcing
systemctl is-active firewalld # active
Kibana 查看:Management → Stack Management → Index Patterns → Create index pattern,填入 *-log-*(一个 pattern 覆盖三条链路全部业务索引),时间字段选 @timestamp,然后到 Discover 检索。
11. 常见问题排查
| 报错/现象 | 原因与解决 |
|---|---|
| can not run elasticsearch as root | ES 禁止 root 启动,本文 systemd 已指定 User=elk |
| max file descriptors [4096] too low | limits.conf 未生效,重新登录 shell 或检查 systemd 的 LimitNOFILE |
| max virtual memory areas vm.max_map_count too low | 执行sysctl -w vm.max_map_count=262144 并写入 sysctl.conf |
| memory locking requested but memory_lock is false | systemd 单元缺少LimitMEMLOCK=infinity,加上后 daemon-reload 并重启 |
| 业务系统连不上 9200 / Filebeat 连不上 5044 | 检查 es-write zone 的 source 网段与端口:firewall-cmd --zone=es-write --list-all |
| Kibana 打不开 | 先本机curl 127.0.0.1:5601/api/status,再检查 elk-admin zone 网段 |
| Logstash 收到日志但索引名是 unknown-log-* | 业务/Filebeat 未传 app 标识,检查 6.4 的 metadata filter 与 Filebeat fields 配置 |
| Filebeat 日志重复采集 | sincedb 丢失或 path 配置冲突,检查 Filebeat 的 data 目录(默认 /opt/filebeat/data) |
| 多行堆栈被拆成多条 | Filebeat multiline 配置未生效,确认 pattern 与实际日志行首格式匹配 |
| 集群状态一直 yellow | 单机存在无法分配的副本分片,执行 4.6 并确认 9.1 模板已生效 |
| 磁盘写满、索引变只读 | 触发 flood_stage;清理旧索引后执行curl -X PUT "127.0.0.1:9200/_all/_settings" -H 'Content-Type: application/json' -d '{"index.blocks.read_only_allow_delete": null}' 解除 |
| 怀疑 SELinux 拦截 | 执行ausearch -m avc -ts recent 查看审计日志;本方案正常不应出现 |
| 修改数据路径后索引丢失 | 需先将原 data 目录内容整体移动到新路径再启动 |
12. 路径与服务管理速查表
12.1 路径速查(ELK 服务器)
| 内容 | 路径 |
|---|---|
| ES 程序 / 配置 | /opt/elk/elasticsearch-7.17.28/config/elasticsearch.yml |
| ES 数据 / 日志 | /data/es/data、/data/es/logs |
| Kibana 程序 / 配置 | /opt/elk/kibana-7.17.28-linux-x86_64/config/kibana.yml |
| Logstash 程序 / 配置 | /opt/elk/logstash/config/ |
| Logstash 数据 / 日志 | /data/logstash/data、/data/logstash/logs |
| Filebeat(各被采集端) | /opt/filebeat/filebeat.yml |
12.2 端口速查
| 端口 | 用途 | 开放对象 |
|---|---|---|
| 9200 | ES HTTP(直写 + 管理) | 业务网段 + 运维网段 |
| 5044 | Logstash beats input(Filebeat) | 业务网段(被采集端) |
| 5045 | Logstash tcp input(应用直发) | 业务网段 |
| 5046 | Logstash http input(应用直发) | 业务网段 |
| 5601 | Kibana Web | 运维网段 |
12.3 服务管理速查
systemctl restart elasticsearch kibana logstash # 改配置后按此顺序重启
systemctl status elasticsearch # 查看状态
journalctl -u elasticsearch -f # ES systemd 日志
tail -f /data/es/logs/elk-cluster.log # ES 应用日志
tail -f /data/logstash/logs/logstash-plain.log # Logstash 应用日志
journalctl -u kibana -f # Kibana 日志
journalctl -u filebeat -f # Filebeat 日志(被采集端)
12.4 防火墙速查
firewall-cmd --zone=es-write --list-all # 业务写入白名单
firewall-cmd --zone=elk-admin --list-all # 运维白名单
firewall-cmd --permanent --zone=es-write --add-source=新网段/24 && firewall-cmd --reload # 新增业务网段
重要提醒
- ES / Kibana / Logstash / Filebeat 版本号必须严格一致。
- 本方案以防火墙网段白名单代替认证:务必确保 9200/5601/5044 等端口不对非信任网段开放,尤其禁止暴露公网。若有跨网段、多租户访问需求,建议开启 xpack 安全认证或升级 8.x。
- 三条接入链路并存时,索引命名规范(
业务名-log-日期)是治理根基,务必在接入前与业务侧书面约定;ES 侧模板/ILM 只做兜底,不能纠正乱命名。 - 新接入的业务优先推荐链路 C(写文件 + Filebeat),可靠性最好;链路 B 仅用于容器化等不便落文件的场景。
- CentOS 7.9 已于 2024 年 6 月停止维护,yum 源失效可更换阿里云/腾讯云 vault 源;新上生产环境建议 Rocky/Alma Linux 9 + ELK 8.x。