docker搭建ELKB
本文使用docker-compose搭建一套单机的elkb日志系统
大致架构如下:
搭建的组件包括
- elasticsearch
- kibana
- logstash
- filebeat
- zookeeper
- kafka
- kafka-ui(可选)
- grokdebugger(可选)
在搭建前简单介绍一下这些组件
elasticsearch
日志的存储介质
kibana
对 Elasticsearch 数据进行可视化
logstash
Logstash 能够动态地采集、转换和传输数据,不受格式或复杂度的影响。利用 Grok 从非结构化数据中派生出结构,从 IP 地址解码出地理坐标,匿名化或排除敏感字段,并简化整体处理过程。Logstash支持多种输入、输出和插件,具有高度的灵活性和可扩展性。
filebeat
轻量级日志采集器,可以安装在各个节点上,根据配置读取对应位置的日志,并上报到其他组件进行存储和分析,提高系统的实时性和效率。
kafka
接收来自不同数据源的数据,并将其分发到多个消费者。
使用Kafka可以提高ELKB系统的稳定性和可靠性,避免因为突发高峰导致处理延迟过高等问题。
kafka-ui
是一个免费的开源 Web UI,用于监控和管理 Apache Kafka 集群。
拉取镜像
本文使用es-7.14.0
docker pull elastic/elasticsearch:7.14.0
docker pull elastic/logstash:7.14.0
docker pull elastic/kibana:7.14.0
docker pull elastic/filebeat:7.14.0
docker pull bitnami/zookeeper
docker pull bitnami/kafka
#可选
docker pull provectuslabs/kafka-ui
创建挂载目录
由于我的宿主机是windows系统,在文件挂载时都挂载到了D盘,大家是linux的话只需要换一下路径就行了。
在/d/dockerworkspace/elkb/目录下创建以下目录
- es
- kibana
- logstash
- filebeat
es配置
在/d/dockerworkspace/elkb/es/目录下创建以下目录
并在config目录下创建elasticsearch.yml
cluster.name: elastic-nodes
node.name: node01
#设置绑定ip 0.0.0.0 任何机器都可以访问节点
network.host: 0.0.0.0
http.port: 9200
#是否开启master角色选举
#node.master: true#
#是否开启数据节点角色
#node.data: true
#以下两项是外部访问http需要开启的项启用跨域资源共享
http.cors.enabled: true
http.cors.allow-origin: "*"
#单节点启动
discovery.type: single-node
kibana配置
/d/dockerworkspace/elkb/kibana/目录下,创建kibana.yml
server.name: kibana
server.host: "0"
# 需要连接的地址
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
xpack.monitoring.ui.container.elasticsearch.enabled: true
i18n.locale: "zh-CN"
filebeat配置
/d/dockerworkspace/elkb/filebeat/目录下,创建filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /logs/*.log #日志目录,注意一会挂载的时候要把要收集的日志文件挂载到这里
output.kafka:
enabled: true
hosts: ["kafka:9092"]
topic: "weishuang-log-dev"
partition.round_robin:
reachable_only: true
required_acks: 1
logstash配置
/d/dockerworkspace/elkb/logstash/目录下,创建config目录
在config目录中创建conf.d目录和logstash.yml文件
path.config: /usr/share/logstash/conf.d/*.conf
http.host: "0.0.0.0"
之后我们配置logstash的规则,就写在conf.d目录下
docker-compose.yaml
version: '3.7'
networks:
elkb-net:
services:
elasticsearch:
container_name: elasticsearch
image: elastic/elasticsearch:7.14.0
environment:
- ES_JAVA_OPTS=-Xms512m -Xmx512m
volumes:
- /d/dockerworkspace/elkb/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- /d/dockerworkspace/elkb/es/data:/usr/share/elasticsearch/data
- /d/dockerworkspace/elkb/es/logs:/usr/share/elasticsearch/logs elastic/elasticsearch:7.14.0
ports:
- 9200:9200
- 9300:9300
networks:
- elkb-net
kibana:
container_name: kibana
image: elastic/kibana:7.14.0
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- 5601:5601
volumes:
- /d/dockerworkspace/elkb/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml
depends_on:
- elasticsearch
networks:
- elkb-net
zookeeper:
container_name: zookeeper
image: bitnami/zookeeper
environment:
- ALLOW_ANONYMOUS_LOGIN=yes # 允许未经身份验证的用户连接到 ZooKeeper
- ZOO_ENABLE_AUTH=false # 关闭 ZooKeeper 的身份认证机制
ports:
- 2181:2181
networks:
- elkb-net
kafka:
container_name: kafka
image: bitnami/kafka
ports:
- "9093:9093"
environment:
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
ALLOW_PLAINTEXT_LISTENER: yes
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CLIENT:PLAINTEXT,EXTERNAL:PLAINTEXT
KAFKA_CFG_LISTENERS: CLIENT://:9092,EXTERNAL://:9093
KAFKA_CFG_ADVERTISED_LISTENERS: CLIENT://kafka:9092,EXTERNAL://localhost:9093
KAFKA_CFG_INTER_BROKER_LISTENER_NAME: CLIENT
depends_on:
- zookeeper
networks:
- elkb-net
kafka-ui:
container_name: kafka-ui
image: provectuslabs/kafka-ui:latest
ports:
- "18080:8080"
environment:
KAFKA_CLUSTERS_0_NAME: "kafka"
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: "kafka:9092"
depends_on:
- kafka
networks:
- elkb-net
logstash:
container_name: logstash
image: elastic/logstash:7.14.0
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
volumes:
- /d/dockerworkspace/elkb/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
- /d/dockerworkspace/elkb/logstash/config/conf.d:/usr/share/logstash/config/conf.d
ports:
- "5044:5044"
- "9600:9600"
depends_on:
- elasticsearch
- kafka
networks:
- elkb-net
filebeat:
container_name: filebeat
image: elastic/filebeat:7.14.0
command: [ "--strict.perms=false" ]
volumes:
- /d/dockerworkspace/elkb/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml
- /d/workspace/weishuang/log:/logs #日志目录
depends_on:
- elasticsearch
- kafka
networks:
- elkb-net
注意:kafka对宿主机暴露的端口我写的是9093,用于kafka对宿主机提供服务。如果大家有其他的需求,可以参照dockerhub上的教程配置hub.docker.com/r/bitnami/k…
执行docker-compose
docker-compose -p elkb up -d
至此,elkb系统就搭建完了。
我在下面提供一下我自己的logstash的配置,供大家参考
logstash相关
logstash中提供了Grok插件用正则表达式的方式过滤数据,同时还预留了能满足大多数用户的规则。
在使用时用%{}包裹起来即可。
但是grok表达式的调试比较麻烦,我们可以使用Grok Debugger (51vagaa.com)来进行grok表达式的调试。也可以搭建grokdebugge容器来进行调试
搭建grokdebugge(可选)
docker pull qiudev/grokdebugger
docker run -d --name grokdebugger -p 19999:9999 qiudev/grokdebugger
进行grok调试
下面是我的spring服务中logback产生的日志
15:21:44.881 [http-nio-9082-exec-1] INFO com.weishuang.social.log.StreamLog - [traceId] - 创建文章
我们把它放到grokdebugge中,并使用logstash官方预留的表达式进行组合
可以看到,我们的日志可以被下面语句捕获到
%{TIME:time} [%{NOTSPACE:thread}] %{LOGLEVEL:loglevel} %{JAVACLASS:clazz} - [%{GREEDYDATA:trace_id}] - %{GREEDYDATA:log_info}
收集日志配置
/d/dockerworkspace/elkb/logstash/config/conf.d/info.conf
input {
kafka {
bootstrap_servers => 'kafka:9092'
group_id => 'elk-dev'
client_id => 'elk-dev'
# 正则匹配topic
topics_pattern => "weishuang-log-dev"
codec => "json"
#默认为false,只有为true的时候才会获取到元数据
decorate_events => true
}
}
filter {
grok {
match => {
"message" => "%{TIME:time} [%{NOTSPACE:app_name}] [%{NOTSPACE:thread}] %{LOGLEVEL:loglevel} %{JAVACLASS:clazz} - [%{GREEDYDATA:trace_id}] - %{GREEDYDATA:log_info}"
}
}
if [log_info] =~ "^STREAM_EVENT.*" {
mutate {
add_tag => [ "stream" ]
}
}
mutate {
add_field => { "index" => "info"}
}
if [loglevel] {
mutate {
lowercase => [ "loglevel" ]
update => { "index" => "%{loglevel}" }
}
}
}
output {
elasticsearch {
hosts => ["http://es:9200"]
#使用上面的index用作ES的索引
index => "logstash-dev-%{index}-%{+YYYY.MM.dd}"
}
if "stream" in [tags] {
kafka {
bootstrap_servers => "http://kafka:9092"
topic_id => "stream-dev"
}
}
}
从kafka中读取消息,通过grok进行过滤,如果日志内容匹配正则表达式^STREAM_EVENT.*就为该条日志添加标签stream。在输出时,如果日志有stream标签,就输出到kafka,供其他消费者进一步消费。
因为es的索引名只能为小写,我们想要把error日志和info日志分开收集,同时在过滤时把loglevel置为小写。把不同等级的日志输出到es的不同索引。