日志是服务器写给运维人员的一封信。但当这台服务器从一台变成一百台,这封信就变成了散落在各个角落的碎片。ELK,就是把碎片拼成全景的那双手。
文章目录
-
- 一、为什么需要集中式日志分析
- [二、ELK 三件套:角色与分工](#二、ELK 三件套:角色与分工)
-
- [1. 一个银行类比](#1. 一个银行类比)
- [2. Elasticsearch:分布式搜索和分析引擎](#2. Elasticsearch:分布式搜索和分析引擎)
- [3. Logstash:服务器端数据处理管道](#3. Logstash:服务器端数据处理管道)
- [4. Kibana:数据可视化与管理平台](#4. Kibana:数据可视化与管理平台)
- 三、工作原理与数据链路
- 四、实验环境规划
- [五、部署 Elasticsearch 集群](#五、部署 Elasticsearch 集群)
-
- [1. 准备主机名解析与 Java 环境](#1. 准备主机名解析与 Java 环境)
- [2. node1:安装并配置 Elasticsearch](#2. node1:安装并配置 Elasticsearch)
- [3. node2:安装并配置 Elasticsearch](#3. node2:安装并配置 Elasticsearch)
- [4. 检查集群健康与状态](#4. 检查集群健康与状态)
- [六、部署 elasticsearch-head 可视化管理插件](#六、部署 elasticsearch-head 可视化管理插件)
-
- [1. node1:编译安装 Node.js](#1. node1:编译安装 Node.js)
- [2. node1:安装 PhantomJS](#2. node1:安装 PhantomJS)
- [3. node1:安装并启动 elasticsearch-head](#3. node1:安装并启动 elasticsearch-head)
- [4. node2:同样的安装流程](#4. node2:同样的安装流程)
- [5. 验证结果](#5. 验证结果)
- [七、部署 Logstash 日志采集管道](#七、部署 Logstash 日志采集管道)
-
- [1. 环境准备](#1. 环境准备)
- [2. 安装 Logstash](#2. 安装 Logstash)
- [3. 命令级对接测试](#3. 命令级对接测试)
- [4. 编写 Logstash 配置文件采集系统日志](#4. 编写 Logstash 配置文件采集系统日志)
- [八、部署 Kibana 可视化平台](#八、部署 Kibana 可视化平台)
- [九、接入 Apache 业务日志](#九、接入 Apache 业务日志)
- 十、总结
一、为什么需要集中式日志分析
日志分析是运维工程师排查系统故障、发现潜在问题的核心手段。日志主要包括系统日志、应用程序日志和安全日志三类。
系统运维和开发人员可以通过日志了解服务器的软硬件信息、检查配置过程中的错误以及错误发生的根因。持续分析日志,能够掌握服务器的负载、性能与安全态势,从而及时采取措施纠正错误。
然而问题在于:日志天然分散。通常,日志被零散地存储在不同设备上。如果你管理着数十上百台服务器,仍在用依次登录每台机器的传统方法查阅日志,既繁琐又低效。为此,我们首先需要引入集中化日志管理(例如开源的 syslog),将所有服务器上的日志收集汇总。
但集中化只解决了一半问题------日志的统计与检索 随之成为新的难题。grep、awk、wc 等 Linux 命令可以实现基础的检索和统计,可面对更高要求的查询、排序与聚合分析,再加上庞大的机器数量,这类方法难免力不从心。
ELK 实时日志分析平台 能够完美解决上述问题。ELK 由 Elasticsearch、Logstash 和 Kibana 三个开源工具组成(官方网站:https://www.elastic.co/products):
- Elasticsearch :开源分布式搜索引擎。特点是分布式、零配置、自动发现、索引自动分片、索引副本机制、RESTful 风格接口、多数据源、自动搜索负载等。作用是存储处理后的日志,提供高速查询与复杂数据分析。
- Logstash:完全开源的服务器端数据处理管道,负责对日志进行收集、过滤与存储,供后续检索使用。
- Kibana:开源免费的数据可视化平台,为 Logstash 和 Elasticsearch 提供友好的日志分析 Web 界面,帮助汇总、分析和搜索重要数据日志。
二、ELK 三件套:角色与分工
1. 一个银行类比
理解三者关系的最好方式,是想象一个银行系统:
- Logstash 就像各地的柜台职员和运钞车。它负责从各个来源(ATM、柜台、网上银行)收集货币(数据),进行清点、验伪、分类整理(解析与转换),然后运送到总行金库。
- Elasticsearch 就是银行的巨型、高科技、超高效的金库与归档系统。它不仅安全地存储所有货币(数据),还建立了极其精细的索引。需要查询时,它能在一瞬间从海量库存中精准定位任何一张钞票或任何一笔交易记录。
- Kibana 则是银行数据分析与监控中心的大屏幕。它连接到金库(Elasticsearch),让管理人员和分析师通过图表、仪表盘、地图来可视化金融趋势、交易流水与风险状况,而不是面对一堆枯燥的数字表格。
2. Elasticsearch:分布式搜索和分析引擎
核心角色:大脑与心脏------负责海量数据的存储、检索和分析。
- 分布式存储与高可用性:Elasticsearch 是分布式数据库,数据被分散存储在多个服务器(节点)上,可处理 PB 级海量数据;通过副本(replicas)机制,即使某个硬件发生故障,数据不丢失、服务不中断,实现高可用。
- 近乎实时的搜索:数据从写入到可被搜索只有毫秒级延迟(约 1 秒内),这对实时监控与告警场景至关重要。
- 强大的全文搜索:基于 Apache Lucene 构建,不止于关键字匹配,还支持模糊搜索(拼写错误也能命中)、同义词处理(搜"手机"能找到"电话")、相关性评分(最相关的结果排最前)。
- 先进的索引技术:数据写入时会被构建为倒排索引(Inverted Index)------类似书末的索引页(例如"提到『数据库』一词的页码是 10、23、45"),查询速度远优于传统数据库的逐行扫描。
- 丰富的 RESTful API:数据写入、查询、集群管理几乎都可以通过简单的 HTTP REST API 完成,极易与周边系统集成开发。
- 强大的聚合分析 :除了搜索,还能执行复杂的聚合(Aggregation)操作,相当于 SQL 的
GROUP BY再加上大量数学运算。例如:"统计过去 5 分钟内错误日志的数量并按应用分组?""计算网站访问量的 95 百分位延迟?""绘制用户地理位置分布图?"
一句话总结:Elasticsearch 是一个专门为"快速查找"而设计的海量数据存储系统。它不擅长频繁更新的事务(那是 MySQL 的强项),但极其擅长对巨量数据进行快速过滤、查询与分析。
3. Logstash:服务器端数据处理管道
核心角色:搬运工与预处理车间------负责收集、解析、转换和输送数据。
Logstash 的工作流程划分为三个阶段:Input → Filter → Output。
1. Input(输入):数据收集
从各种来源实时收集数据与日志,凭借丰富的插件支持极多的输入源:
- 文件(如
*.log) - 系统日志(Syslog)
- 消息队列(Kafka、Redis、RabbitMQ)
- 数据库(MySQL、PostgreSQL)
- 监控数据(Beats、JMX)
- 网络协议(TCP/UDP、HTTP)
2. Filter(过滤):数据解析与丰富(Enrichment)
这是 Logstash 最强大的部分。原始日志(一行文本)通常是非结构化的,Filter 插件将其解析为结构化、有意义的字段,便于在 Elasticsearch 中高效查询。常用插件:
- Grok :用正则模式解析复杂文本行。例如从下面这条 Apache 访问日志中,提取出
client_ip、timestamp、http_method、response_code等字段:
bash
127.0.0.1 - - [10/Oct/2023:14:16:39 +0000] "GET / HTTP/1.1" 200 3574
- Mutate:修改字段------重命名、删除、替换、转换数据类型
- Date :解析时间戳,设置为事件的正式
@timestamp字段 - GeoIP:根据 IP 地址反查国家、城市与经纬度,极大丰富数据维度
- KV :解析
key=value形式的数据
3. Output(输出):数据发送
将处理好的数据送往指定目的地。最常用的输出是 Elasticsearch,同时也支持其他数据库(MongoDB)、消息队列(Kafka)、文件系统、监控系统(Nagios)、电子邮件等。
一句话总结:Logstash 是一个数据流引擎,负责把杂乱无章的原始数据"加工"成干净、结构化的数据,再喂给 Elasticsearch。它是功能全面的重量级工具,相应地资源消耗也较高。
小提示:在需要轻量采集的场景下,Elastic 官方提供了 Beats 家族(Filebeat、Metricbeat 等)来替代 Logstash 的 Input 角色------更轻、更专一,通常将数据直接发给 Logstash 做进一步处理,或直接写入 Elasticsearch。
4. Kibana:数据可视化与管理平台
核心角色:窗口与仪表盘------用于数据的探索、可视化与交互。
- 数据探索与发现(Discover):交互式界面直接查询、浏览 Elasticsearch 中的原始数据,支持 Lucene 查询语法或 KQL,可添加过滤器动态缩小数据范围,查看匹配文档的详情。
- 可视化(Visualize):丰富的可视化组件------柱状图、折线图、饼图、指标看板(单个数字,如总错误数)、数据表(聚合数据)、坐标地图(结合 GeoIP 在地图上展示数据点)、热力图等。
- 仪表盘(Dashboard):将多个可视化组件拖放组合成统一综合的监控大屏,让运维与开发团队在一个屏幕上全局掌握系统健康状态、性能指标与业务趋势。
- 管理和维护(Stack Management):管理整个 Elastic Stack 的配置,如索引生命周期管理(ILM)、用户与角色权限控制、导入/导出保存的可视化与仪表盘、配置 Kibana 本身。
一句话总结:Kibana 是 ELK Stack 的"面子",它将 Elasticsearch 中深奥的数据以人类易于理解的图形方式呈现,让任何人都能轻松进行数据分析和决策,而无需编写复杂的查询代码。
这正是 ELK / Elastic Stack 的强大之处------它将数据的收集、存储、可视化三个环节无缝衔接,提供端到端的解决方案,广泛应用于日志分析、应用性能监控(APM)、安全信息与事件管理(SIEM)、业务指标分析等领域。
三、工作原理与数据链路
ELK 工作原理示意:
bash
【AppServer 集群】 → 【logstash Agent 采集器】 → 【Elasticsearch Cluster】 → 【Kibana Server】 → 【Browser】
Logstash 收集 AppServer 产生的日志并存入 Elasticsearch 集群,Kibana 则从 ES 集群查询数据生成图表,返回给浏览器。简单来说,一次完整的日志处理分析通常经过以下步骤:
- Filebeat 将日志集中化管理(Beats 家族),在采集端替代 Logstash;
- Logstash 将日志格式化;
- Elasticsearch 对格式化后的数据进行索引与存储;
- Kibana 完成前端数据展示。
四、实验环境规划
本次实战以集群方式配置 ELK 日志分析系统:2 个 Elasticsearch 节点 ,并监控 Apache 服务器日志。使用 CentOS7-template 模板机克隆 3 台主机:

| 主机 | 操作系统 | 主机名 | IP 地址 | 主要软件 |
|---|---|---|---|---|
| 服务器 | CentOS 7.9 | node1 | 192.168.108.41 | Elasticsearch、Kibana |
| 服务器 | CentOS 7.9 | node2 | 192.168.108.42 | Elasticsearch |
| 服务器 | CentOS 7.9 | apache | 192.168.108.43 | Logstash、Apache |

数据流向为:apache 节点上的 Logstash 采集系统与业务日志 → 写入 node1/node2 组成的 Elasticsearch 集群 → 由 node1 上的 Kibana 做前端展示,同时通过各节点的 elasticsearch-head(9100 端口)管理集群。
五、部署 Elasticsearch 集群
1. 准备主机名解析与 Java 环境
登录 node1(192.168.108.41),在 /etc/hosts 最底部添加两行域名解析,并确认 Java 环境:
bash
[root@node1 ~]# vim /etc/hosts
192.168.108.41 node1
192.168.108.42 node2
[root@node1 ~]# java -version
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
登录 node2(192.168.108.42),更改主机名,做同样的域名解析配置并确认 Java 环境:
bash
[root@node2 ~]# vim /etc/hosts
192.168.108.41 node1
192.168.108.42 node2
[root@node2 ~]# java -version
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
2. node1:安装并配置 Elasticsearch
上传 elasticsearch-5.5.0.rpm 到 /opt 目录并安装:
bash
[root@node1 ~]# cd /opt
[root@node1 opt]# rpm -ivh elasticsearch-5.5.0.rpm
# 加载系统服务
[root@node1 ~]# systemctl daemon-reload
[root@node1 ~]# systemctl enable elasticsearch.service
备份并修改主配置文件:
bash
[root@node1 ~]# cp /etc/elasticsearch/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml.bak
[root@node1 ~]# vim /etc/elasticsearch/elasticsearch.yml
bash
17 cluster.name: my-elk-cluster # 集群名字
23 node.name: node1 # 节点名字
33 path.data: /data/elk_data # 数据存放路径
37 path.logs: /var/log/elasticsearch/ # 日志存放路径
43 bootstrap.memory_lock: false # 启动时不锁定内存。锁定物理内存地址可防止 ES 内存被交换出去(避免使用 swap),频繁交换会导致 IOPS 变高
55 network.host: 0.0.0.0 # 服务绑定的 IP 地址,0.0.0.0 代表所有地址
59 http.port: 9200 # 侦听端口为 9200
68 discovery.zen.ping.unicast.hosts: ["node1", "node2"] # 集群发现通过单播实现
创建数据存放路径并授权,随后启动服务:
bash
[root@node1 opt]# mkdir -p /data/elk_data
[root@node1 opt]# chown elasticsearch:elasticsearch /data/elk_data/
[root@node1 elasticsearch]# systemctl start elasticsearch.service
[root@node1 elasticsearch]# netstat -antp | grep 9200
tcp6 0 0 :::9200 :::* LISTEN 64463/java
查看节点信息------用真机(192.168.108.1)浏览器打开 http://192.168.108.41:9200,返回节点信息即说明启动成功:
bash
{
"name" : "node1",
"cluster_name" : "my-elk-cluster",
"cluster_uuid" : "KnVmyqgIRVqNtWVbic3Jbw",
"version" : {
"number" : "5.5.0",
"build_hash" : "260387d",
"build_date" : "2017-06-30T23:16:05.735Z",
"build_snapshot" : false,
"lucene_version" : "6.6.0"
},
"tagline" : "You Know, for Search"
}
3. node2:安装并配置 Elasticsearch
操作与 node1 基本一致,仅主机名不同。上传 elasticsearch-5.5.0.rpm 到 /opt:
bash
[root@node2 ~]# cd /opt
[root@node2 opt]# rpm -ivh elasticsearch-5.5.0.rpm
[root@node2 ~]# systemctl daemon-reload
[root@node2 ~]# systemctl enable elasticsearch.service
[root@node2 ~]# cp /etc/elasticsearch/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml.bak
[root@node2 ~]# vim /etc/elasticsearch/elasticsearch.yml
bash
17 cluster.name: my-elk-cluster # 集群名字(必须与 node1 一致)
23 node.name: node2 # 节点名字(与 node1 区分)
33 path.data: /data/elk_data # 数据存放路径
37 path.logs: /var/log/elasticsearch/ # 日志存放路径
43 bootstrap.memory_lock: false # 启动时不锁定内存
55 network.host: 0.0.0.0 # 绑定所有地址
59 http.port: 9200 # 侦听端口
68 discovery.zen.ping.unicast.hosts: ["node1", "node2"] # 单播集群发现
bash
[root@node2 ~]# mkdir -p /data/elk_data
[root@node2 ~]# chown elasticsearch:elasticsearch /data/elk_data/
[root@node2 elasticsearch]# systemctl start elasticsearch.service
[root@node2 elasticsearch]# netstat -antp | grep 9200
tcp6 0 0 :::9200 :::* LISTEN 64463/java
浏览器打开 http://192.168.108.42:9200 查看节点信息:
bash
{
"name" : "node2",
"cluster_name" : "my-elk-cluster",
"cluster_uuid" : "KnVmyqgIRVqNtWVbic3Jbw",
"version" : {
"number" : "5.5.0",
"build_hash" : "260387d",
"build_date" : "2017-06-30T23:16:05.735Z",
"build_snapshot" : false,
"lucene_version" : "6.6.0"
},
"tagline" : "You Know, for Search"
}
4. 检查集群健康与状态
浏览器打开 http://192.168.108.41:9200/_cluster/health?pretty 检查集群健康状况------status: green 即正常,number_of_nodes 应为 2:
bash
{
"cluster_name" : "my-elk-cluster",
"status" : "green", # green 就正常
"timed_out" : false,
"number_of_nodes" : 2, # nodes 要为 2
"number_of_data_nodes" : 2,
"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
}
浏览器打开 http://192.168.108.41:9200/_cluster/state?pretty 检查集群状态信息,可见 node1、node2 均已加入集群:
bash
{
"cluster_name" : "my-elk-cluster",
"version" : 5,
"state_uuid" : "iZdm0i61SPyHuKT3nYHukA",
"master_node" : "jFRvlxKqTByVsRsad1UHCg",
"blocks" : { },
"nodes" : {
"jFRvlxKqTByVsRsad1UHCg" : {
"name" : "node1",
"ephemeral_id" : "N1sLK7QiRVyd-4JNyKuW3A",
"transport_address" : "192.168.108.41:9300",
"attributes" : { }
},
"3uKGTZaJRiS-bZ5TGBhiag" : {
"name" : "node2",
"ephemeral_id" : "KDX_zchjRW26YkR3OGs7gA",
"transport_address" : "192.168.108.42:9300",
"attributes" : { }
}
},
"metadata" : {
"cluster_uuid" : "KnVmyqgIRVqNtWVbic3Jbw",
"templates" : { },
"indices" : { },
"index-graveyard" : {
"tombstones" : [ ]
}
},
"routing_table" : {
"indices" : { }
},
"routing_nodes" : {
"unassigned" : [ ],
"nodes" : {
"3uKGTZaJRiS-bZ5TGBhiag" : [ ],
"jFRvlxKqTByVsRsad1UHCg" : [ ]
}
}
}
六、部署 elasticsearch-head 可视化管理插件
通过浏览器直接查看集群状态的方式并不直观,安装 elasticsearch-head 插件后即可图形化管理集群。head 插件依赖 Node.js 运行环境,还需要 PhantomJS(无界面浏览器,用于前端渲染/测试)。
1. node1:编译安装 Node.js
上传 node-v8.2.1.tar.gz 到 /opt,编译安装(耗时较长,约 10 分钟):
bash
[root@node1 ~]# yum install gcc gcc-c++ make -y
[root@node1 ~]# cd /opt
[root@node1 opt]# tar xzvf node-v8.2.1.tar.gz
[root@node1 opt]# cd node-v8.2.1/
[root@node1 node-v8.2.1]# ./configure
[root@node1 node-v8.2.1]# make -j4 # 等待时间较长
[root@node1 node-v8.2.1]# make install
2. node1:安装 PhantomJS
上传软件包到 /usr/local/src/:
bash
[root@node1 node-v8.2.1]# cd /usr/local/src/
[root@node1 src]# tar xjvf phantomjs-2.1.1-linux-x86_64.tar.bz2
[root@node1 src]# cd phantomjs-2.1.1-linux-x86_64/bin
[root@node1 bin]# cp phantomjs /usr/local/bin
3. node1:安装并启动 elasticsearch-head
bash
[root@node1 bin]# cd /usr/local/src/
[root@node1 src]# tar xzvf elasticsearch-head.tar.gz # 解压 head 插件源码包
[root@node1 src]# cd elasticsearch-head/ # 进入插件目录
[root@node1 elasticsearch-head]# npm install # npm(Node Package Manager,Node.js 的包管理工具)安装 package.json 定义的全部依赖
修改 Elasticsearch 主配置文件,在末尾添加跨域配置(head 是独立站点,必须开启 CORS 才能访问 ES 的 9200 端口):
bash
[root@node1 ~]# cd ~
[root@node1 ~]# vim /etc/elasticsearch/elasticsearch.yml # 以下配置插在文件末尾
http.cors.enabled: true ## 开启跨域访问支持,默认为 false
http.cors.allow-origin: "*" ## 跨域访问允许的域名地址
[root@node1 ~]# systemctl restart elasticsearch
启动 head 插件服务器:
bash
[root@node1 ~]# cd /usr/local/src/elasticsearch-head/
[root@node1 elasticsearch-head]# npm run start & # 切换到后台运行
[1] 114729
elasticsearch-head@0.0.0 start /usr/local/src/elasticsearch-head
grunt server
Running "connect:server" (connect) task
Waiting forever...
Started connect web server on http://localhost:9100
[root@node1 elasticsearch-head]# netstat -lnupt | grep 9100
tcp 0 0 0.0.0.0:9100 0.0.0.0:* LISTEN 114739/grunt
[root@node1 elasticsearch-head]# netstat -lnupt | grep 9200
tcp6 0 0 :::9200 :::* LISTEN 114626/java
4. node2:同样的安装流程
上传 node-v8.2.1.tar.gz 到 /opt,编译安装 Node.js(耗时较长,约 10 分钟):
bash
[root@node2 ~]# yum install gcc gcc-c++ make -y
[root@node2 ~]# cd /opt
[root@node2 opt]# tar xzvf node-v8.2.1.tar.gz
[root@node2 opt]# cd node-v8.2.1/
[root@node2 node-v8.2.1]# ./configure
[root@node2 node-v8.2.1]# make -j4 # 等待时间较长
[root@node2 node-v8.2.1]# make install
安装 PhantomJS:
bash
[root@node2 node-v8.2.1]# cd /usr/local/src/
[root@node2 src]# tar xjvf phantomjs-2.1.1-linux-x86_64.tar.bz2
[root@node2 src]# cd phantomjs-2.1.1-linux-x86_64/bin
[root@node2 bin]# cp phantomjs /usr/local/bin
安装 elasticsearch-head:
bash
[root@node2 bin]# cd /usr/local/src/
[root@node2 src]# tar xzvf elasticsearch-head.tar.gz
[root@node2 src]# cd elasticsearch-head/
[root@node2 elasticsearch-head]# npm install
修改主配置文件并重启:
bash
[root@node2 ~]# cd ~
[root@node2 ~]# vim /etc/elasticsearch/elasticsearch.yml # 以下配置插在文件末尾
http.cors.enabled: true ## 开启跨域访问支持
http.cors.allow-origin: "*" ## 跨域访问允许的域名地址
[root@node2 ~]# systemctl restart elasticsearch
启动 head 插件服务器:
bash
[root@node2 ~]# cd /usr/local/src/elasticsearch-head/
[root@node2 elasticsearch-head]# npm run start & # 切换到后台运行
[1] 114729
elasticsearch-head@0.0.0 start /usr/local/src/elasticsearch-head
grunt server
Running "connect:server" (connect) task
Waiting forever...
Started connect web server on http://localhost:9100
[root@node2 elasticsearch-head]# netstat -lnupt | grep 9100
tcp 0 0 0.0.0.0:9100 0.0.0.0:* LISTEN 114739/grunt
[root@node2 elasticsearch-head]# netstat -lnupt | grep 9200
tcp6 0 0 :::9200 :::* LISTEN 114626/java
5. 验证结果
node1 现象 :笔记本浏览器打开 http://192.168.108.41:9100/,初始显示"集群健康值:未连接"。在 Elasticsearch 地址栏输入 http://192.168.108.41:9200 并点击"连接",集群健康值变为 green (0 of 0),页面同时列出 node1 与 node2 两个节点的信息与动作。

node2 现象 :笔记本浏览器打开 http://192.168.108.42:9100/,同样先显示"集群健康值:未连接"。在 Elasticsearch 地址栏输入 http://192.168.108.42:9200 并点击"连接",集群健康值同样为 green (0 of 0),此时 node2 显示为当前信息动作节点,node1 仍完整可见。

写入测试数据 :登录 node1,创建索引 index-demo、类型 test,验证写入成功:
bash
[root@node1 ~]# curl -XPUT 'localhost:9200/index-demo/test/1?pretty&pretty' -H 'content-Type: application/json' -d '{"user":"zhangsan","mesg":"hello world"}'
{
"_index" : "index-demo",
"_type" : "test",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"created" : true
}
浏览器打开 http://192.168.108.41:9100/ 查看索引信息,可见索引默认被分为 5 个分片、1 个副本 :node1 承担分片 0~4 的信息动作,node2 同样持有分片 0~4。这说明 node1 和 node2 是平等关系,不是主从关系------Elasticsearch 集群没有主从节点之分,节点完全对等。
点击"数据浏览"即可看到存储的数据:刚才在 node1 创建的 index-demo / test 索引,文档内容为 {"user":"zhangsan","mesg":"hello world"}。
七、部署 Logstash 日志采集管道
Logstash 部署在 apache 节点(192.168.108.43),负责把日志收集后输出到 Elasticsearch。
1. 环境准备
登录 apache 主机,关闭防火墙与 SELinux,安装 Apache 服务(httpd):
bash
[root@apache ~]# yum -y install httpd
[root@apache ~]# systemctl start httpd
# 访问下日志
[root@apache ~]# cd /var/log/httpd/
[root@apache httpd]# ls
access_log error_log
# access_log 访问日志
# error_log 错误日志
确认 Java 环境(Logstash 运行于 JVM 之上):
bash
[root@apache ~]# java -version
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
2. 安装 Logstash
上传 logstash-5.5.1.rpm 到 /opt 目录:
bash
[root@apache ~]# cd /opt
[root@apache opt]# rpm -ivh logstash-5.5.1.rpm # 安装 logstash
[root@apache opt]# systemctl start logstash.service # 启动 logstash
[root@apache opt]# systemctl enable logstash.service
[root@apache opt]# ln -s /usr/share/logstash/bin/logstash /usr/local/bin/ # 建立 logstash 软连接
3. 命令级对接测试
Logstash 常用测试参数:
-f:指定 Logstash 配置文件,按文件配置运行;-e:后跟字符串作为临时配置(若为"",默认以 stdin 为输入、stdout 为输出);-t:测试配置文件是否合法,然后退出。
测试一:stdin 输入 → stdout 输出。 这条命令启动一个"标准输入读、标准输出写"的最简管道,用于快速验证 Logstash 能否正常运行:
bash
[root@apache ~]# logstash -e 'input { stdin{} } output { stdout{} }'
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
WARNING: Could not find logstash.yml which is typically located in $LS_HOME/config or /etc/logstash. You can specify the path using --path.settings. Continuing using the defaults
Could not find log4j2 configuration at path //usr/share/logstash/config/log4j2.properties. Using default config which logs to console
15:04:01.317 [main] INFO logstash.setting.writabledirectory - Creating directory {:setting=>"path.queue", :path=>"/usr/share/logstash/data/queue"}
15:04:01.321 [main] INFO logstash.setting.writabledirectory - Creating directory {:setting=>"path.dead_letter_queue", :path=>"/usr/share/logstash/data/dead_letter_queue"}
15:04:01.342 [LogStash::Runner] INFO logstash.agent - No persistent UUID file found. Generating new UUID {:uuid=>"3d0b1388-05c5-4a06-b6f4-61d071064844", :path=>"/usr/share/logstash/data/uuid"}
15:04:01.469 [[main]-pipeline-manager] INFO logstash.pipeline - Starting pipeline {"id"=>"main", "pipeline.workers"=>4, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>5, "pipeline.max_inflight"=>500}
15:04:01.518 [[main]-pipeline-manager] INFO logstash.pipeline - Pipeline main started
The stdin plugin is now waiting for input:
15:04:01.581 [Api Webserver] INFO logstash.agent - Successfully started Logstash API endpoint {:port=>9600}
www.baidu.com # 需要输入 www.baidu.com
2025-12-12T07:05:01.001Z apache www.baidu.com
www.sina.com.cn # 需要输入 www.sina.com.cn
2025-12-12T07:05:08.375Z apache www.sina.com.cn # ctrl+c 退出
^C15:05:15.825 [SIGINT handler] WARN logstash.runner - SIGINT received. Shutting down the agent.
15:05:16.225 [LogStash::Runner] WARN logstash.agent - stopping pipeline {:id=>"main"}
开头的 ERROR/WARNING 属于 Java 体系未配置 log4j2 的常规提示,不影响运行。
测试二:用 rubydebug 显示详细输出。 codec 是一种编解码器:
bash
[root@apache ~]# logstash -e 'input { stdin{} } output { stdout{ codec=>rubydebug } }'
......(启动日志略)......
The stdin plugin is now waiting for input:
www.baidu.com # 需要输入 www.baidu.com
{
"@timestamp" => 2025-12-12T07:08:43.174Z,
"@version" => "1",
"host" => "apache",
"message" => "www.baidu.com"
} # ctrl+c 退出
测试三:stdin 输入 → Elasticsearch 输出,完成对接。
bash
[root@apache ~]# logstash -e 'input { stdin{} } output { elasticsearch { hosts=>["192.168.108.41:9200"] } }'
......(省略)......
The stdin plugin is now waiting for input:
15:14:21.757 [Api Webserver] INFO logstash.agent - Successfully started Logstash API endpoint {:port=>9600}
www.baidu.com # 输入内容
www.360.cn # 输入内容
www.qq.com # 输入内容
# ctrl+c 退出
在笔记本(192.168.108.1)浏览器打开 http://192.168.108.41:9100/,可见多出一个 logstash-2025.12.12 索引(未命名时自动以日期为后缀)。查看其索引信息,同样按默认规则分片并带副本;点击"数据浏览"可以看到三条输入内容已被写成 ES 文档。
4. 编写 Logstash 配置文件采集系统日志
Logstash 配置文件主要由三部分组成:input、output、filter(按需)。
先放开系统日志的读权限:
bash
[root@apache ~]# chmod o+r /var/log/messages
[root@apache ~]# ll /var/log/messages
-rw----r--. 1 root root 856951 Dec 12 15:51 /var/log/messages
编写采集配置:
bash
[root@apache opt]# vim /etc/logstash/conf.d/system.conf
bash
input {
file {
path => "/var/log/messages"
type => "system"
start_position => "beginning"
}
}
output {
elasticsearch {
hosts => ["192.168.108.41:9200"]
index => "system-%{+YYYY.MM.dd}"
}
}
bash
[root@apache opt]# systemctl restart logstash.service
笔记本浏览器打开 http://192.168.108.41:9100/ 查看索引信息,多出 system-2025.12.12;点击"数据浏览"可看到采集进来的系统日志内容。


数据能进来,但纯 JSON 的内容并不直观------这正是需要 Kibana 的时刻。
八、部署 Kibana 可视化平台
Kibana 安装在 node1(192.168.108.41)主机上。上传 kibana-5.5.1-x86_64.rpm 到 /usr/local/src 目录:

bash
[root@node1 ~]# cd /usr/local/src/
[root@node1 src]# rpm -ivh kibana-5.5.1-x86_64.rpm
[root@node1 src]# cd /etc/kibana/
[root@node1 kibana]# cp kibana.yml kibana.yml.bak
[root@node1 kibana]# vim kibana.yml
bash
2 server.port: 5601 # kibana 打开的端口
7 server.host: "0.0.0.0" # kibana 侦听的地址
21 elasticsearch.url: "http://192.168.108.41:9200" # 和 elasticsearch 建立联系
30 kibana.index: ".kibana" # 在 elasticsearch 中添加 .kibana 索引
bash
[root@node1 kibana]# systemctl start kibana.service # 启动 kibana 服务
[root@node1 kibana]# systemctl enable kibana.service # 开机启动 kibana 服务
笔记本浏览器输入 192.168.108.41:5601。首次登录要求配置索引模式(Index pattern),需要填写一个匹配 ES 中索引名称的模式串:

-
名称填写
system-*(对接系统日志文件),点击底部的 Create 按钮创建;
-
创建完成后,点击左上角的 Discover 按钮,即可看到
system-*的实时日志流;
-
在 Discover 页面左下角的字段列表中,点击
host旁的 add 将其加入显示列,再同样加上message字段。
此时右侧只剩下 Time、host、message 三项,日志以时间为横轴、按主机名与消息内容展开,界面立刻清爽友好,远非"数据浏览"里的原始 JSON 可比。

九、接入 Apache 业务日志
接下来对接 Apache 主机的访问日志与错误日志。在 apache 主机(192.168.108.43)上操作:
bash
[root@apache ~]# cd /etc/logstash/conf.d/
[root@apache conf.d]# touch apache_log.conf
[root@apache conf.d]# vim apache_log.conf
bash
input {
file {
path => "/var/log/httpd/access_log"
type => "access"
start_position => "beginning"
}
file {
path => "/var/log/httpd/error_log"
type => "error"
start_position => "beginning"
}
}
output {
if [type] == "access" {
elasticsearch {
hosts => ["192.168.108.41:9200"]
index => "apache_access-%{+YYYY.MM.dd}"
}
}
if [type] == "error" {
elasticsearch {
hosts => ["192.168.108.41:9200"]
index => "apache_error-%{+YYYY.MM.dd}"
}
}
}
bash
[root@apache conf.d]# /usr/share/logstash/bin/logstash -f apache_log.conf
访问一次 Apache 站点产生日志(浏览器打开 http://192.168.108.43,看到 CentOS 默认测试页即为访问成功)。
在 head(http://192.168.108.41:9100/)中查看索引信息,可发现 apache_access-2025.12.12 与 apache_error-2025.12.12 两个新索引,两类日志被条件判断(if [type])分别投递到了各自的索引。
最后打开 Kibana(http://192.168.108.41:5601,必要时多刷新几次):Management → Index Patterns → Create index pattern ,分别创建 apache_access-* 和 apache_error-* 两个索引模式,选择 @timestamp 作为时间字段并完成创建。
完成后进入 Discover,切换到对应的索引模式,Apache 的访问与错误日志便按时间顺序直观呈现------至此,一条从业务服务器到前端大屏的完整企业级日志分析链路正式贯通。
十、总结
从"逐台登录翻日志"到"一屏纵览全局",这套 ELK 集群给出了大规模日志治理的完整答案。Elasticsearch 双节点集群以分片与副本机制承担海量日志的存储与秒级检索,节点间完全对等、无主从之分;Logstash 以 Input-Filter-Output 三段管道,把系统日志与 Apache 访问、错误日志分类清洗后精准投递到对应索引;Kibana 则用索引模式与可视化界面,将枯燥的原始文本变成可直接决策的信息;elasticsearch-head 补上了集群管理最后一块拼图。整条"采集---存储---展示"链路环环相扣,一次搭建即可长期为故障排查、性能监控与安全审计提供支撑,这正是 ELK 成为企业日志分析事实标准的根本原因。