注意
此文档是适用于练习学习测试之用,不适用于生产环境
特别不适用于小白!
图
三、实施步骤
5 日志搜集阶段
参考资料:
设置Filebeat 模块与Logstash一起使用
shil:设置Filebeat模块以使用Kafka和Logstash
此示例的主要目标是演示如何从Filebeat加载摄取管道并将其与Logstash一起使用。
5.1 部署 elasticsearch 集群 + Kibana + Logstash + cerebro
二进制下载连接:
https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.0-linux-x86_64.tar.gz
https://artifacts.elastic.co/downloads/kibana/kibana-7.10.2-linux-x86_64.tar.gz
https://artifacts.elastic.co/downloads/logstash/logstash-7.11.1-linux-x86_64.tar.gz
https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.10.2-linux-x86_64.tar.gz
5.1.1 环境说明
- elasticsearch 存数据、搜索数据
- cerebro 用于查看和管理 elasticsearch 集群信息
- Kibana k
先说一下适用场景:
容器的宿主机 4 G内存
以下是已经完全启动后的内存使用情况
在之前实验的基础上去构建 Elastic 集群
5.1.2 构建 docker-compose.yml 文件
整个文件结构:
1 创建项目使用的文件夹
mkdir -p elastic/{filebeat,logstash/{config,pipeline}}
2 接着在 elastic
目录下创建 docker-compose.yml
文件,并写入如下内容:
version: '3.8'
services:
# 用于连接到集群,查看集群信息
cerebro:
image: lmenezes/cerebro:0.8.4
# 浏览器中访问宿主机的 9000 端口即可
# 访问到集群的信息
ports:
- "9000:9000"
command:
# 用于此容器访问elasticsearch 集群的节点 es01
- -Dhosts.0.host=http://es01:9200
networks:
- es7net
kibana:
image: docker.elastic.co/kibana/kibana:7.10.0
environment:
# 设置为中文环境
I18N_LOCALE: zh-CN
# 链接到 elasticsearch 集群的节点 es01
ELASTICSEARCH_URL: http://es01:9200
ELASTICSEARCH_HOSTS: http://es01:9200
ports:
- "5601:5601"
networks:
- es7net
logstash7:
image: docker.elastic.co/logstash/logstash:7.10.0
volumes:
- type: bind
# 映射的配置文件
source: ./logstash/config/logstash.yml
target: /usr/share/logstash/config/logstash.yml
read_only: true
- type: bind
# 映射的输入输出配置文件
source: ./logstash/pipeline
target: /usr/share/logstash/pipeline
read_only: true
ports:
# 映射端口到宿主机,这样的话无论 filebeat 是否使用了容器
# 都可以通过访问宿主机的 5044 端口,
# 把日志输入到 logstash
- "5044:5044"
environment:
# 设置 JVM 的堆内存,两个数据要一致
# 生产环境设置为物理内存的一半即可
LS_JAVA_OPTS: "-Xmx512m -Xms512m"
networks:
- es7net
# logstash 容器依赖于下面的几个容器
depends_on:
- es01
- es02
- es03
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0
environment:
# 集群的名称
- cluster.name=elk-cluster
# 此容器在集群中的名称,成为节点名称
- node.name=es7_01
# 锁定物理内存,禁止物理内存和虚拟内存 swap 进行交换
# 假如交换的话,会造成性能低下
- bootstrap.memory_lock=true
# 设置堆内存,生产环境需要设置为物理内存大小的一半
# 或者一半以下,并且总体大小不要超过 30 G
# 即使您限制对容器的内存访问,也必须配置堆大小。
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
# 关于集群互相发现的设置
- discovery.seed_hosts=e01,es02,es03
# 集群中参与 master 选举的节点成员
- cluster.initial_master_nodes=es7_01,es7_02,es7_03
ulimits:
memlock:
soft: -1
hard: -1
nproc: 65535
nofile: 65535
volumes:
# 此容器中的数据,存放到 Docker 数据卷中
- es7data1:/usr/share/elasticsearch/data
networks:
- es7net
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0
environment:
- cluster.name=elk-cluster
- node.name=es7_02
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=e01,es02,es03
- cluster.initial_master_nodes=es7_01,es7_02,es7_03
ulimits:
memlock:
soft: -1
hard: -1
nproc: 65535
nofile: 65535
volumes:
- es7data2:/usr/share/elasticsearch/data
networks:
- es7net
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0
environment:
- cluster.name=elk-cluster
- node.name=es7_03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=es7_01,es7_02,es7_03
- cluster.initial_master_nodes=es7_01,es7_02,es7_03
# - xpack.license.self_generated.type=trial
# - xpack.security.enabled=true
# - xpack.monitoring.collection.enabled=true
# - xpack.security.transport.ssl.enabled=true
ulimits:
memlock:
soft: -1
hard: -1
nproc: 65535
nofile: 65535
volumes:
- es7data3:/usr/share/elasticsearch/data
networks:
- es7net
volumes:
# 声明的 Docker 本地数据卷
es7data1:
driver: local
es7data2:
driver: local
es7data3:
driver: local
networks:
# 声明的网络网桥名称
es7net:
driver: bridge
# 使用之前实验中声明的网络
external:
name: vhost_xiuyun_net
3 创建 elastic/logstash/config/logstash.yml
文件并写入如下内容:
# 监听所有 IP,用于其他主机通过本机(或者此容器的 IP) 访问 logstash
http.host: "0.0.0.0"
4 创建 elastic/logstash/pipeline/logstash.conf
文件并写入如下内容:
input {
# 监听 5044 端口,用于接收 filebeat 输出的日志数据
beats {
port => 5044
}
}
# 把处理好的数据输出到指定的目标中
output {
# 把接受的信息输出到标准输出,也就是屏幕上
stdout { codec => rubydebug }
}
5 在宿主机上操作,假如你用的是单独的虚拟机,就在每台 elasticsearch 主机上操作
7 启动此项目
cd elastic
docker-compose up -d
8 验证集群有效
用浏览器访问宿主机的 9000 端口
5.2 部署 filebeat
要想搜集某个日志,需要在这个日志所在的主机上部署 filebeat。
部署的方式可以是:
- yum 安装包
- Docker 容器
- 二进制包(推荐)
需要保证版本和 Elasticsearch 版本一致
5.3 配置 Logstash 和 Filebeat
5.3.1 设置并运行Filebeat
如果您尚未设置Filebeat索引模板和示例Kibana仪表板,请运行Filebeatsetup命令以立即执行此操作:
1 设置 filebeat
[root@slb filebeat]# grep -Pv '^[ ]*#|^[ ]*$' filebeat.yml
filebeat.inputs:
- type: log
enabled: false
paths:
- /var/log/*.log
- type: filestream
enabled: false
paths:
- /var/log/*.log
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
setup.template.settings:
index.number_of_shards: 1
setup.kibana:
# 这里能连接到 kibana 的 IP 或者主机名
host: "192.168.122.127:5601"
output.elasticsearch:
# 连接到 elasticsearch 的主机名或者 IP
hosts: ["es01:9200"]
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- add_docker_metadata: ~
- add_kubernetes_metadata: ~
运行 filebeat,并使用 --dashboards
选项,以便推出 仪表盘 模板到 kibana
filebeat setup --dashboards
这将会推出如下目录下所有以 .json
结尾的模板
[root@slb filebeat]# ls kibana/7/dashboard/
成功加载模板和仪表板后,您将看到如下消息
[root@slb filebeat]# ./filebeat setup --dashboards
Loading dashboards (Kibana must be running and reachable)
Loaded dashboards
用浏览器访问 kibana
2 运行modules enable命令以启用要运行的模块。
./filebeat modules enable nginx
可以通过编辑Filebeatmodules.d目录下的配置文件来进一步配置模块。例如,如果日志文件不在模块期望的位置,则可以设置该var.paths选项。
例如:
- module: nginx
# Access logs
access:
enabled: true
var.paths: ["/var/log/nginx/access.*"]
3 运行 setup
命令并使用指定的 --pipelines
和 --modules
选项,目的时为已启用的模块加载提取管道。此步骤还需要连接到Elasticsearch。如果要使用Logstash管道而不是摄取节点来解析数据,请跳过此步骤
[root@slb filebeat]# ./filebeat -e setup --pipelines --modules nginx
应该会看到屏幕上最后有如下输出
2021-02-25T18:32:05.090+0800 INFO fileset/pipelines.go:143 Elasticsearch pipeline with ID 'filebeat-7.10.0-nginx-access-pipeline' loaded
2021-02-25T18:32:05.242+0800 INFO fileset/pipelines.go:143 Elasticsearch pipeline with ID 'filebeat-7.10.0-nginx-error-pipeline' loaded
2021-02-25T18:32:05.446+0800 INFO fileset/pipelines.go:143 Elasticsearch pipeline with ID 'filebeat-7.10.0-nginx-ingress_controller-pipeline' loaded
Loaded Ingest pipelines
- ilebeat-7.10.0-nginx-access-pipeline 处理访问日志的管道
- filebeat-7.10.0-nginx-error-pipeline 处理错误日志的管道
- filebeat-7.10.0-nginx-ingress_controller-pipeline 处理 Kubernetes nginx 的日志的管道
4 配置 Filebeat 将日志发送到 Logstash
修改 filebeat.yml 文件为如下内容:
#output.elasticsearch:
#hosts: ["localhost:9200"]
output.logstash:
# The Logstash hosts
hosts: ["192.168.122.127:5044"]
假如想单独调试 Filebeat 可以添加如下配置,把收集到的日志输出到终端
output.console:
pretty: true
只能同时配置一个 output
假如想要输出到 kafka ,需要修改位如下配置内容:
#output.elasticsearch:
#hosts: ["localhost:9200"]
output.kafka:
hosts: ["kafka:9092"]
topic: "filebeat"
codec.json:
pretty: false
选择其中任意一种即可
5 启动 Filebeat
nohup ./filebeat &
5.4.2 启动Logstash 并创建管道
1 在安装Logstash的系统上,创建一个Logstash管道配置
这里我的环境是需要修改 logstash 容器使用的配置文件
[root@docker-host elastic]# cat logstash/pipeline/logstash.conf
input {
# 监听 5044 端口,用于接收 filebeat 输出的日志数据
beats {
port => 5044
}
}
output {
if [@metadata][pipeline] {
elasticsearch {
hosts => ["es01:9200","es02:9200","es03:9200"]
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
pipeline => "%{[@metadata][pipeline]}"
}
} else {
elasticsearch {
hosts => ["es01:9200","es02:9200","es03:9200"]
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
}
之后重新 logstash
我的环境是需要重新 logstash 容器
[root@docker-host elastic]# docker-compose restart logstash7
Restarting elastic_logstash7_1 ... done
将pipeline选项设置为%{[@metadata][pipeline]}。此设置将Logstash配置为基于事件中传递的元数据选择正确的接收管道。
等待 几秒后再次查看访问 9000 端口的页面,会发现多了一个索引
5.4.3 可视化数据
要可视化Kibana中的数据,请通过将浏览器指向端口5601来启动Kibana Web界面。例如,http://127.0.0.1: 5601 。单击仪表板,然后查看Filebeat仪表板。
需要调整为正确的时间才会有数据展示出来
假如不使用 Filebeat 的摄取管道,而只使用 Logstash 的管道
如果要使用Logstash管道而不是摄取节点来解析数据,请参阅下面的使用Logstash管道进行解析的示例中的filter和output设置 。
处理 Nginx 日志
本示例中的Logstash管道配置显示了如何运送和解析nginxFilebeat模块收集的访问和错误日志 。
input {
beats {
port => 5044
host => "0.0.0.0"
}
}
filter {
if [fileset][module] == "nginx" {
if [fileset][name] == "access" {
grok {
match => { "message" => ["%{IPORHOST:[nginx][access][remote_ip]} - %{DATA:[nginx][access][user_name]} \[%{HTTPDATE:[nginx][access][time]}\] \"%{WORD:[nginx][access][method]} %{DATA:[nginx][access][url]} HTTP/%{NUMBER:[nginx][access][http_version]}\" %{NUMBER:[nginx][access][response_code]} %{NUMBER:[nginx][access][body_sent][bytes]} \"%{DATA:[nginx][access][referrer]}\" \"%{DATA:[nginx][access][agent]}\""] }
remove_field => "message"
}
mutate {
add_field => { "read_timestamp" => "%{@timestamp}" }
}
date {
match => [ "[nginx][access][time]", "dd/MMM/YYYY:H:m:s Z" ]
remove_field => "[nginx][access][time]"
}
useragent {
source => "[nginx][access][agent]"
target => "[nginx][access][user_agent]"
remove_field => "[nginx][access][agent]"
}
geoip {
source => "[nginx][access][remote_ip]"
target => "[nginx][access][geoip]"
}
}
else if [fileset][name] == "error" {
grok {
match => { "message" => ["%{DATA:[nginx][error][time]} \[%{DATA:[nginx][error][level]}\] %{NUMBER:[nginx][error][pid]}#%{NUMBER:[nginx][error][tid]}: (\*%{NUMBER:[nginx][error][connection_id]} )?%{GREEDYDATA:[nginx][error][message]}"] }
remove_field => "message"
}
mutate {
rename => { "@timestamp" => "read_timestamp" }
}
date {
match => [ "[nginx][error][time]", "YYYY/MM/dd H:m:s" ]
remove_field => "[nginx][error][time]"
}
}
}
}
output {
elasticsearch {
hosts => localhost
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
处理 mysql 日志
此示例中的Logstash管道配置显示了如何传送和解析mysqlFilebeat模块收集的错误日志和慢日志 。
input {
beats {
port => 5044
host => "0.0.0.0"
}
}
filter {
if [fileset][module] == "mysql" {
if [fileset][name] == "error" {
grok {
match => { "message" => ["%{LOCALDATETIME:[mysql][error][timestamp]} (\[%{DATA:[mysql][error][level]}\] )?%{GREEDYDATA:[mysql][error][message]}",
"%{TIMESTAMP_ISO8601:[mysql][error][timestamp]} %{NUMBER:[mysql][error][thread_id]} \[%{DATA:[mysql][error][level]}\] %{GREEDYDATA:[mysql][error][message1]}",
"%{GREEDYDATA:[mysql][error][message2]}"] }
pattern_definitions => {
"LOCALDATETIME" => "[0-9]+ %{TIME}"
}
remove_field => "message"
}
mutate {
rename => { "[mysql][error][message1]" => "[mysql][error][message]" }
}
mutate {
rename => { "[mysql][error][message2]" => "[mysql][error][message]" }
}
date {
match => [ "[mysql][error][timestamp]", "ISO8601", "YYMMdd H:m:s" ]
remove_field => "[mysql][error][time]"
}
}
else if [fileset][name] == "slowlog" {
grok {
match => { "message" => ["^# User@Host: %{USER:[mysql][slowlog][user]}(\[[^\]]+\])? @ %{HOSTNAME:[mysql][slowlog][host]} \[(IP:[mysql][slowlog][ip])?\](\s*Id:\s* %{NUMBER:[mysql][slowlog][id]})?\n# Query_time: %{NUMBER:[mysql][slowlog][query_time][sec]}\s* Lock_time: %{NUMBER:[mysql][slowlog][lock_time][sec]}\s* Rows_sent: %{NUMBER:[mysql][slowlog][rows_sent]}\s* Rows_examined: %{NUMBER:[mysql][slowlog][rows_examined]}\n(SET timestamp=%{NUMBER:[mysql][slowlog][timestamp]};\n)?%{GREEDYMULTILINE:[mysql][slowlog][query]}"] }
pattern_definitions => {
"GREEDYMULTILINE" => "(.|\n)*"
}
remove_field => "message"
}
date {
match => [ "[mysql][slowlog][timestamp]", "UNIX" ]
}
mutate {
gsub => ["[mysql][slowlog][query]", "\n# Time: [0-9]+ [0-9][0-9]:[0-9][0-9]:[0-9][0-9](\\.[0-9]+)?$", ""]
}
}
}
}
output {
elasticsearch {
hosts => localhost
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
处理系统日志
本示例中的Logstash管道配置显示了如何运送和解析systemFilebeat模块收集的系统日志 。
input {
beats {
port => 5044
host => "0.0.0.0"
}
}
filter {
if [fileset][module] == "system" {
if [fileset][name] == "auth" {
grok {
match => { "message" => ["%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: %{DATA:[system][auth][ssh][event]} %{DATA:[system][auth][ssh][method]} for (invalid user )?%{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]} port %{NUMBER:[system][auth][ssh][port]} ssh2(: %{GREEDYDATA:[system][auth][ssh][signature]})?",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: %{DATA:[system][auth][ssh][event]} user %{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]}",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: Did not receive identification string from %{IPORHOST:[system][auth][ssh][dropped_ip]}",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sudo(?:\[%{POSINT:[system][auth][pid]}\])?: \s*%{DATA:[system][auth][user]} :( %{DATA:[system][auth][sudo][error]} ;)? TTY=%{DATA:[system][auth][sudo][tty]} ; PWD=%{DATA:[system][auth][sudo][pwd]} ; USER=%{DATA:[system][auth][sudo][user]} ; COMMAND=%{GREEDYDATA:[system][auth][sudo][command]}",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} groupadd(?:\[%{POSINT:[system][auth][pid]}\])?: new group: name=%{DATA:system.auth.groupadd.name}, GID=%{NUMBER:system.auth.groupadd.gid}",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} useradd(?:\[%{POSINT:[system][auth][pid]}\])?: new user: name=%{DATA:[system][auth][useradd][name]}, UID=%{NUMBER:[system][auth][useradd][uid]}, GID=%{NUMBER:[system][auth][useradd][gid]}, home=%{DATA:[system][auth][useradd][home]}, shell=%{DATA:[system][auth][useradd][shell]}$",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} %{DATA:[system][auth][program]}(?:\[%{POSINT:[system][auth][pid]}\])?: %{GREEDYMULTILINE:[system][auth][message]}"] }
pattern_definitions => {
"GREEDYMULTILINE"=> "(.|\n)*"
}
remove_field => "message"
}
date {
match => [ "[system][auth][timestamp]", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]
}
geoip {
source => "[system][auth][ssh][ip]"
target => "[system][auth][ssh][geoip]"
}
}
else if [fileset][name] == "syslog" {
grok {
match => { "message" => ["%{SYSLOGTIMESTAMP:[system][syslog][timestamp]} %{SYSLOGHOST:[system][syslog][hostname]} %{DATA:[system][syslog][program]}(?:\[%{POSINT:[system][syslog][pid]}\])?: %{GREEDYMULTILINE:[system][syslog][message]}"] }
pattern_definitions => { "GREEDYMULTILINE" => "(.|\n)*" }
remove_field => "message"
}
date {
match => [ "[system][syslog][timestamp]", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]
}
}
}
}
output {
elasticsearch {
hosts => localhost
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
2 启动Logstash,传入您刚定义的管道配置文件。例如:
bin/logstash -f mypipeline.conf
Logstash应该启动管道并开始从Kafka输入接收事件。