docker搭建ELKB

1,802 阅读5分钟

docker搭建ELKB

本文使用docker-compose搭建一套单机的elkb日志系统

大致架构如下:

image.png

搭建的组件包括

  • 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

image.png

es配置

在/d/dockerworkspace/elkb/es/目录下创建以下目录

image.png

并在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插件用正则表达式的方式过滤数据,同时还预留了能满足大多数用户的规则。

github.com/elastic/log…

image.png

在使用时用%{}包裹起来即可。

但是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产生的日志

image.png

15:21:44.881 [http-nio-9082-exec-1] INFO  com.weishuang.social.log.StreamLog - [traceId] - 创建文章

我们把它放到grokdebugge中,并使用logstash官方预留的表达式进行组合

image.png

可以看到,我们的日志可以被下面语句捕获到

%{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的不同索引。