适用环境: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)


目录

  1. 混合接入架构与规划
  2. 系统初始化(SELinux 保持开启)
  3. 数据盘挂载(/data,1TB)
  4. 安装 Elasticsearch
  5. 安装 Kibana
  6. 安装 Logstash(多链路管道)
  7. Filebeat 安装配置(被采集端)
  8. 防火墙配置(网段白名单)
  9. ES 侧统一治理(索引模板 / ILM / 水位线)
  10. 端到端验证(三条链路)
  11. 常见问题排查
  12. 路径与服务管理速查表

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 直写侧规范(需与业务侧约定)

  1. 按天建索引 业务名-log-日期,禁止写入单一大索引;
  2. 必须使用 _bulk 批量接口,禁止一条日志一次 HTTP 请求;
  3. 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   # 新增业务网段

重要提醒

  1. ES / Kibana / Logstash / Filebeat 版本号必须严格一致。
  2. 本方案以防火墙网段白名单代替认证:务必确保 9200/5601/5044 等端口不对非信任网段开放,尤其禁止暴露公网。若有跨网段、多租户访问需求,建议开启 xpack 安全认证或升级 8.x。
  3. 三条接入链路并存时,索引命名规范(业务名-log-日期)是治理根基,务必在接入前与业务侧书面约定;ES 侧模板/ILM 只做兜底,不能纠正乱命名。
  4. 新接入的业务优先推荐链路 C(写文件 + Filebeat),可靠性最好;链路 B 仅用于容器化等不便落文件的场景。
  5. CentOS 7.9 已于 2024 年 6 月停止维护,yum 源失效可更换阿里云/腾讯云 vault 源;新上生产环境建议 Rocky/Alma Linux 9 + ELK 8.x。