docker 搭建 EFK(ElasticSearch+Fluentd+Kibana)日志集中收集系统
EFK 日志采集系统
简介
EFK
= ElasticSearch
+ Fluentd
+ Kibana
Elasticsearch
是一个分布式的搜索和分析引擎,可以用于全文检索、结构化检索和分析,并能将这三者结合起来。
Fluentd
是一个优秀的 log
信息收集开源免费软件。
Kibana
是一个开源的分析与可视化平台,可以用 kibana
搜索、查看存放在 Elasticsearch
中的索引。
版本
当前最新的 Release
版本
Elasticsearch
: v6.4.2 – 2018/10/02
Fluentd
: v1.2.6 – 2018/10/03
Kibana
: v6.4.2 – 2018/10/02
主要介绍 Fluentd
Fluentd
是一个完全开源免费的日志收集系统。它主要使用 c 语言编写并由轻量级的 Ruby
封装,给用户提供灵活的扩展性,因此它目前有 125
以上插件。结合不同插件可实现:异常报警(alerting)、数据分析(analysis)、归档(archiving)等等功能。
特点:
1)安装方便
2)占用空间小
3)半结构化数据日志记录
4)灵活的插件机制
5)可靠的缓冲
6)日志转发
使用前
使用后
使用场景
1.apache 日志到 mongodb
步骤:
1.轮询监控 access_log
文件。
2.将传入的日志记录解析为有意义的字段(例如:ip
, path
,user_agent
等)并缓冲他们。
3.定时将缓冲区内容写入 MongoDB
。
2.程序推送
配置 fluent.conf
<source>
@type forward
port 24224
</source>
<match fluentd.test.**>
@type stdout
</match>
JAVA
import java.util.HashMap;
import java.util.Map;
import org.fluentd.logger.FluentLogger;
public class Main {
private static FluentLogger LOG = FluentLogger.getLogger("fluentd.test");
public void doApplicationLogic() {
// ...
Map<String, Object> data = new HashMap<String, Object>();
data.put("from", "userA");
data.put("to", "userB");
LOG.log("follow", data);
// ...
}
}
PHP
<?php
require_once __DIR__.'/vendor/autoload.php';
use Fluent\Logger\FluentLogger;
$logger = new FluentLogger("localhost","24224");
$logger->post("fluentd.test.follow", array("from"=>"userA", "to"=>"userB"));
3.docker 日志
fluent.conf
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
# docker log
<match docker.**>
@type elasticsearch
host elasticsearch
port 9200
type_name docker
logstash_format true
logstash_prefix docker-logs
logstash_dateformat %Y-%m-%d
flush_interval 15s
include_tag_key true
</match>
docker-compose.yml
加入如下配置信息
logging:
driver: fluentd
options:
fluentd-address: "192.168.5.47:24224"
tag: "docker.web.cas"
4.多节点集中收集
“日志聚合器” 是继续从日志转发器接收事件的守护程序。 他们缓冲事件并定期将数据上传到云中。
5.日志可视化
该图为上文所提到的 EFK 日志系统架构
插件
Fluentd
存在 7 种类型的插件:
Input 输入,从外部源检索和提取事件日志。
Parser 解析器,允许用户创建自定义的解析器。
Filter 过滤器,用于过滤输入内容(例如: 隐私信息)
Output 输出
Formatter 格式化器
Storage 存储引擎
Buffer 缓冲区
以下主要介绍 Input
Filter
Output
这 3 种插件
输入(Input)
Fluentd
支持多种的输入类型,支持 udp
tcp
http
等数据包的监听。既支持网络协议传输的数据流,也支持从文件中读取数据。
监听 tcp 数据包例子
配置
<source>
@type tcp
tag tcp.events # required
<parse>
@type regexp
expression /^(?<field1>\d+):(?<field2>\w+)$/
</parse>
port 20001 # optional. 5170 by default
bind 0.0.0.0 # optional. 0.0.0.0 by default
delimiter \n # optional. \n (newline) by default
</source>
发送数据包
$ echo '123456:awesome' | netcat 0.0.0.0 5170
fluentd 解析
{"field1":"123456","field2":"awesome}
过滤(Filter)
过滤插件使 Fluentd 可以修改事件流。
示例用例:
通过删除一个或多个字段的值来过滤事件
通过添加新字段丰富事件 例如:给某个符合的记录,添加一个字段标记
删除或屏蔽某些字段,以确保隐私权和合规性。
Event processing pipeling(事件处理流)
filter
指令具有与 match
相同的语法,但是 filter
可以串联成 pipeline
,对数据进行串行处理,最终再交给 match
输出。 使用 fliters
,事件流如下:
Input -> filter 1 -> ... -> filter N -> Output(Match tag)
例 1:
配置:
<source>
@type http
port 8888
bind 0.0.0.0
</source>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^logout$ # 过滤掉 action 参数为 logout 的数据
</exclude>
</filter>
<match test.cycle>
@type stdout
</match>
测试:
$ curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-type: text/plain
Connection: Keep-Alive
Content-length: 0
$ curl -i -X POST -d 'json={"action":"logout","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-type: text/plain
Connection: Keep-Alive
Content-length: 0
输出:
2018-10-15 12:37:41 -0600 [info]: adding filter pattern="test.cycle" type="grep"
2018-10-15 12:37:41 -0600 [info]: adding match pattern="test.cycle" type="stdout"
2018-10-15 12:37:41 -0600 [info]: adding source type="http"
2018-10-25 12:37:42 -0600 test.cycle: {"action":"login","user":2}
上面的指令用标签 foo
匹配事件。如果 action
字段的值包含 logout
,则事件将过滤该记录。
例 2:
### http://this.host:9880/myapp.access?json={"event":"data"}
<source>
@type http
port 9880
</source>
# filter 1
<filter foo.bar>
@type grep
regexp1 message cool
</filter>
# filter 2
<filter foo.bar>
@type record_transformer
<record>
hostname "#{Socket.gethostname}"
</record>
</filter>
只有其 message
字段包含 cool
的事件才会添加新的 hostname
字段,并将机器的主机名作为其值。
如果有多个 filter
标签,命中上一个才会继续往下匹配。
这个例子里,filter
获取数据后,调用原生的 @type record_transformer
插件,在事件的 record
里插入了新的字段 host_param
,然后再交给 match
输出。
filter
匹配顺序与 match
相同,应该在 <match>
之前放置 <filter>
。
输出(Output)
存在 3 种输出模式:
- Non-Buffered mode(不缓冲): 不缓存数据并立即写出结果。
- Synchronous Buffered mode(同步缓冲模式): 具有“分段”缓冲块(块是事件的集合)和块的队列,其行为可以由
<buffer>
部分控制(见下图)。 - Asynchronous Buffered mode(异步步缓冲模式): 也存在
stage
和queue
,但是 output plugin 不会同步提交写块,而是在以后提交。
输出插件可以支持所有模式,但只支持其中一种模式。如果配置中没有的部分,Fluentd
会自动选择合适的模式。
总结
Input
负责接收数据或者主动抓取数据。支持 syslog
,http
,file
tail
等。
Buffer
负责数据获取的性能和可靠性,也有文件或内存等不同类型的 Buffer
可以配置。
Output
负责输出数据到目的地例如文件,AWS S3 或者其它的 Fluentd。
Docker 环境下搭建 EFK
docker 运行容器
xp-room@experience-room:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b45c17e65a49 kibana:6.4.2 "/usr/local/bin/ki..." 4 days ago Up 4 days 0.0.0.0:5601->5601/tcp efk_kibana_1
58ba0b6ec3a7 efk_fluentd "/bin/entrypoint.s..." 4 days ago Up 4 days 5140/tcp, 0.0.0.0:24224->24224/tcp, 0.0.0.0:24224->24224/udp 58ba0b6ec3a7_efk_fluentd_1
ceb349479fdf elasticsearch:6.4.2 "/usr/local/bin/do..." 4 days ago Up 4 days 0.0.0.0:9200->9200/tcp, 9300/tcp efk_elasticsearch_1
Server
Tree
server
├── docker-compose.yml
├── elasticsearch
│ └── elasticsearch.yml
├── fluentd
│ ├── conf
│ │ └── fluent.conf
│ └── Dockerfile
└── kibana
└── kibana.yml
docker-compose.yml
version: '2'
services:
fluentd:
privileged: true
build: ./fluentd
volumes:
- ./fluentd/conf:/fluentd/etc
- /var/log/nginx/access-kod-explorer.log:/var/logs/nginx/access-kod-explorer.log
- /var/log/fluentd:/var/lib/fluentd
links:
- "elasticsearch"
ports:
- "24224:24224"
- "24224:24224/udp"
elasticsearch:
image: elasticsearch:6.4.2
expose:
- 9200
environment:
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- TZ=Asia/Shanghai
ulimits:
memlock:
soft: -1
hard: -1
ports:
- "9200:9200"
volumes:
- ./elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
kibana:
image: kibana:6.4.2
links:
- "elasticsearch"
ports:
- "5601:5601"
volumes:
- ./kibana/kibana.yml:/usr/share/kibana/config/kibana.yml
environment:
- TZ=Asia/Shanghai
elasticsearch
elasticsearch.yml
cluster.name: "docker-cluster"
network.host: 0.0.0.0
# minimum_master_nodes need to be explicitly set when bound on a public IP
# set to 1 to allow single node clusters
# Details: https://github.com/elastic/elasticsearch/pull/17288
discovery.zen.minimum_master_nodes: 1
fluentd
Dockerfile
# fluentd/Dockerfile
FROM fluent/fluentd:v1.2-debian
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-rdoc", "--no-ri"]
conf
fluent.conf
# fluentd/conf/fluent.conf
# Server
# in_forward
<source>
@type forward
port 24224
bind 0.0.0.0
# <security>
# self_hostname experience-room
# shared_key room2017
# </security>
</source>
# fhy scenic access log
<match apache.access>
@type elasticsearch
host elasticsearch
port 9200
logstash_prefix fhyscenic
logstash_format true
logstash_dateformat %Y%m%d
type_name scenic_access_log #(optional; default=fluentd)
flush_interval 10s
</match>
# docker log
<match docker.**>
@type elasticsearch
host elasticsearch
port 9200
type_name docker
logstash_format true
logstash_prefix docker-logs
logstash_dateformat %Y-%m-%d
flush_interval 15s
include_tag_key true
</match>
kibana
kibana.yml
---
# Default Kibana configuration from kibana-docker.
server.name: kibana
server.host: "0"
elasticsearch.url: http://elasticsearch:9200
xpack.monitoring.ui.container.elasticsearch.enabled: true
Client
Tree
client
├── docker-compose.yml
└── fluentd
├── conf
│ └── fluent.conf
└── Dockerfile
docker-compose.yml
version: '2'
services:
fluentd:
build: ./fluentd
volumes:
- ./fluentd/conf:/fluentd/etc
- /usr/local/apache2/logs:/var/logs/httpd:rw
- /disk4/log/fluentd:/var/lib/fluentd:rw
# links:
# - "elasticsearch"
ports:
- "24224:24224"
- "24224:24224/udp"
# logging:
# driver: fluentd
# options:
# fluentd-address: "192.168.5.47:24224"
# tag: "docker.web"
fluentd
Dockerfile
# fluentd/Dockerfile
FROM fluent/fluentd:v1.2-debian
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-rdoc", "--no-ri"]
conf
fluent.conf
# fluentd/conf/fluent.conf
# Client
# scenic access log
<source>
@type tail
path /var/logs/httpd/jingqv-access_log # 需要收集的日志文件
pos_file /var/lib/fluentd/jingqv-access_log.pos # 记录收集目录
tag apache.access # 定义标签
format apache2 # 日志类型 可支持正则表达式
read_from_head true # 从文件头部读取日志文件
</source>
# out_forward
<match apache.access>
@type forward
compress gzip
# 将日志记录输出到远程服务器
<server>
name Centos7 # client server name
host 192.168.5.47 # server fluentd
port 24224
</server>
# <security>
# self_hostname Centos7-110
# shared_key room2017
# </security>
flush_interval 5s
buffer_chunk_limit 8m
buffer_queue_limit 1000
num_threads 4
</match>
参考
https://docs.fluentd.org/v1.0/articles/in_forward
https://docs.fluentd.org/v1.0/articles/out_forward