Go-Zero项目开发42: 基于Docker构建ELK日志收集架构
2026/7/30 14:38:19 网站建设 项目流程

纲要

  • 微服务日志收集的挑战
  • ELK技术栈概述
    • Elasticsearch:搜索引擎与数据存储
    • Logstash:日志采集与处理
    • Kibana:数据可视化
  • ELK 工作流程
  • 基于Docker构建 ELK 架构
    • 环境准备与目录结构
    • 启动ElasticsearchKibana
    • 配置与启动Logstash
      • 核心配置文件结构:inputfilteroutput
      • 单一日志采集示例:MySQL慢查询日志
      • 多日志源采集示例:结合Redis访问日志
      • 使用grok语法进行日志解析
    • 验证日志流转
  • 常见问题与调试技巧
  • 总结

微服务日志收集的挑战

在微服务架构中,系统被拆分为多个独立的服务,例如用户服务、订单服务,同时还可能包含MySQLRedis等基础组件。每个服务在运行过程中都会产生自己的日志文件。

当我们需要排查问题或进行性能优化时,就必须收集并分析这些分散的日志。由于日志散落在不同的服务节点上,且彼此之间缺乏关联,如何高效、统一地收集与分析日志就成为了一个核心挑战。

ELK技术栈正是为了解决这一难题而生的。它提供了一整套从采集、存储到可视化的解决方案,帮助开发人员快速构建日志分析平台。

ELK 技术栈概述

ELK是三个开源软件的首字母缩写:

  • Elasticsearch:一个基于 Lucene 的分布式搜索和分析引擎,用于集中存储和索引日志数据。
  • Logstash:一个服务端数据处理管道,能够从多个来源采集数据、转换数据,并将数据发送到指定目标。
  • Kibana:一个可视化平台,负责将Elasticsearch中的数据通过仪表盘、图表等形式展现出来。

核心工作流程

下图展示了ELK的基本工作流程:

可视化

存储与分析

采集层

日志源

日志文件

日志文件

慢查询日志

访问日志

推送结构化数据

查询与读取

开发人员

微服务A

微服务B

MySQL

Redis

Logstash
数据采集与过滤

Elasticsearch
索引与存储

Kibana
仪表盘展示

分析问题与监控

  1. Logstash从各个服务的日志文件或系统指标中采集数据,这一过程通常由配置文件定义,也可使用轻量级的Filebeat作为日志采集代理。
  2. 采集到的日志经过Logstashfilter插件进行解析、清洗和格式化。
  3. 处理后的数据被推送到Elasticsearch集群中进行存储和索引。
  4. Kibana连接到Elasticsearch,提供可视化界面和仪表盘,开发人员可以实时监控系统状态和分析日志。

基于 Docker 构建 ELK 架构

在实际开发中,我们通常会借助Docker来快速搭建和部署ELK环境,从而保证各组件之间的一致性,并简化配置管理。

环境准备与目录结构

首先在项目目录中创建必要的文件夹和配置文件。推荐的目录结构如下:

elk-stack/ ├── docker-compose.yml ├── elasticsearch/ │ └── data/ # 挂载数据目录,需要提前设置权限 ├── logstash/ │ ├── config/ │ │ └── logstash.conf # Logstash 核心配置 │ └── logs/ # 放置示例日志文件,如 mysql-slow.log └── kibana/

由于Elasticsearch容器在启动时需要写入数据目录,必须确保宿主机上的挂载目录有足够的权限。可以通过以下命令设置:

chmod-R777./elasticsearch/data

启动 Elasticsearch 与 Kibana

ElasticsearchKibana通常可以先行部署,因为二者可以脱离Logstash独立运行并相互配合。
下面是一个简单的docker-compose.yml配置示例:

version:'3.8'services:elasticsearch:image:elasticsearch:7.17.10container_name:elasticsearchenvironment:-discovery.type=single-node-"ES_JAVA_OPTS=-Xms512m -Xmx512m"ports:-"9200:9200"volumes:-./elasticsearch/data:/usr/share/elasticsearch/datanetworks:-elkkibana:image:kibana:7.17.10container_name:kibanaports:-"5601:5601"environment:-ELASTICSEARCH_HOSTS=http://elasticsearch:9200depends_on:-elasticsearchnetworks:-elknetworks:elk:driver:bridge

在项目根目录执行docker-compose up -d即可启动。启动过程中Elasticsearch需要一定时间来初始化,可以通过访问http://<服务器IP>:9200验证其状态。

当返回JSON格式的节点信息时表示启动成功。Kibana则通过http://<服务器IP>:5601访问。

配置与启动 Logstash

Logstash的核心在于其配置文件,它定义了数据从哪来(input)、如何加工(filter)以及送往哪里(output)。典型的logstash.conf结构如下:

