欢迎光临
我们一直在努力

ELK 日志收集平台实战:Docker Compose 一键部署,从零搭建运维日志看板

本文基于实际项目,记录了使用 Docker Compose 部署 ELK 日志收集平台的完整过程,包括架构设计、配置详解、踩坑记录和效果展示。

前言

作为运维人员,你是否遇到过这些场景:

  • 服务器报错了,日志分散在 10 台机器上,一台一台 ssh 上去 cat?
  • Nginx 访问量突然暴涨,哪个接口被刷了?
  • 程序挂了,想看最近 1 小时的错误日志,却不知道从哪找?

ELK 就是解决这些问题的利器!

它能把分散在各台服务器的日志集中收集、全文搜索、可视化展示,让你在一个网页上就能查所有机器的日志。

什么是 ELK?

ELK 是三个工具的组合:

组件作用类比
Elasticsearch 存储和搜索日志的数据库 图书馆的书架 + 检索系统
Logstash 过滤、解析、转换日志 图书馆的分拣员
Kibana 可视化展示日志 图书馆的查询终端

再加上一个轻量级采集器 Filebeat,组成完整的日志收集体系。

架构设计

整体架构

┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Nginx │───▶│ Filebeat │───▶│ Logstash │───▶│Elasticsearch│
│ 产生日志 │ │ 采集日志 │ │ 过滤解析 │ │ 存储日志 │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘


┌─────────────┐
│ Kibana │
│ 可视化展示 │
└─────────────┘

