ELK日志系统从零搭建到实战:Nginx日志采集与可视化全攻略

引言

在微服务和分布式架构盛行的今天,应用的日志不再集中在一台服务器上,而是散落在各个容器、主机中。排查问题时,若仍使用 tail -f 逐台登录查看日志,效率极低且容易遗漏关键信息。ELK(Elasticsearch、Logstash、Kibana)是业界最为成熟的开源日志解决方案,能够方便地完成日志的采集、传输、存储、搜索和可视化。本文将带你从零开始,用 Docker Compose 快速搭建一套 ELK 系统,并实战采集 Nginx 访问日志,在 Kibana 中生成实时可视化看板。所有代码均可直接复制运行,让你在十分钟内拥有自己的日志中心。

核心概念与架构

实际的日志流水线通常由四部分组成:

  • Filebeat(轻量级采集器):部署在产生日志的服务器上,监控日志文件并将日志推送到 Logstash 或直接到 Elasticsearch。它资源消耗极小,适合做日志的"搬运工"。
  • Logstash(数据处理管道):负责接收、过滤、转换日志。可以用 Grok 解析非结构化日志,还可以丰富字段(如添加地理位置信息)。
  • Elasticsearch(存储与搜索引擎):存储索引后的日志数据,提供近乎实时的搜索和分析能力。
  • Kibana(可视化界面):通过图表、仪表盘展示 Elasticsearch 中的数据,支持交互式搜索。

一个典型的架构如下:

复制代码
Nginx(容器) → Filebeat → Logstash → Elasticsearch → Kibana

本文示例中,所有组件都运行在 Docker 中,方便快速搭建和复现。

实战:搭建 ELK + Filebeat 采集 Nginx 日志

1. 环境准备

确保你的机器已安装 Docker 和 Docker Compose(版本 ≥ 1.29)。建议给 Docker 分配至少 4GB 内存,因为 Elasticsearch 比较占内存。

创建项目目录:

bash 复制代码
mkdir elk-stack && cd elk-stack

2. 编写 Docker Compose 编排文件

docker-compose.yml 中定义 Elasticsearch、Logstash、Kibana、Nginx 和 Filebeat 服务。我们采用桥接网络 elk-net 让容器间互通。

yaml 复制代码
version: '3.7'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.12
    container_name: elasticsearch
    environment:
      - discovery.type=single-node        # 单节点模式
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # 限制堆内存
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    networks:
      - elk-net

  logstash:
    image: docker.elastic.co/logstash/logstash:7.17.12
    container_name: logstash
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline   # 自定义管道配置
    ports:
      - "5044:5044"   # 接收 Filebeat 输入
    depends_on:
      - elasticsearch
    networks:
      - elk-net

  kibana:
    image: docker.elastic.co/kibana/kibana:7.17.12
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - elk-net

  nginx:
    image: nginx:1.21
    container_name: nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro   # 自定义 Nginx 日志格式
      - nginx_logs:/var/log/nginx
    ports:
      - "8080:80"
    networks:
      - elk-net

  filebeat:
    image: docker.elastic.co/beats/filebeat:7.17.12
    container_name: filebeat
    user: root                   # 需要 root 读取 Nginx 日志
    volumes:
      - ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
      - nginx_logs:/var/log/nginx:ro   # 挂载同一个日志卷
    command: filebeat -e -strict.perms=false
    depends_on:
      - logstash
      - nginx
    networks:
      - elk-net

volumes:
  esdata:
  nginx_logs:

networks:
  elk-net:
    driver: bridge

3. 配置各组件

Nginx 日志格式

为了让日志包含更丰富的字段(如请求时间、状态码、响应时间等),我们自定义 JSON 格式的日志。创建 nginx/nginx.conf

nginx 复制代码
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format json_combined escape=json '{'
        '"time_local":"$time_iso8601",'
        '"remote_addr":"$remote_addr",'
        '"remote_user":"$remote_user",'
        '"request":"$request",'
        '"status": "$status",'
        '"body_bytes_sent":"$body_bytes_sent",'
        '"request_time":"$request_time",'
        '"http_referrer":"$http_referer",'
        '"http_user_agent":"$http_user_agent"'
    '}';

    access_log  /var/log/nginx/access.log json_combined;

    sendfile        on;
    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

重启 Nginx 后,访问日志将是 JSON 格式,非常便于 Logstash 解析。

Logstash 管道

创建 logstash/pipeline/nginx.conf

复制代码
input {
  beats {
    port => 5044
  }
}

filter {
  # 如果日志是 JSON 格式(Nginx 访问日志),直接解析
  if [log][file][path] =~ "access" {
    json {
      source => "message"
      target => "nginx"          # 解析后的字段放入 nginx 对象
    }
    # 将常用字段提升到顶级
    mutate {
      copy => {
        "[nginx][remote_addr]" => "client_ip"
        "[nginx][status]"       => "status_code"
        "[nginx][request_time]" => "response_time"
        "[nginx][request]"      => "request_url"
      }
      convert => {
        "status_code"   => "integer"
        "response_time" => "float"
      }
    }
    # 移除原始 message 和 nginx 大对象(可选)
    # mutate { remove_field => ["message", "nginx"] }
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "nginx-%{+YYYY.MM.dd}"
    user => "elastic"
    password => "changeme"        # 如有安全设置需配置,这里暂不启用
    manage_template => false
  }
  # stdout { codec => rubydebug }   # 调试时可开启
}

