ELK日志环境搭建
环境规划
192.168.3.61 logstash、filebeat 、kibana 、es
192.168.3.62 es
192.168.3.63 es
配置主机名
hostnamectl set-hostname ela1.com
hostnamectl set-hostname ela2.com
hostnamectl set-hostname ela3.com
配置hosts文件解析
cat >> /etc/hosts << EOF
192.168.3.61 ela1 ela1.com
192.168.3.62 ela2 ela2.com
192.168.3.63 ela3 ela3.com
EOF
修改三台主机免密ssh登录
ssh-keygen -f ~/.ssh/id_rsa -P '' -q
ssh-copy-id 192.168.3.61
ssh-copy-id 192.168.3.62
ssh-copy-id 192.168.3.63
安装filebeat
tar -xf filebeat-7.13.2-linux-x86_64.tar.gz
mv filebeat-7.13.2-linux-x86_64 /usr/local/
mv /usr/local/filebeat-7.13.2-linux-x86_64/ /usr/local/filebeat
mkdir /usr/local/filebeat/logs -p
filebeat启动
cat >> /usr/local/filebeat/start.sh << EOF
nohup /usr/local/filebeat/filebeat -e -c /usr/local/filebeat/filebeat.yml > /usr/local/filebeat/logs/filebeat.log 2>&1 &
EOF
chmod +x /usr/local/filebeat/start.sh
/usr/local/filebeat/start.sh
-e 的作用是让 Filebeat 把日志打到 stderr,然后配合 > logs/filebeat.log 2>&1 将这些日志统一重定向到 logs/filebeat.log 文件中。
等价于 --stderr,强制 Filebeat 把日志输出到 stderr
Filebeat简单使用
准备测试数据
cat >> /tmp/access.log << EOF
123.127.39.50 - - [04/Mar/2026:10:50:28 +0800] "GET /logo.jpg HTTP/1.1" 200 14137 "http://81.68.233.173/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36" "-"
EOF
配置Filebeat 的输入和输出
vim /usr/local/filebeat/filebeat.yml
yaml
filebeat.inputs:
- type: log
enabled: true # 改
paths:
- /tmp/*.log # 改
# 设置 filebeat 输出的位置为终端 ,filebeat 的输出位置只能有一个,其他 output 位置需要注释
# ---------------------------- Elasticsearch Output ----------------------------
# output.elasticsearch: # 注释这行
# hosts: ["localhost:9200"] # 注释这行
output.console: # 添加 输出到终端即屏幕上
pretty: true
# 以下配置无需修改了 默认即可
processors:
- add_host_metadata: # 主机的源数据信息到输出数据中,比如 IP MAC OS 等信息
when.not.contains.tags: forwarded
# ============================== Filebeat modules ==============================
# 模块相关配置 内置了些模块,配置模块后就可以采集相关的日志
filebeat.config.modules: # 内置的收集日志的模块配置文件的存放路径
path: ${path.config}/modules.d/*.yml
reload.enabled: false # 当模块的配置文件有更新时,此程序是否要自动加载,false不加载,true 加载
setup.template.settings:
index.number_of_shards: 1
启动测试
默认日志位置在logs下
shell
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml
{
"@timestamp": "2026-07-11T11:52:25.970Z",
"@metadata": {
"beat": "filebeat",
"type": "_doc",
"version": "7.13.2"
},
"ecs": {
"version": "1.8.0"
},
"host": {
"containerized": false,
"ip": [
"192.168.3.61",
"fe80::ec9:9d78:e02b:d35d",
"fe80::ed28:4363:215e:a0c1"
],
"mac": [
"00:0c:29:58:70:56"
],
"hostname": "ela1.com",
"architecture": "x86_64",
"os": {
"name": "CentOS Linux",
"kernel": "3.10.0-957.el7.x86_64",
"codename": "Core",
"type": "linux",
"platform": "centos",
"version": "7 (Core)",
"family": "redhat"
},
"name": "ela1.com",
"id": "89b07113c20b441e8d5a8dcadb27e658"
},
"agent": {
"type": "filebeat",
"version": "7.13.2",
"hostname": "ela1.com",
"ephemeral_id": "275e2495-ec11-4703-aabf-e3f4ee93bf2d",
"id": "504e778c-506f-4d96-9aae-b30c252cce1f",
"name": "ela1.com"
},
"log": {
"offset": 0,
"file": {
"path": "/tmp/access.log"
}
},
"message": "124.127.39.50 - - [04/Mar/2021:10:50:28 +0800] \"GET /logo.jpg HTTP/1.1\" 200 14137 \"http://81.68.233.173/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36\" \"-\"",
"input": {
"type": "log"
}
}
停止
ps -ef | grep filebeat.yml | grep -v grep | awk '{print $2}' | xargs kill -9
filebeat重读日志
有时候处于实验目的,可能需要重新读取日志文件,这个时候需要删除安装目录下的 data 文件夹,重新运行 filebeat 即可。
[root@ela1 filebeat]# ls
data filebeat filebeat.yml kibana logs modules.d README.md
fields.yml filebeat.reference.yml filebeat.yml.yuanshi LICENSE.txt module NOTICE.txt
# 删除 data 即可重读日志
rm -rf data
安装Logstash
tar -xf logstash-7.13.2-linux-x86_64.tar.gz -C /usr/local/
mv /usr/local/logstash-7.13.2/ /usr/local/logstash
执行启动命令
/usr/local/logstash/bin/logstash -e ''
-e 选项用于设置 Logstash 处理数据的输入和输出
-e '' 等同于 -e input { stdin { type => stdin } } output { stdout { codec => rubydebug } }
input { stdin { type => stdin } }
表示 Logstash 需要处理的数据来源来自于标准输入设备
output { stdout { codec => rubydebug } }
表示 Logstash 把处理好的数据输出到标准输出设备
执行 bin/logstash -e '' 命令后 在终端中输入abcd 后有以下输出即说明安装无误
abcd
{
"host" => "ela1.com",
"message" => "abcd",
"@version" => "1",
"@timestamp" => 2026-07-11T12:30:12.994Z,
"type" => "stdin"
}
配置输入和输出
生产中,Logstash管道要复杂一些:它通常具有一个或多个输入,过滤器和输出插件。
本部分中,将创建一个Logstash管道,该管道使用标准输入来获取Apache Web日志作为输入,解析这些日志以从日志中创建特定的命名字段,然后将解析的数据输出到标准输出(屏幕上)。并且这次无需在命令行上定义管道配置,而是在配置文件中定义管道。
创建任意一个文件,并写入如下内容,作为 Logstash 的管道配置文件
vim /usr/local/logstash/config/first-pipeline.conf
input {
stdin { }
}
output {
stdout {}
}
配置文件语法测试
/usr/local/logstash/bin/logstash -f config/first-pipeline.conf --config.test_and_exit
运行如下命令启动 Logstash
/usr/local/logstash/bin/logstash -f config/first-pipeline.conf
启动后复制如下内容到命令行中,并按下回车键
83.149.9.216 - - [04/Jan/2025:05:13:42 +0000] "GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1" 200 203023 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
将会看到如下输出
{
"@version" => "1",
"message" => "83.149.9.216 - - [04/Jan/2015:05:13:42 +0000] \"GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1\" 200 203023 \"http://semicomplete.com/presentations/logstash-monitorama-2013/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
"@timestamp" => 2026-05-02T11:37:23.956Z,
"host" => "ela1"
}
使用Grok过滤器插件解析Web日志
现在有了一个工作管道,但是日志消息的格式不是理想的。你想解析日志消息,以便能从日志中创建特定的命名字段。为此,应该使用grok过滤器插件。
使用grok过滤器插件,可以将非结构化日志数据解析为结构化和可查询的内容。
grok 会根据你感兴趣的内容分配字段名称,并把这些内容和对应的字段名称进行绑定。
grok 如何知道哪些内容是你感兴趣的呢?它是通过自己预定义的模式来识别感兴趣的字段的。这个可以通过给其配置不同的模式来实现。
这里使用的模式是 %{COMBINEDAPACHELOG}
{COMBINEDAPACHELOG 使用以下模式从Apache日志中构造行:
| 原信息 | 对应新的字段名称 |
|---|---|
| IP 地址 | clientip |
| 用户 ID | ident |
| 用户认证信息 | auth |
| 时间戳 | timestamp |
| HTTP 请求方法 | verb |
| 请求的 URL | request |
| HTTP 版本 | httpversion |
| 响应码 | response |
| 响应体大小 | bytes |
| 跳转来源 | referrer |
| 客户端代理(浏览器) | agent |
这里要想实现修改配置文件之后自动加载它,不能配置 input 为 stdin。所以, 这里使用了 file ,创建示例日志文件
vim /var/log/httpd.log
83.149.9.216 - - [04/Jan/2026:05:13:42 +0000] "GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1" 200 203023 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
修改好的管道配置文件如下:
vim /usr/local/logstash/config/first-pipeline.conf
input {
file {
path => ["/var/log/httpd.log"]
start_position => "beginning"
}
}
filter {
grok { # 对 web 日志进行过滤处理,输出结构化的数据
# 在 message 字段对应的值中查询匹配上 COMBINEDAPACHELOG
match => { "message" => "%{COMBINEDAPACHELOG}" } }
}
output {
stdout {}
}
match => { "message" => "%{COMBINEDAPACHELOG}"} 的意思是:
当匹配到 "message" 字段时,用户模式 "COMBINEDAPACHELOG}" 进行字段映射。
配置完成后,再次进行验证
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf
下面是输出内容
{
"path" => "/var/log/httpd.log",
"clientip" => "83.149.9.216",
"timestamp" => "04/Jan/2015:05:13:42 +0000",
"response" => "200",
"verb" => "GET",
"bytes" => "203023",
"agent" => "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
"@version" => "1",
"message" => "83.149.9.216 - - [04/Jan/2015:05:13:42 +0000] \"GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1\" 200 203023 \"http://semicomplete.com/presentations/logstash-monitorama-2013/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
"host" => "ela1",
"auth" => "-",
"request" => "/presentations/logstash-monitorama-2013/imageskibana-search.png",
"referrer" => "\"http://semicomplete.com/presentations/logstash-monitorama-2013/\"",
"httpversion" => "1.1",
"@timestamp" => 2026-05-02T11:39:44.349Z,
"ident" => "-"
}
你会发现原来的非结构化数据,变为结构化的数据了。
细心的你一定发现原来的 message 字段仍然存在,假如你不需要它,可以使用 grok 中提供的常用选项之一: remove_filed 来移除这个字段。
remove_field 可以移除任意的字段,它可以接收的值是一个数组。
rename可以重新命名字段
修改后管道配置文件如下:
vim /usr/local/logstash/config/first-pipeline.conf
input {
file {
path => ["/var/log/httpd.log"]
start_position => "beginning"
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" } }
mutate {
#重写字段
rename => {
"clientip" => "cip"
}
}
mutate {
#去掉没用字段
remove_field => ["message","input_type","@version","fields"]
}
}
output {
stdout {}
}
增加新日志
vim /var/log/httpd.log
# 新加入一行日志
再次测试,你会发现 message 不见了,而且clientip重命名成了cip:
/usr/local/logstash/bin/logstash -f config/first-pipeline.conf
{
"ident" => "-",
"referrer" => "\"http://semicomplete.com/presentations/logstash-monitorama-2013/\"",
"verb" => "GET",
"auth" => "-",
"timestamp" => "04/Jan/2015:05:13:42 +0000",
"response" => "200",
"agent" => "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
"host" => "logstash",
"cip" => "83.149.9.216",
"httpversion" => "1.1",
"@timestamp" => 2021-06-23T15:46:09.624Z,
"request" => "/presentations/logstash-monitorama-2013/imageskibana-search.png",
"bytes" => "203023",
"path" => "/var/log/httpd.log"
}
filebeat和logstash联动
filebeat采集日志输出到logstash
vim /usr/local/logstash/config/first-pipeline.conf
# 监听 5044 端口,接收 filebeat 的输入
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG }" }
}
}
output {
stdout {}
}
运行logstash
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf
运行 logstash 之后修改 filebeat 的 yml 文件输出目标如下
注意 : output只能有一个配置,只能输出到一个地方
vim /usr/local/filebeat/filebeat.yml
# output.console: # 注释原来输出到终端的配置
# pretty: true
filebeat.inputs:
- type: log
enabled: true
paths:
- /tmp/*.log
# 改为输出到logstash
output.logstash:
# The Logstash hosts
hosts: ["192.168.3.61:5044"]
运行filebeat
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml
logstash接收到的filebeat的消息如下:
{
"@version" => "1",
"message" => "ABG",
"log" => {
"offset" => 4,
"file" => {
"path" => "/tmp/access.log"
}
},
"agent" => {
"id" => "e1fd3d9a-bf15-4cd7-9afa-faa9e4037cb4",
"hostname" => "localhost",
"ephemeral_id" => "b5b0c305-c123-4d66-899b-05abcdaf131f",
"type" => "filebeat",
"name" => "localhost",
"version" => "7.13.2"
},
"ecs" => {},
"host" => {
"id" => "70b835b3e58a4ec294e3f2ca23d3fbc1",
"hostname" => "localhost",
"os" => {
"codename" => "Core",
"platform" => "centos",
"kernel" => "3.10.0-693.el7.x86_64",
"name" => "CentOS Linux",
"version" => "7 (Core)",
"type" => "linux",
"family" => "redhat"
},
"containerized" => false,
"name" => "localhost",
"ip" => [
[0] "192.168.232.138",
[1] "fe80::d166:4c0b:187c:9b3a",
[2] "fe80::fa61:ef46:73d7:d050"
],
"mac" => [
[0] "00:0c:29:4a:13:ae"
],
"architecture" => "x86_64"
},
"project" => {
"id" => "574734885120952459",
"name" => "myproject"
},
"@timestamp" => 2021-07-07T01:43:24.041Z,
"tags" => [
[0] "beats_input_codec_plain_applied",
[1] "_grokparsefailure"
]
}
安装ElasticSearch集群
修改内核参数
# 添加以内核参数设置
cat >> /etc/sysctl.conf << EOF
fs.file-max=655360
vm.max_map_count = 262144
EOF
#执行命令使内核参数生效
sysctl -p
cat >> /etc/security/limits.conf << EOF
* soft nproc 20480
* hard nproc 20480
* soft nofile 65536
* hard nofile 65536
* soft memlock unlimited
* hard memlock unlimited
EOF
解压安装包
tar -xf elasticsearch-7.13.2-linux-x86_64.tar.gz -C /usr/local/
mv /usr/local/elasticsearch-7.13.2 /usr/local/elasticsearch
在每个节点创建用户 ela
useradd ela
echo "123456" | passwd --stdin ela
在每个节点上对 ela 用户授权
chown -R ela:ela /usr/local/elasticsearch
ela1 节点 设置的内容如下:
vim /usr/local/elasticsearch/config/elasticsearch.yml
yaml
# 文件末尾加入
cluster.name: elk
node.name: ela1
node.data: true
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: #官方指定写法如下,3台机器一样
- 192.168.3.61 #节点1
- 192.168.3.62 #节点2
- 192.168.3.63 #节点3
cluster.initial_master_nodes: ["192.168.3.61", "192.168.3.62", "192.168.3.63"]
ela2 节点设置的内容如下:
vim /usr/local/elasticsearch/config/elasticsearch.yml
yaml
# 文件末尾加入
cluster.name: elk
node.name: ela2
node.data: true
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: #官方指定写法如下,3台机器一样
- 192.168.3.61 #节点1
- 192.168.3.62 #节点2
- 192.168.3.63 #节点3
cluster.initial_master_nodes: ["192.168.3.61", "192.168.3.62", "192.168.3.63"]
ela3 节点设置的内容如下:
vim /usr/local/elasticsearch/config/elasticsearch.yml
yaml
# 文件末尾加入
cluster.name: elk
node.name: ela3
node.data: true
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: #官方指定写法如下,3台机器一样
- 192.168.3.61 #节点1
- 192.168.3.62 #节点2
- 192.168.3.63 #节点3
cluster.initial_master_nodes: ["192.168.3.61", "192.168.3.62", "192.168.3.63"]
参数说明
- cluster.name 集群名称,各节点配成相同的集群名称。
- node.name 节点名称,各节点配置不同。
- node.data 指示节点是否为数据节点。数据节点包含并管理索引的一部分。
- network.host 绑定节点IP。
- http.port 监听端口。
- path.data 数据存储目录。
- path.logs 日志存储目录。
- discovery.seed_hosts 指定集群成员,用于主动发现他们,所有成员都要写进来,包括自己,每个节点中应该写一样的信息。
- cluster.initial_master_nodes 指定有资格成为 master 的节点
- http.cors.enabled 用于允许head插件访问ES。
- http.cors.allow-origin 允许的源地址。
注意:
- 当您为提供自定义设置时 network.host,Elasticsearch会假设您正在从开发模式过渡到生产模式,并将许多系统启动检查从警告升级到异常。
- cluster.initial_master_nodes 中的节点名称需要和 node.name 的名称一致。
启动集群
切换到普通用户 ela , 启动elasticsearch
su - ela
/usr/local/elasticsearch/bin/elasticsearch -d -p /tmp/elasticsearch.pid
启动脚本
vi start.sh
shell
#!/bin/bash
# Elasticsearch 启动脚本(以用户 ela 运行)
# ========== 配置区 ==========
ES_USER="ela" # 运行 ES 的系统用户
ES_HOME="/usr/local/elasticsearch" # ES 安装目录
PID_FILE="/tmp/elasticsearch.pid" # PID 文件路径
# ============================
# 检查 PID 文件是否存在且进程仍在运行
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
echo "Elasticsearch 已在运行,PID: $pid"
exit 1
else
echo "发现过期的 PID 文件,正在移除..."
rm "$PID_FILE"
fi
fi
# 切换到 ES 用户并启动(su - 会加载用户环境,-c 执行命令)
su - "$ES_USER" -c "$ES_HOME/bin/elasticsearch -d -p $PID_FILE"
# 等待 2 秒,检查 PID 文件是否生成,确认启动成功
sleep 2
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
echo "Elasticsearch 启动成功,PID: $pid"
else
echo "启动失败,请检查日志(位于 $ES_HOME/logs/)"
exit 1
fi
shell
chmod +x start.sh
./start.sh
默认端口号是 :
9200用于外部访问的监听端口,比如查看集群状态,向其传输数据,查询数据等9300用户集群中节点之间的互相通信,比如主节点的选举,集群节点信息的通告等。
注意:如果集群配置错误,想重新初始化集群,只需要删除数据目录,重启服务即可
日志消息可以在 $ES_HOME/logs/ 目录中找到
常用es命令
查看集群健康状态
[ela@ela3 logs]$ curl -X GET "192.168.3.61:9200/_cat/health?v"
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1783868461 15:01:01 elk green 3 3 0 0 0 0 0 0 - 100.0%
三种不同状态的含义
- 黄色 如果您仅运行单个Elasticsearch实例,则集群状态将保持黄色。单节点群集具有完整的功能,但是无法将数据复制到另一个节点以提供弹性。
- 绿色 副本分片必须可用,群集状态为绿色。
- 红色 如果群集状态为红色,则某些数据不可用。
查看集群节点信息
curl -X GET "http://192.168.3.61:9200/_cat/nodes?v"
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.3.62 35 97 0 0.00 0.03 0.03 cdhilmrstw - ela2
192.168.3.61 27 96 0 0.01 0.06 0.06 cdhilmrstw * ela1
192.168.3.63 27 62 0 0.00 0.05 0.05 cdhilmrstw - ela3
检查集群状态
curl -XGET 'http://localhost:9200/_cluster/health/?pretty'
{
"cluster_name" : "elk",
"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
}
查看ES中所有的索引
curl -X GET http://192.168.3.61:9200/_cat/indices?v

- health: 索引的健康状态,Elasticsearch 索引的健康状态有三种:green(绿色,健康),yellow(黄色,部分健康),red(红色,不健康)。"yellow" 状态表示索引的某些分片处于未分配状态,但主分片是可用的。
- status: 索引的状态,这里是 "open"。这表示索引处于打开状态,可以进行读取和写入操作。
- index: 索引的名称,这里是 "nginx-access-log-2023.09.13"。
- uuid: 索引的唯一标识符。
- pri: 主分片(primary shard)的数量,这里是 1 个主分片。
- rep: 副本分片(replica shard)的数量,这里也是 1 个副本分片。
- docs.count: 索引中文档的总数,这里是 20。
- docs.deleted: 索引中已删除的文档数量,这里是 0。
- store.size: 索引的存储大小,这里是 34.1KB。
- pri.store.size: 主分片的存储大小,这里也是 34.1KB。
新建索引
curl -X PUT http://192.168.3.61:9200/testyf
删除索引
curl -X DELETE http://192.168.3.61:9200/testyf
查看指定索引信息
curl -X GET http://192.168.3.61:9200/testyf?pretty
查看别名
curl -X GET http://192.168.3.61:9200/_cat/aliases
es集群测试
使用 Filebeat 搜集 Nginx 的日志,输出到 Logstash, 再由 Logstash 处理完数据后输出到 Elasticsearch。
启动es集群
su - ela
cd /usr/local/elasticsearch
./bin/elasticsearch -d
查看集群状态 为 green
curl -XGET 'http://192.168.3.61:9200/_cluster/health/?pretty'
配置logstash
vi /usr/local/logstash/config/first-pipeline.conf
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
remove_field => [ "message" ]
}
geoip {
source => "clientip"
}
}
output {
stdout {
codec => rubydebug
}
elasticsearch { #原来基础上添加此配置
# 这里是输出到 elasticsearch 集群中
hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
}
}
启动 Logstash
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf
启动 Filebeat
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml
查看 Logstash 的终端 , 应有相应的输出
......
"@timestamp" => 2026-07-13T13:33:59.538Z,
"input" => {
"type" => "log"
},
"verb" => "GET",
"auth" => "-",
"log" => {
"offset" => 234,
"file" => {
"path" => "/tmp/access.log"
}
....
验证Elasticsearch是否创建了索引
[root@ela2 ~]# curl -X GET "192.168.3.61:9200/_cat/indices"
green open logstash-2026.07.13-000001 T9eheSsfSFyUwVT_Ctns_A 1 1 2 0 65.4kb 32.7kb
可以看到索引以创建,但索引是 Elasticsearch 是自动创建的,不过这往往不是生产中想要的。
通常把访问日志 access.log 中的内容单独放到一个索引中
编辑配置文件
vim /usr/local/logstash/config/first-pipeline.conf
yaml
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
remove_field => [ "message" ]
}
geoip {
source => "clientip"
}
}
output {
stdout {
codec => rubydebug
}
if [log][file][path] == "/tmp/access.log" {
elasticsearch {
hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
index => "%{[host][hostname]}-nginx-access-%{+YYYY.MM.dd}"
}
} else if [log][file][path] == "/var/log/nginx/error.log" {
elasticsearch {
hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
index => "%{[host][hostname]}-nginx-error-%{+YYYY.MM.dd}"
}
}
}
重启logstash
ps -ef | grep logstash | grep -v grep | awk '{print $2}' | xargs kill -9
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf
想access.log中新写入一行
vi /tmp/access.log
124.127.39.57 - - [04/Mar/2026:10:50:28 +0800] "GET /logo.jpg HTTP/1.1" 200 14137 "http://81.68.233.173/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36" "-"
验证 Elasticsearch 集群中的索引
[root@ela3 ~]# curl -X GET "192.168.3.61:9200/_cat/indices"
green open logstash-2026.07.13-000001 T9eheSsfSFyUwVT_Ctns_A 1 1 2 0 65.6kb 32.8kb
green open ela1.com-nginx-access-2026.07.13 ILGlwQ3tRXS-51bavKALvw 1 1 1 0 65.2kb 32.5kb
logstash-2026.07.13-000001 是原来自动创建的
ela1.com-nginx-access-2026.07.13 是新建立的,手动定义的索引
安装kibana
注意: kibana版本必须和es版本完全一致,否则kibana无法启动
tar -xf kibana-7.13.2-linux-x86_64.tar.gz -C /usr/local/
mv /usr/local/kibana-7.13.2-linux-x86_64 /usr/local/kibana
配置主配置文件
vim /usr/local/kibana/config/kibana.yml
server.port: 5601 #改
server.host: "0.0.0.0" #改
# 用于连接到 ES 集群的地址和端口
elasticsearch.hosts: ["http://192.168.3.61:9200"] #改
# 日志文件路径
# logging.dest: stdout
logging.dest: /var/log/kibana/kibana.log #改
# 设置页面的字体为中文
i18n.locale: "zh-CN" #改
创建用于运行 kibana 的普通用户
默认情况下,kibana 不允许使用 root 用户运行,所以这里创建一个普通用户
useradd kib
echo "123456" | passwd --stdin kib
创建程序使用到的目录并赋予权限
mkdir /var/log/kibana/ -p
mkdir /run/kibana -p
chown kib:kib /run/kibana /var/log/kibana/ /usr/local/kibana -R
运行于前台
su - kib
/usr/local/kibana/bin/kibana
运行于后台
su - kib
nohup /usr/local/kibana/bin/kibana &
使用浏览器访问 http://192.168.3.61:5601
登录kibana创建索引






kafaka集群
kafka简介
数据缓冲队列。同时提高了可扩展性。具有峰值处理能力,使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
Kafka是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。
1.话题(Topic):是特定类型的消息流。(每条发布到 kafka 集群的消息属于的类别,即 kafka 是面向 topic 的。)
2.生产者(Producer):是能够发布消息到话题的任何对象(发布消息到 kafka 集群的终端或服务).
3.消费者(Consumer):可以订阅一个或多个话题,从而消费这些已发布的消息。
4.服务代理(Broker):已发布的消息保存在一组服务器中,它们被称为代理(Broker)或Kafka集群。
5.partition(区):每个 topic 包含一个或多个 partition。
6.replication:partition 的副本,保障 partition 的高可用。
7.leader:replica 中的一个角色, producer 和 consumer 只跟 leader 交互。
8.follower:replica 中的一个角色,从 leader 中复制数据。
9.zookeeper:kafka 通过 zookeeper 来存储集群的信息。

Zookeeper简介
ZooKeeper是一个分布式协调服务,它的主要作用是为分布式系统提供一致性服务,提供的功能包括:配置维护、分布式同步等。Kafka的运行依赖ZooKeeper。也是java微服务里面使用的一个注册中心服务
ZooKeeper主要用来协调Kafka的各个broker,不仅可以实现broker的负载均衡,而且当增加了broker或者某个broker故障了,ZooKeeper将会通知生产者和消费者,这样可以保证整个系统正常运转。
在Kafka中,一个topic会被分成多个区并被分到多个broker上,分区的信息以及broker的分布情况与消费者当前消费的状态信息都会保存在ZooKeeper中。
部署zk
zk需要依赖jdk,安装jdk
rpm -ivh jdk-8u131-linux-x64.rpm
Kafka运行依赖ZK,Kafka官网提供的tar包中,已经包含了ZK,这里不再额外下载ZK程序。
解压至目录
shell
tar xzf kafka_2.12-2.8.0.tgz -C /usr/local/
mv /usr/local/kafka_2.12-2.8.0/ /usr/local/kafka/
分别配置三台kafka中的zookeeper
第一台节点
注释所有配置
shell
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/zookeeper.properties
文件后添加如下配置
shell
vi /usr/local/kafka/config/zookeeper.properties
shell
dataDir=/opt/data/zookeeper/data # 需要创建,所有节点一致
dataLogDir=/opt/data/zookeeper/logs # 需要创建,所有节点一致
clientPort=2181
tickTime=2000
initLimit=20
syncLimit=10
# 以下 IP 信息根据自己服务器的 IP 进行修改 kafka集群IP:Port
server.1=192.168.3.61:2888:3888
server.2=192.168.3.62:2888:3888
server.3=192.168.3.63:2888:3888
创建 data、log 目录
shell
mkdir -p /opt/data/zookeeper/{data,logs}
创建myid文件 ,myid号按顺序排
shell
echo 1 > /opt/data/zookeeper/data/myid
第二台节点
注释所有配置
shell
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/zookeeper.properties
文件后添加如下配置
shell
vi /usr/local/kafka/config/zookeeper.properties
shell
dataDir=/opt/data/zookeeper/data # 需要创建,所有节点一致
dataLogDir=/opt/data/zookeeper/logs # 需要创建,所有节点一致
clientPort=2181
tickTime=2000
initLimit=20
syncLimit=10
# 以下 IP 信息根据自己服务器的 IP 进行修改 kafka集群IP:Port
server.1=192.168.3.61:2888:3888
server.2=192.168.3.62:2888:3888
server.3=192.168.3.63:2888:3888
创建 data、log 目录
shell
mkdir -p /opt/data/zookeeper/{data,logs}
创建myid文件 ,myid号按顺序排
shell
echo 2 > /opt/data/zookeeper/data/myid
第三台节点
注释所有配置
shell
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/zookeeper.properties
文件后添加如下配置
shell
vi /usr/local/kafka/config/zookeeper.properties
shell
# 需要创建,所有节点一致
dataDir=/opt/data/zookeeper/data
dataLogDir=/opt/data/zookeeper/logs
clientPort=2181
tickTime=2000
initLimit=20
syncLimit=10
# 以下 IP 信息根据自己服务器的 IP 进行修改 kafka集群IP:Port
server.1=192.168.3.61:2888:3888
server.2=192.168.3.62:2888:3888
server.3=192.168.3.63:2888:3888
创建 data、log 目录
shell
mkdir -p /opt/data/zookeeper/{data,logs}
创建myid文件 ,myid号按顺序排
shell
echo 3 > /opt/data/zookeeper/data/myid
配置项含义:
dataDir ZK数据存放目录。
dataLogDir ZK日志存放目录。
clientPort 客户端连接ZK服务的端口。
tickTime ZK服务器之间或客户端与服务器之间维持心跳的时间间隔。
initLimit 允许follower连接并同步到Leader的初始化连接时间,当初始化连接时间超过该值,则表示连接失败。
syncLimit Leader与Follower之间发送消息时如果follower在设置时间内不能与leader通信,那么此follower将会被丢弃。
server.1=192.168.3.61:2888:3888 2888是follower与leader交换信息的端口,3888是当leader挂了时用来执行选举时服务器相互通信的端口。
启动zk
cd /usr/local/kafka
nohup bin/zookeeper-server-start.sh config/zookeeper.properties &
查看端口
netstat -lntp | grep 2181
tcp6 0 0 :::2181 :::* LISTEN 1226/java
部署Kafka
第一台节点
注释所有配置
shell
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/server.properties
文件后添加如下配置
shell
vim /usr/local/kafka/config/server.properties
shell
# 注意对应id
broker.id=1
# 注意对应ip
listeners=PLAINTEXT://192.168.3.61:9092
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/opt/data/kafka/logs
num.partitions=6
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=2
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.retention.hours=168
log.segment.bytes=536870912
log.retention.check.interval.ms=300000
zookeeper.connect=192.168.3.61:2181,192.168.3.62:2181,192.168.3.63:2181
zookeeper.connection.timeout.ms=6000
group.initial.rebalance.delay.ms=0
创建目录
shell
mkdir -p /opt/data/kafka/logs
配置项含义:
broker.id
每一个broker在集群中的唯一标识,要求是正数。在改变IP地址,不改变broker.id的时不会影响consumers
listeners=PLAINTEXT://192.168.3.61:9092
监听地址
num.network.threads
broker 处理消息的最大线程数,一般情况下不需要去修改
num.io.threads
broker处理磁盘IO 的线程数 ,数值应该大于你的硬盘数
socket.send.buffer.bytes
socket的发送缓冲区
socket.receive.buffer.bytes
socket的接收缓冲区
socket.request.max.bytes
socket请求的最大数值,防止serverOOM,message.max.bytes必然要小于socket.request.max.bytes,会被topic创建时的指定参数覆盖
log.dirs 日志文件目录
num.partitions
num.recovery.threads.per.data.dir 每个数据目录(数据目录即指的是上述log.dirs配置的目录路径)用于日志恢复启动和关闭时的线程数量。
offsets.topic.replication.factor
transaction state log replication factor 事务主题的复制因子(设置更高以确保可用性)。 内部主题创建将失败,直到群集大小满足此复制因素要求
log.cleanup.policy = delete
日志清理策略 选择有:delete和compact 主要针对过期数据的处理,或是日志文件达到限制的额度,会被 topic创建时的指定参数覆盖
log.cleanup.interval.mins=1
指定日志每隔多久检查看是否可以被删除,默认1分钟
log.retention.hours
数据存储的最大时间 超过这个时间 会根据log.cleanup.policy设置的策略处理数据,也就是消费端能够多久去消费数据。log.retention.bytes和log.retention.minutes或者log.retention.hours任意一个达到要求,都会执行删除,会被topic创建时的指定参数覆盖
log.segment.bytes
topic的分区是以一堆segment文件存储的,这个控制每个segment的大小,会被topic创建时的指定参数覆盖
log.retention.check.interval.ms
文件大小检查的周期时间,是否触发 log.cleanup.policy中设置的策略
zookeeper.connect
ZK主机地址,如果zookeeper是集群则以逗号隔开。
zookeeper.connection.timeout.ms
连接到Zookeeper的超时时间。
第二台节点
shell
scp 192.168.3.61:/usr/local/kafka/config/server.properties 192.168.3.62:/usr/local/kafka/config/server.properties
mkdir -p /opt/data/kafka/logs
# 修改对应id 和 ip
vim /usr/local/kafka/config/server.properties
broker.id=2 # 注意对应id
listeners=PLAINTEXT://192.168.3.62:9092 # 注意对应ip
第三台节点
bash
scp 192.168.3.61:/usr/local/kafka/config/server.properties 192.168.3.63:/usr/local/kafka/config/server.properties
mkdir -p /opt/data/kafka/logs
# 修改对应id 和 ip
vim /usr/local/kafka/config/server.properties
broker.id=3 # 注意对应id
listeners=PLAINTEXT://192.168.3.63:9092 # 注意对应ip
启动Kafka
shell
cd /usr/local/kafka
nohup bin/kafka-server-start.sh config/server.properties &
验证kafka
在192.168.3.61上创建topic
/usr/local/kafka/bin/kafka-topics.sh --create --zookeeper 192.168.3.61:2181 --replication-factor 1 --partitions 1 --topic testtopic
# Created topic testtopic.
参数解释:
--zookeeper指定zookeeper的地址和端口
--partitions指定partition的数量
--replication-factor指定数据副本的数量
在192.168.3.62上面查询192.168.3.61上的topic
/usr/local/kafka/bin/kafka-topics.sh --zookeeper 192.168.3.61:2181 --list
# testtopic
模拟消息生产和消费
发送消息到192.168.19.20
/usr/local/kafka/bin/kafka-console-producer.sh --broker-list 192.168.3.61:9092 --topic testtopic
>hello
>你好呀
从192.168.3.61接受消息
/usr/local/kafka/bin/kafka-console-consumer.sh --bootstrap-server 192.168.3.61:9092 --topic testtopic --from-beginning
hello
你好呀
logstash服务器从kafka获取数据并输出到es集群
shell
vim /usr/local/logstash/config/first-pipeline.conf
shell
input {
kafka {
type => "apache_log"
codec => "json"
topics => ["apache"]
decorate_events => true
bootstrap_servers => "192.168.3.61:9092, 192.168.3.62:9092, 192.168.3.63:9092"
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
remove_field => [ "message" ]
}
}
output {
stdout {}
if [type] == "apache_log" { #和上面的type一致
elasticsearch {
index => "apache-%{+YYYY.MM.dd}"
codec => "json"
hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
}
}
}
decorate_events => true 默认是 false 这将向logstash 事件添加一个名为kafka的字段 ,这包含以下属性。
-
topic 主题:与此消息相关联的主题
-
consumer_group 使用者群组:此事件中用来读取的使用者群组
-
partition 分区:与此消息关联的分区
-
offset 偏移量:与此消息关联的分区的偏移量
-
key:包含message key的ByteBuffer
重启动 logstash
kill -9 进程id
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf --config.reload.automatic
配置 Filebeat 输出到 kafka
shell
vim /usr/local/filebeat/filebeat.yml
shell
# 注释其他 output filebeat只能有一个output位置
# output.console:
# pretty: true
# output.logstash:
# The Logstash hosts
# hosts: ["192.168.3.61:5044"]
# 配置输入端
filebeat.inputs:
- type: log
enabled: true
paths:
- /tmp/*.log
# 加入以下配置,设置输出目标为kafka集群
output.kafka:
hosts: ["192.168.3.61:9092", "192.168.3.62:9092", "192.168.3.63:9092"]
topic: 'apache'
partition.round_robin:
reachable_only: false
required_acks: 1
compression: gzip
max_message_bytes: 1000000
重新启动filebeat
kill -9 进程id
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml
获取apache topic
[root@ela3 kafka]# /usr/local/kafka/bin/kafka-console-consumer.sh --bootstrap-server 192.168.3.61:9092 --topic apache --from-beginning
{"@timestamp":"2026-07-19T01:50:42.128Z","@metadata":{"beat":"filebeat","type":"_doc","version":"7.13.2"},"log":{"offset":1872,"file":{"path":"/tmp/access.log"}},"message":"124.127.39.61 - - [04/Mar/2021:10:50:28 +0800] \"GET /logo.jpg HTTP/1.1\" 200 14137 \"http://81.68.233.173/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36\" \"-\"","input":{"type":"log"},"ecs":{"version":"1.8.0"},"host":
es获取索引
[root@ela3 kafka]# curl -X GET "192.168.3.61:9200/_cat/indices"
green open .apm-custom-link 1mqc4K6WRKmcLh8GddR37Q 1 1 0 0 416b 208b
green open logstash-2026.07.13-000001 T9eheSsfSFyUwVT_Ctns_A 1 1 2 0 65.6kb 32.8kb
green open .kibana_task_manager_1 0svl5hNdQzWU80BA3zqP2A 1 1 5 40 323.6kb 162.3kb
green open .apm-agent-configuration JG_SJgheQxOptCCPXbE5zA 1 1 0 0 416b 208b
green open .kibana-event-log-7.10.0-000001 IQtSHKjqRH6tkacvzGr8hQ 1 1 3 0 32.8kb 16.4kb
green open ela1.com-nginx-access-2026.07.13 ILGlwQ3tRXS-51bavKALvw 1 1 2 0 130.1kb 65kb
green open ela1.com-nginx-access-2026.07.18 HtOKF29STsyaeZaCAqUuPQ 1 1 1 0 65.3kb 32.6kb
green open .kibana_1 VjbUWUD1SS6-nCFJlZUW-Q 1 1 34 11 20.8mb 10.4mb
green open apache-2026.07.19 LYYrhiddQ26xsAGZC38rMQ 1 1 1 0 51.8kb 25.8kb
kibana 中创建索引后适用discover查看如下

OK完结