数据流向

  • Nginx 产生访问日志(JSON 格式)
  • Filebeat 读取日志文件,发送给 Logstash
  • Logstash 解析 JSON,提取 IP、时间、URL、状态码等字段
  • 解析后的日志存入 Elasticsearch
  • Kibana 从 Elasticsearch 读取数据,展示图表
  • 为什么用 Filebeat?

    你可能会问:为什么不直接让 Logstash 读日志文件?

    原因:

    • Logstash 是 Java 写的,吃资源(内存大)
    • Filebeat 是 Go 写的,轻量级,只负责"读文件、发送"
    • 实际生产环境:每台服务器装 Filebeat 采集日志,集中发给 Logstash 处理

    类比:

    • Filebeat = 快递员(上门取件)
    • Logstash = 分拣中心(拆包、分类、打包)
    • Elasticsearch = 仓库(存储)
    • Kibana = 查询系统(查快递到哪了)

    环境准备

    前置条件

    • Docker 已安装
    • Docker Compose 已安装
    • 至少 4GB 可用内存
    • 至少 10GB 可用磁盘空间

    检查命令

    docker –version
    docker compose version
    free -h
    df -h /

    部署步骤

    第一步:创建项目目录

    mkdir -p /root/elk-platform
    cd /root/elk-platform
    mkdir -p nginx/conf.d nginx/logs logstash/pipeline filebeat

    第二步:配置 Nginx

    创建 nginx/nginx.conf:

    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;

    # 定义 JSON 格式的日志格式
    log_format json_combined escape=json
    '{'
    '"time_local":"$time_local",'
    '"remote_addr":"$remote_addr",'
    '"remote_user":"$remote_user",'
    '"request":"$request",'
    '"status": "$status",'
    '"body_bytes_sent":"$body_bytes_sent",'
    '"request_time":"$request_time",'
    '"http_referer":"$http_referer",'
    '"http_user_agent":"$http_user_agent"'
    '}';

    sendfile on;
    keepalive_timeout 65;

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

    创建 nginx/conf.d/default.conf:

    server {
    listen 80;
    server_name localhost;

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

    location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    }
    }

    为什么要用 JSON 格式?

    传统的 Nginx 日志是这样的:

    192.168.1.1 – – [04/Jun/2026:10:30:00 +0000] "GET /index.html HTTP/1.1" 200 1234

    Logstash 需要用正则表达式解析,容易出错。改成 JSON 格式后:

    {"time_local":"04/Jun/2026:10:30:00 +0000","remote_addr":"192.168.1.1","request":"GET /index.html HTTP/1.1","status":"200"}

    Logstash 直接解析 JSON,简单可靠。

    第三步:配置 Logstash

    创建 logstash/pipeline/nginx.conf:

    input {
    beats {
    port => 5044
    }
    }

    filter {
    json {
    source => "message"
    target => "nginx"
    }

    date {
    match => ["[nginx][time_local]", "dd/MMM/yyyy:HH:mm:ss Z"]
    target => "@timestamp"
    }

    mutate {
    convert => {
    "[nginx][status]" => "integer"
    "[nginx][body_bytes_sent]" => "integer"
    "[nginx][request_time]" => "float"
    }
    }

    mutate {
    add_field => { "source" => "nginx" }
    }
    }

    output {
    elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "nginx-access-%{+YYYY.MM.dd}"
    }
    }

    配置详解:

    • input { beats { port => 5044 } } — 接收 Filebeat 发送的数据
    • json { source => "message" } — 解析 JSON 格式的日志
    • date { … } — 提取时间字段,替换默认的 @timestamp
    • mutate { convert => … } — 转换字段类型(字符串转数字)
    • output { elasticsearch { … } } — 输出到 Elasticsearch,索引名按日期分

    第四步:配置 Filebeat

    创建 filebeat/filebeat.yml:

    filebeat.inputs:
    type: log
    enabled: true
    paths:
    /var/log/nginx/access.log

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

    logging.level: info
    logging.to_files: true
    logging.files:
    path: /var/log/filebeat
    name: filebeat
    keepfiles: 7
    permissions: 0644

    注意:hosts 要写 logstash:5044,不能写 localhost:5044,因为容器内的 localhost 指的是容器自己。

    第五步:创建 Docker Compose

    创建 docker-compose.yml:

    version: '3.8'

    services:
    elasticsearch:
    image: elasticsearch:8.11.0
    container_name: elasticsearch
    environment:
    discovery.type=singlenode
    xpack.security.enabled=false
    ES_JAVA_OPTS=Xms512m Xmx512m
    ports:
    "9200:9200"
    volumes:
    es_data:/usr/share/elasticsearch/data
    networks:
    elk
    healthcheck:
    test: ["CMD-SHELL","curl -f http://localhost:9200/_cluster/health || exit 1"]
    interval: 30s
    timeout: 10s
    retries: 5

    logstash:
    image: logstash:8.11.0
    container_name: logstash
    ports:
    "5044:5044"
    volumes:
    ./logstash/pipeline:/usr/share/logstash/pipeline
    environment:
    LS_JAVA_OPTS=Xms256m Xmx256m
    networks:
    elk
    depends_on:
    elasticsearch:
    condition: service_healthy

    kibana:
    image: kibana:8.11.0
    container_name: kibana
    ports:
    "5601:5601"
    environment:
    ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    networks:
    elk
    depends_on:
    elasticsearch:
    condition: service_healthy

    filebeat:
    image: elastic/filebeat:8.11.0
    container_name: filebeat
    user: root
    volumes:
    ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
    ./nginx/logs:/var/log/nginx:ro
    filebeat_data:/usr/share/filebeat/data
    networks:
    elk
    depends_on:
    logstash

    nginx:
    image: nginx:alpine
    container_name: nginx
    ports:
    "80:80"
    volumes:
    ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    ./nginx/conf.d:/etc/nginx/conf.d:ro
    ./nginx/logs:/var/log/nginx
    networks:
    elk

    volumes:
    es_data:
    filebeat_data:

    networks:
    elk:
    driver: bridge

    第六步:启动服务

    docker-compose up -d

    启动需要 1-2 分钟,用以下命令查看状态:

    docker-compose ps

    第七步:验证服务

    # 验证 Elasticsearch
    curl http://localhost:9200

    # 生成测试日志
    curl http://localhost
    curl http://localhost/test

    # 查看 Elasticsearch 索引
    curl http://localhost:9200/_cat/indices

    第八步:在 Kibana 中查看日志

  • 打开 Kibana:http://localhost:5601
  • 点击左上角菜单 → “Discover”
  • 点击 “Create data view”
  • 填写:
    • Name: nginx-access-*
    • Pattern: nginx-access-*
    • Timestamp: @timestamp
  • 点击 “Save data view to Kibana”
  • 现在可以看到日志了!
  • 踩坑记录

    踩坑 1:Nginx log_format 必须在 http 块内

    现象:

    nginx: [emerg] "log_format" directive is not allowed here

    原因:

    • log_format 是全局指令,必须在 http 块内定义
    • 我们把配置放在 conf.d/ 目录,这个目录的文件会被包含到 server 块内
    • server 块内不能定义 log_format

    解决:

    • 挂载完整的 nginx.conf,在 http 块内定义 log_format
    • conf.d/default.conf 只定义 server 块

    教训: 配置文件写完一定要测试,不能只看逻辑对不对。

    踩坑 2:Filebeat 输出地址要用容器名

    现象:

    • Filebeat 日志显示连接 Logstash 失败
    • connection refused

    原因:

    • 配置文件中写的是 localhost:5044
    • 在容器内 localhost 指的是容器自己,不是 Logstash 容器

    解决:

    # 错误
    output.logstash:
    hosts: ["localhost:5044"]

    # 正确
    output.logstash:
    hosts: ["logstash:5044"]

    教训: Docker 容器内访问其他容器,要用容器名,不能用 localhost。

    踩坑 3:Elasticsearch 内存不足

    现象:

    elasticsearch exited with code 137

    原因:

    • Elasticsearch 默认需要 1GB 内存
    • 虚拟机内存不足,被 OOM Killer 杀掉

    解决:

    environment:
    ES_JAVA_OPTS=Xms512m Xmx512m

    教训: Java 应用要限制内存,避免占用太多资源。

    踩坑 4:Filebeat 权限不足

    现象:

    Permission denied

    原因:

    • Filebeat 默认用户是 filebeat(UID 1000)
    • Nginx 日志文件的所有者是 root
    • filebeat 用户没有读权限

    解决:

    filebeat:
    user: root

    教训: Docker 挂载文件时要注意权限问题。

    效果展示

    Kibana Discover 页面

    在 Discover 页面可以看到所有的 Nginx 访问日志,包括:

    • 请求时间
    • 客户端 IP
    • 请求路径
    • HTTP 状态码
    • 响应大小
    • 用户代理

    创建可视化图表

    在 Kibana 中可以创建各种图表:

    • 请求量趋势:按时间展示请求量变化
    • 状态码分布:饼图展示 200、404、500 的比例
    • Top 10 IP:表格展示访问量最大的 IP
    • 请求路径:词云展示最常访问的路径

    常用命令

    # 启动服务
    docker-compose up -d

    # 停止服务
    docker-compose down

    # 停止并删除数据
    docker-compose down -v

    # 查看所有日志
    docker-compose logs -f

    # 查看某个服务的日志
    docker-compose logs -f elasticsearch
    docker-compose logs -f logstash
    docker-compose logs -f kibana
    docker-compose logs -f filebeat
    docker-compose logs -f nginx

    # 重启服务
    docker-compose restart

    # 进入容器
    docker-compose exec elasticsearch bash
    docker-compose exec logstash bash

    和 Prometheus 的区别

    PrometheusELK
    监控什么 指标(数字) 日志(文本)
    典型问题 “CPU 90% 了!” “哪个接口报错了?”
    存储方式 时序数据库 全文搜索引擎

    两者互补,不是替代关系。

    • Prometheus 告诉你"服务器出问题了"
    • ELK 帮你找到"具体是什么问题"

    扩展方向

  • 收集多个应用的日志 — 修改 Filebeat 配置,添加多个 input
  • 添加告警 — 使用 Elasticsearch 的 Watcher 或 Kibana 的 Alerting
  • 日志保留策略 — 配置 Elasticsearch 的 ILM(Index Lifecycle Management)
  • 安全加固 — 启用 Elasticsearch 的 X-Pack Security
  • 性能优化 — 调整 Elasticsearch 的分片和副本数量
  • 总结

    通过本文,我们完成了:

  • ✅ 使用 Docker Compose 部署 ELK 平台
  • ✅ 配置 Nginx 输出 JSON 格式日志
  • ✅ 配置 Filebeat 采集日志
  • ✅ 配置 Logstash 解析日志
  • ✅ 在 Kibana 中查看和可视化日志
  • ELK 是运维工程师的必备技能,掌握它能让你的日志管理效率提升 10 倍!

    参考文档

    • Elasticsearch 官方文档
    • Logstash 官方文档
    • Kibana 官方文档
    • Filebeat 官方文档

    如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注!

    赞(0)
    未经允许不得转载:171主机测评 » ELK 日志收集平台实战:Docker Compose 一键部署,从零搭建运维日志看板
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址