22

我有一组分散在多个服务器上的 dockerized 应用程序,并尝试使用 ELK 设置生产级集中日志记录。我对 ELK 部分本身没意见,但我对如何将日志转发到我的日志存储区有点困惑。我正在尝试使用 Filebeat,因为它具有负载平衡功能。我还想避免将 Filebeat(或其他任何东西)打包到我所有的 docker 中,并保持它分开,无论是否 dockerized。

我该如何进行?

我一直在尝试以下。我的 Docker 登录标准输出,因此使用配置为从标准输入读取的非 dockerized Filebeat 我这样做:

码头工人日志-f mycontainer | ./filebeat -e -c filebeat.yml

这似乎在一开始就起作用。第一个日志被转发到我的logstash。我猜是缓存的。但在某些时候它会卡住并继续发送相同的事件

这只是一个错误还是我走错了方向?你设置了什么解决方案?

4

6 回答 6

19

这是转发docker logs到 ELK 堆栈的一种方法(对于 gelf 日志驱动程序,需要 docker >= 1.8):

  1. 使用gelf 输入插件启动 Logstash 容器,以从 gelf 读取数据并输出到 Elasticsearch 主机(ES_HOST:port):

    docker run --rm -p 12201:12201/udp logstash \
        logstash -e 'input { gelf { } } output { elasticsearch { hosts => ["ES_HOST:PORT"] } }'
    
  2. 现在启动一个 Docker 容器并使用gelf Docker logging driver。这是一个愚蠢的例子:

    docker run --log-driver=gelf --log-opt gelf-address=udp://localhost:12201 busybox \
        /bin/sh -c 'while true; do echo "Hello $(date)"; sleep 1; done'
    
  3. 加载 Kibana,本应登陆的内容docker logs现在可见。gelf 源代码显示为您生成了一些方便的字段(帽子提示:Christophe Labouisse):_container_id, _container_name, _image_id, _image_name, _command, _tag, _created.

如果您使用 docker-compose(确保使用 docker-compose >= 1.5)并docker-compose.yml在启动 logstash 容器后添加适当的设置:

log_driver: "gelf"
log_opt:
  gelf-address: "udp://localhost:12201"
于 2015-11-20T00:01:41.260 回答
9

Docker 允许您指定正在使用的logDriver。这个答案不关心 Filebeat 或负载平衡。

在一次演示中,我使用 syslog 将日志转发到侦听端口 5000 的 Logstash (ELK) 实例。以下命令不断通过 syslog 向 Logstash 发送消息:

docker run -t -d --log-driver=syslog --log-opt syslog-address=tcp://127.0.0.1:5000 ubuntu /bin/bash -c 'while true; do echo "Hello $(date)"; sleep 1; done'
于 2015-10-30T10:00:36.270 回答
8

使用 filebeat,您可以docker logs像您所描述的那样通过管道输出。您看到的行为绝对听起来像一个错误,但也可能是部分行读取配置击中您(重新发送部分行,直到找到换行符)。

如果没有可用的logstash,我看到的管道问题可能是背压。如果 filebeat 无法发送任何事件,它将在内部缓冲事件,并在某些时候停止从标准输入读取。不知道 docker 如何/是否防止标准输出变得无响应。如果您使用的是 docker-compose,管道的另一个问题可能是 filebeat + docker 的重启行为。docker-compose 默认重用图像 + 图像状态。因此,当您重新启动时,您将再次发送所有旧日志(假设底层日志文件尚未轮换)。

您可以尝试读取 docker 写入主机系统的日志文件,而不是管道。默认的 docker 日志驱动是json 日志驱动. 您可以并且应该配置 json 日志驱动程序来执行日志轮换 + 保留一些旧文件(用于在磁盘上缓冲)。请参阅 max-size 和 max-file 选项。json 驱动程序为要记录的每一行放置一行“json”数据。在 docker 主机系统上,日志文件被写入 /var/lib/docker/containers/container_id/container_id-json.log 。这些文件将通过 filebeat 转发到 logstash。如果 logstash 或网络变得不可用或 filebeat 重新启动,它会继续转发它离开的日志行(给定文件由于日志轮换而没有被删除)。不会丢失任何事件。在 logstash 中,您可以使用 json_lines 编解码器或过滤器来解析 json 行,并使用 grok 过滤器从日志中获取更多信息。

关于使用 libbeat(由 filebeat 用于传送日志文件)向 docker 添加新的日志驱动程序已经有一些讨论。也许将来可以使用 docker logs api 通过dockerbeat收集日志(不过,我不知道有任何关于使用日志 api 的计划)。

使用 syslog 也是一种选择。也许你可以在你的 docker 主机负载平衡日志事件上获得一些 syslog 中继。或者让 syslog 写入日志文件并使用 filebeat 转发它们。我认为 rsyslog 至少有一些故障转移模式。您可以使用 logstash syslog 输入插件和 rsyslog 将日志转发到具有故障转移支持的 logstash,以防活动的 logstash 实例不可用。

于 2015-11-20T13:59:36.573 回答
7

我使用 Docker API 创建了自己的 docker 镜像来收集机器上运行的容器的日志,并通过 Filebeat 将它们发送到 Logstash。无需在主机上安装或配置任何东西。

检查一下并告诉我它是否适合您的需求:https ://hub.docker.com/r/bargenson/filebeat/ 。

代码可在此处获得:https ://github.com/bargenson/docker-filebeat

于 2016-02-07T06:17:47.930 回答
0

只是为了帮助其他需要这样做的人,您可以简单地使用 Filebeat 来发送日志。我会使用@brice-argenson 的容器,但我需要 SSL 支持,所以我使用了本地安装的 Filebeat 实例。

filebeat 的探矿者是(重复更多容器):

- input_type: log
  paths:
    - /var/lib/docker/containers/<guid>/*.log
  document_type: docker_log
  fields:
    dockercontainer: container_name

您需要知道 GUID 有点糟糕,因为它们可能会在更新时发生变化。

在 logstash 服务器上,为 logstash 设置通常的 filebeat 输入源,并使用如下过滤器:

filter {
  if [type] == "docker_log" {
    json {
      source => "message"
      add_field => [ "received_at", "%{@timestamp}" ]
      add_field => [ "received_from", "%{host}" ]
    }
    mutate {
      rename => { "log" => "message" }
    }
    date {
      match => [ "time", "ISO8601" ]
    }
  }
}

这将从 Docker 日志中解析 JSON,并将时间戳设置为 Docker 报告的时间戳。

如果你从 nginx Docker 镜像中读取日志,你也可以添加这个过滤器:

filter {
  if [fields][dockercontainer] == "nginx" {
    grok {
      match => { "message" => "(?m)%{IPORHOST:targethost} %{COMBINEDAPACHELOG}" }
    }
    mutate {
      convert => { "[bytes]" => "integer" }
      convert => { "[response]" => "integer" }
    }
    mutate {
      rename => { "bytes" => "http_streamlen" }
      rename => { "response" => "http_statuscode" }
    }
  }
}

转换/重命名是可选的,但修复了COMBINEDAPACHELOG表达式中的一个疏忽,即它不会将这些值转换为整数,从而使它们无法在 Kibana 中进行聚合。

于 2016-11-25T09:25:10.013 回答
0

我在评论中验证了 erewok 上面写的内容:

根据文档,您应该能够在您的prospectors.paths 中使用这样的模式:/var/lib/docker/containers/*/*.log – erewok Apr 18 at 21:03

以第一个“*”表示的 docker 容器 guid 在 filebeat 启动时被正确解析。我不知道添加容器时会发生什么。

于 2017-09-13T22:14:56.570 回答