此配置将 Filebeat 传来的日志按 JSON 解析,提取出 Nginx 的关键字段,最终存入以日期分片的索引中。

Filebeat 配置

创建 filebeat/filebeat.yml

yaml 复制代码
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
  # 多行合并(如果需要)
  # multiline.pattern: '^\{'
  # multiline.negate: true
  # multiline.match: after

output.logstash:
  hosts: ["logstash:5044"]

Filebeat 监控 Nginx 日志文件,并发送给 Logstash。

4. 启动服务

在项目根目录下执行:

bash 复制代码
docker-compose up -d

首次启动会拉取镜像,稍等片刻。待所有容器状态为 Up 后,用浏览器访问 http://localhost:8080 多次,产生一些 Nginx 日志。

5. 在 Kibana 中查看与分析

  1. 打开浏览器访问 http://localhost:5601
  2. 进入 Management → Stack Management → Index Patterns ,创建索引模式。
    • Index pattern name 填写 nginx-*
    • 选择时间字段 @timestamp(由 Filebeat 自动添加)。
  3. 创建成功后,进入 Discover 页面,选择 nginx-* 索引,即可看到 Nginx 日志数据。可以使用 KQL 查询,例如:status_code:404 查找 404 请求。
  4. 制作可视化看板:
    • 点击 Create new 选择 LensVisualization
    • 以柱状图展示每分钟请求量:x 轴为 @timestamp,y 轴为 Count
    • status_code 作为分桶维度,统计各状态码分布。
    • 保存图表并添加到 Dashboard,最终生成实时监控仪表盘。

这样,一个基础但完整的日志中心便搭建完成。

常见问题与注意事项

  1. Elasticsearch 内存不足导致启动失败

    现象:elasticsearch 容器反复退出。解决方案:增加 Docker 可用内存,或调整 ES_JAVA_OPTS-Xms-Xmx 参数,但最小不低于 512m。生产环境建议分配 2G 以上。

  2. Filebeat 无权读取日志文件

    日志卷权限默认为 root,需要使用 user: root 运行 Filebeat 容器并为配置文件设置 -strict.perms=false。生产环境建议用 chmod 或组授权更安全的方式处理。

  3. Logstash 管道语法错误

    如果 Logstash 启动后自动退出,可能是配置文件有误。可以通过 docker logs logstash 查看错误信息。调试时可开启 stdout { codec => rubydebug } 输出,将日志打印在控制台,确认数据流转正常。

  4. 索引模式未匹配到数据

    检查时间字段选择,确认日志中确实有 @timestamp 且是有效的日期类型。若使用自定义解析,确保 date 过滤器正确转换了时间字段。

  5. 磁盘空间增长过快

    Elasticsearch 索引默认每天创建一个,长期运行会占用大量磁盘。建议设置 ILM(索引生命周期管理)策略,定期删除或归档老旧索引。

  6. 安全性

    本文示例未开启安全认证,仅适合演示环境。生产环境中务必启用 X-Pack 认证、加密、用户角色等安全功能。

总结

本文详细介绍了如何使用 Docker Compose 快速部署一套 ELK + Filebeat 日志收集系统,并实战采集 Nginx 的 JSON 格式日志,在 Kibana 中实现了搜索和可视化。通过这套组合,无论是开发环境排错,还是生产环境监控,都能大幅提升日志处理效率。

从本文你可以学到:

  • ELK 各个组件的作用和数据流向

  • Docker 化部署 ELK 的 YAML 编排技巧

  • Nginx 日志格式定制与 Filebeat、Logstash 的配置联动

  • Kibana 索引模式与可视化图表的基本操作

希望这篇实战指南能帮助你在项目中轻松落地日志中心。下一步你可以尝试加入 Grafana、告警规则,或扩展到 Kubernetes 日志采集,打造企业级可观测性平台。

相关推荐
小蓝波4 小时前
docker 的命令
java·docker·容器
利威尔·5 小时前
常用git命令
大数据·elasticsearch·搜索引擎
考虑考虑5 小时前
nginx配置ssl
运维·后端·nginx
2301_801184756 小时前
docker 工作
java·docker·容器
想你依然心痛9 小时前
AtomCode 在 DevOps 场景中的实战:CI/CD 流水线脚本自动生成
运维·ci/cd·docker·devops·自动化部署·github actions
摇滚侠9 小时前
DockerHub 在国内有没有替代
docker
是大强10 小时前
Docker中文件修改的三种方法
运维·docker·容器
say_fall11 小时前
【Git 精品详解】企业规范:企业级开发模型、Git Flow、发版流程规范、Code Owner 制度、事故应急回滚
大数据·linux·服务器·git·学习·elasticsearch
激情的学姐21 小时前
【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器
运维·nginx