input { # 定义数据源 } filter { # 定义数据处理逻辑 } output { # 定义数据输出目标 }
单一日志采集:MySQL 慢查询日志

首先准备一份MySQL慢查询日志(mysql-slow.log),日志内容示例:

# Time: 2026-07-09T10:00:00.000000Z # User@Host: root[root] @ localhost [] # Query_time: 12.345678 Lock_time: 0.000123 Rows_sent: 1 Rows_examined: 100000 SET timestamp=1752487200; SELECT * FROM orders WHERE user_id = 123 AND status = 'pending';

为了解析这种多行格式的日志,我们需要在Logstash配置中同时指定文件输入、多行处理规则以及使用grok语法进行字段提取。完整配置如下(路径按实际挂载调整):

input { file { path => "/usr/share/logstash/logs/mysql-slow.log" type => "mysql-slow" start_position => "beginning" # 多行合并规则:以 "# Time:" 开头的行作为一条日志的开始 codec => multiline { pattern => "^# Time:" negate => true what => "previous" } } } filter { if [type] == "mysql-slow" { # 使用 grok 解析慢查询日志 grok { match => { "message" => "^# Time: %{TIMESTAMP_ISO8601:timestamp}\s+# User@Host: %{USER:user}\[%{USER:host}\] @ %{HOSTNAME:client_host} \[\]\s+# Query_time: %{NUMBER:query_time:float}\s+Lock_time: %{NUMBER:lock_time:float}\s+Rows_sent: %{NUMBER:rows_sent:int}\s+Rows_examined: %{NUMBER:rows_examined:int}\s+SET timestamp=%{NUMBER:set_timestamp:int};\s+%{GREEDYDATA:sql_query}" } } # 将 query_time 转换为毫秒方便分析 mutate { convert => { "query_time" => "float" } } # 删除原始 message 字段(可选) remove_field => ["message", "set_timestamp"] } } output { if [type] == "mysql-slow" { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "mysql-slow-%{+YYYY.MM.dd}" } # 同时输出到控制台用于调试 stdout { codec => rubydebug } } }

配置说明:

  • inputfile插件读取指定路径的日志文件,start_position => "beginning"表示首次从头读取,之后会记录偏移量以支持断点续传;multilinecodec 将以# Time:开头的行作为新日志的起始,之前的内容合并到上一条日志。
  • filtergrok插件使用预定义和自定义正则表达式将非结构化日志解析为字段,如query_timesql_query等。mutate用于类型转换和字段裁剪。grok语法可借助 Grok Debugger 在线调试。
  • output:将解析后的数据按天索引写入Elasticsearch,同时输出到控制台方便观察。
多日志源采集:结合 Redis 访问日志

在实际项目中,Logstash往往需要同时采集多种类型的日志。通过在配置中为不同来源打上type标签,再结合if条件判断,可以很容易地实现多源处理。

假设我们新增Redis的访问日志(redis-access.log),内容示例:

2026-07-09 10:05:03.123 1.2.3.4 SET mykey myvalue 2026-07-09 10:05:04.567 5.6.7.8 GET mykey

更新后的logstash.conf可扩展为:

input { file { path => "/usr/share/logstash/logs/mysql-slow.log" type => "mysql-slow" start_position => "beginning" codec => multiline { pattern => "^# Time:" negate => true what => "previous" } } file { path => "/usr/share/logstash/logs/redis-access.log" type => "redis-access" start_position => "beginning" } } filter { if [type] == "mysql-slow" { grok { ... } # 同上 } if [type] == "redis-access" { grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{IP:client_ip} %{WORD:command} %{GREEDYDATA:args}" } } date { match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"] target => "@timestamp" } } } output { if [type] == "mysql-slow" { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "mysql-slow-%{+YYYY.MM.dd}" } } if [type] == "redis-access" { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "redis-access-%{+YYYY.MM.dd}" } } stdout { codec => rubydebug } }

通过为每个input指定不同的type,在filteroutput阶段用if [type] == "..."分支处理,就可以灵活地扩展多种日志的采集流程,而不会相互干扰。

启动 Logstash

在将logstash.conf写好并放入./logstash/config/后,需要将其添加到docker-compose.yml中:

logstash:image:logstash:7.17.10container_name:logstashvolumes:-./logstash/config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro-./logstash/logs:/usr/share/logstash/logsdepends_on:-elasticsearchnetworks:-elkcommand:logstash-f /usr/share/logstash/pipeline/logstash.conf

注意:Logstash启动较慢,因为它是基于JRuby的 JVM 程序,需要等待初始化完成。可以通过docker logs -f logstash观察启动日志。当控制台输出开始解析日志记录时,即表示运行正常。

验证日志流转

  1. 访问Kibana控制台(http://<服务器IP>:5601)。
  2. 进入Management → Stack Management → Index Patterns,创建索引模式,例如mysql-slow-*redis-access-*
  3. Discover页面即可看到解析好的日志数据,字段如query_timesql_queryclient_ip等都可被用来过滤和聚合。
  4. 之后可以创建仪表盘,对慢查询次数、耗时分布等进行可视化监控。

常见问题与调试技巧

  • 权限问题Elasticsearch容器无法写入挂载的数据目录。解决:使用chmod 777或更改目录属主为1000:1000Elasticsearch容器内运行用户 uid 通常为 1000)。
  • Logstash启动缓慢:JVM 启动需要时间,可以通过调整 JVM 堆大小(如LS_JAVA_OPTS=-Xmx512m -Xms512m)来加速。
  • 配置不生效:检查配置文件的缩进和引号,确保path指向容器内部的正确路径(而非宿主机路径)。可在logstash.conf中加入stdout { codec => rubydebug }来本地调试。
  • grok匹配失败:利用 Grok Debugger 在线测试,逐步调整模式。
  • 多行合并错误multilinecodec 的pattern必须能匹配日志的第一行,negatewhat的组合要符合预期。

总结

通过Docker我们可以快速构建起一套功能完善的ELK日志收集系统。Logstash灵活的input-filter-output管道设计,使其能够轻松应对多种日志格式的采集与处理需求。

在实际项目中,只需根据业务需要扩展配置即可实现大规模日志的集中管理和可视化,为微服务系统的运维和优化提供强有力的数据支持。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询