Filebeat5+Kafka+ELK Docker搭建日志系统

lek-architecture.jpg

这篇文章是基于近期搭建的日志系统踩过的各种坑,本身自己是边做边记录的,但是内容点实在斑驳繁杂,仅仅是技术选型就来回折腾了几次,选型后的版本匹配问题又是一些体力活(5.0开始已有统一版本号的趋势:ELKstack),最后的日志解析和应用产品线如何设计更是重中之重。

思虑再三,还是决定把整个过程以去除弯路,单刀直入加备注坑点的方式来描述一把。希望能写清楚。面向读者需要对文中的技术有一定理论知识,本文只叙搭建不究原理。

准备工作

  • 所有的安装、配置或者说明文档都以官方为准,比如 docker.io, elastic.co, kafka.apache.org 等。
    百度出来的古老文章如果解决不了问题,后果自裁。
  • 备好三台不同ip的虚机(下文用A B C说明),做集群嘛,标配!
  • 做好心理预期,谷歌科学搜索不能少,妖怪问题会层出不穷,千万不能被吓到!
名称 版本号
Filebeat 5.0.0-alpha1
Kafka 0.9.0.1
Zookeeper 3.4.8
Elasticsearch 2.4.0
Logstash 2.4.0
Kibana 4.6.0

为什么使用Docker

纯粹是处于个人爱好,各种技术只要跟 Docker 搭边就倾爱它的 Docker 镜像版本。本文除了filebeat agent是二进制版本直接安装在应用机上,与docker无关,其他都是基于docker 镜像版本的集群安装。

为什么使用Kafka

分布式基于发布订阅的消息系统Kafka,它可以将业务应用端(client)和日志分析服务端(server)很好的黏合起来,并起到了缓冲作用,并提供了很多优秀特性比如异步,解耦,持久化,顺序化等。而且Kafka可以与很多开源组件Storm、Spark等集成,对于日后的扩展这一层会有很大的帮助。

为什么选择Filebeat5

本来开始确实是首选Flume,要做两件事:①上传client端的日志文件到Kafka; ②消费Kafka的队列消息存入ElasticSearch。
坑爹的是,当时最新发布的Flume版本是1.6.0, 而它支持的es版本最高只到1.7.5, 不支持2.x版本,中间对es做了各种的降级和甚至还得配合jdk8云云, 最后放弃。
选择就剩了 logstash-forwarder 和 filebeat, 而后者其实就是前者的升级版+替代品,所以直接选用filebeat无疑了。
妖怪又粗线了, filebeat当时的最新稳定版是1.3.0, 而它是不支持output到kafka的。也就是第①件事就被卡住了,幸好Beats5的alpha1测试版发布了,虽然不稳定,但是测试下来还未发现日志丢失的情况,先用着吧。
话音未落,alpha2又发布了...
https://www.elastic.co/guide/en/beats/libbeat/master/release-notes-5.0.0-alpha2.html

第②件事就通过Logstash来实现了(因为docker镜像就是elk一体的 hihahiha)

开整

问完十万个为什么之后,终于可以开整了(其实前面的#为什么#也是我的血泪史...)

一、Zookeeper 的安装

直接介绍一个不错的docker镜像,pull下来直接使用
<pre>docker pull jeygeethan/zookeeper-cluster</pre>

集群三个点上分别启动命令,虚拟卷大家自定义
<pre>docker run --name docker-zk -d --restart=always
--net="host"
-p 2181:2181
-p 2888:2888
-p 3888:3888
-v ~/dockerdata/zookeeper/lib:/var/lib/zookeeper
-v ~/dockerdata/zookeeper/log:/var/log/zookeeper
-v /etc/localtime:/etc/localtime:ro
jeygeethan/zookeeper-cluster 192.168.0.1,192.168.0.2,192.168.0.3 1 ***{1/2/3: 三个节点分别设置} ***</pre>

三个节点都启动成功后,进入节点A

运行 docker exec -it docker-zk bash

默认就会进入/usr/share/zookeeper 目录,

运行 bin/zkCli.sh

进入了zk的客户端命令行,
<pre>
创建节点 create /nicholas "nicholas"
查看节点 get /nicholas 显示创建成功,
在虚机B、C上执行get操作检查下新的节点是否已同步,可见则成功。
</pre>

二、Kafka 的安装

同样 pull 镜像先
<pre>docker pull jeygeethan/kafka-cluster</pre>

同样三个节点上分别启动,注意,我这里kafka和zk使用的是相同的三台虚机。
<pre>
docker run --name docker-kafka -d -p 9092:9092
-e KAFKA_HOST=192.168.0.1
-e KAFKA_PORT=9092
-e ZOOKEEPER_CONNECT=192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181
-e KAFKA_ID=0 ***{0/1/2: 三个节点分别设置,从0开始} ***
-v ~/dockerdata/kafka/logs:/tmp/kafka-logs
jeygeethan/kafka-cluster
</pre>

同时进入虚机A,和虚机B
<pre>
进入docker
docker exec -it docker-kafka bash
转换目录
cd /opt/kafka_2.11-0.9.0.1/bin
创建Topic
./kafka-topics.sh --create --topic TP_NIC --partitions 4 --replication-factor 2
--zookeeper 192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181
查看Topic
./kafka-topics.sh --describe --topic TP_NIC
--zookeeper 192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181
在broker0(虚机A)上生产消息
./kafka-console-producer.sh --topic=TP_NIC
--broker-list=192.168.0.1:9092,192.168.0.2:9092,192.168.0.3:9092
在broker1(虚机B)上消费消息
./kafka-console-consumer.sh --topic=TP_NIC
--zookeeper 192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181
</pre>

到此,虚机A和B已经都关联上了TP_NIC, 在 A 命令行上,随意输入各类字符, 在 B 上可以看到同样的字符即说明消费成功了.

三、ELK 的安装

pull 镜像 2.4 版本 最新的5已经有了
<pre>docker pull sebp/elk:es240_l240_k460</pre>

修改即将要映射的虚拟卷的目录权限, 注意这里的991,992,993分别对应ELK的三个独立用户,如果你看下docker file的build脚本就明白了,为了让docker运行成功,我们先把权限配上。
<pre>
chown -R 991:991 ~/dockerdata/es && chown -R 992:992 ~/dockerdata/logstash && chown -R 993:993 ~/dockerdata/kibana
</pre>

进入对应的目录,我们先把配置给设定好。
注:这些配置文件是从docker里面cp出来的,如源文件没有,请先docker run启动原镜像然后docker cp拷贝。

  • Elasticsearch 配置

<pre>
vi ~/dockerdata/es/config/elasticsearch.yml
编辑内容如下
cluster.name: mm-cluster

node.name: mm-node-01
node.master: false
node.data: true

restrict outside access

network.host: 192.168.0.11
transport.tcp.port: 9300
http.port: 9200

path.data: /etc/elasticsearch/data
path.work: /etc/elasticsearch/work
path.logs: /etc/elasticsearch/logs
path.plugins: /etc/elasticsearch/plugins

bootstrap.mlockall: true

discovery.zen.ping.multicat.enabled: false
discovery.zen.fd.ping_timeout: 100s

discovery.zen.fd.ping_retries: 6

discovery.zen.fd.ping_interval: 30s

discovery.zen.ping.timeout: 100s
discovery.zen.minimum_master_nodes: 1

discovery.zen.ping.unicast.hosts: ["192.168.0.11", "192.168.0.12", "192.168.0.13"]
gateway.recover_after_nodes: 2

action.auto_create_index: false

index.number_of_replicas: 0
index.number_of_shards: 2
</pre>

  • Kibana 配置

<pre>
vi ~/dockerdata/kibana/config/kibana.yml
检查 elasticsearch.url: "http://localhost:9200" 对应上了即可
</pre>

  • Logstash 配置

<pre>
新增Kafka的input配置文件:
vi ~/dockerdata/logstash/config/03-kafka-input.conf


input {
kafka {
zk_connect => "192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181 "
#group_id => ""
topic_id => "syslog"
codec => "plain"
reset_beginning => false
consumer_threads => 5
decorate_events => true
add_field => { "[@metadata][type]" => "syslog" }
}
}

修改日志解析过滤配置文件:
vi ~/dockerdata/logstash/config/10-syslog.conf


filter {
if [@metadata][type] in ["syslog","accesslog"] {
ruby {
code => "event['mlogsendts'] = event['@timestamp']"
}
mutate {
add_field => ["mlogsendts_string", "%{@timestamp}"]
}
json {
source => "message"
add_field => {
"mlogmsg" => "%{message}"
}
remove_field => [ "message"]
}
grok {
patterns_dir => ["/opt/logstash/patterns"]
match => { "mlogmsg" => "[%{MMLOGTS:mlogts}]\s[%{MMLOGWORDEXT:mlogcell}]\s[%{MMLOGWORDEXT:mlognode}]\s[%{MMLOGWORDEXT:mlogthread}]\s[%{MMLOGWORD:mloglevel}]\s[%{MMLOGWORDEXT:mlogclass}]\s%{GREEDYDATA}" }
}
grok {
match => { "source" => "%{GREEDYDATA}/%{GREEDYDATA:mlogfilename}.log" }
}

syslog_pri { }
date {
  match => [ "mlogts", "yyyy-MM-dd HH:mm:ss.SSS" ]
  timezone => "Asia/Shanghai"
  target => "@timestamp"
}

}
}

这里最复杂的其实是两件事,
① 用日志中的时间戳替换系统@timstamp(参见配置)
②grok表达式将日志中的变量分段解析(找在线grok校验工具可以验证自己的正则,很费劲!!!)
grok表达式默认支持各种格式的正则格式变量,大家自行官网搜索,这里我是自定义的一些正则变量,存放在:
vi ~/dockerdata/logstash/patterns/mmlog
.
patterns下面的文件logstash默认会自动扫描的,所以文件名随便定义,只要正则对了就可以了。
内容为:
MMLOGTS \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.\d{3}
MMLOGWORD \w*
MMLOGWORDEXT [^]]+
MMLOGTHREAD \w(\w):\w-\w
MMLOGCLASS [\w.]+:\w\s*
</pre>

下面就可以启动docker了,对于ELK中的Elasticsearch 和 Logstash都需要是集群三个点的,而Kibana只是展示数据,单点即可。所以启动脚本分别为:

  • Kibana单点虚机,ELK三者全部开启,E+L的堆大小配置是基于该虚机是2c4g(相对低配置)
    <pre>
    docker run --privileged=true -i -d -p 5601:5601 -p 9200:9200 -p 9300:9300 -p 5044:5044 -p 5000:5000
    --net="host"
    -v ~/dockerdata/es/config/:/etc/elasticsearch/:rw
    -v ~/dockerdata/es/plugins/:/etc/elasticsearch/plugins/:rw
    -v ~/dockerdata/es/data/:/etc/elasticsearch/data/:rw
    -v ~/dockerdata/es/work/:/etc/elasticsearch/work/:rw
    -v ~/dockerdata/es/logs/:/var/log/elasticsearch/:rw
    -v ~/dockerdata/logstash/config/:/etc/logstash/conf.d/:rw
    -v ~/dockerdata/logstash/patterns/:/opt/logstash/patterns/:rw
    -v ~/dockerdata/logstash/logs/:/var/log/logstash/:rw
    -v ~/dockerdata/kibana/config/:/opt/kibana/config/:rw
    -v ~/dockerdata/kibana/logs/:/var/log/kibana/:rw
    -v /etc/localtime:/etc/localtime:ro
    -e ES_JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
    -e ES_HEAP_SIZE="2g"
    -e LS_HEAP_SIZE="1g"
    **-e ELASTICSEARCH_START=1 -e LOGSTASH_START=1 -e KIBANA_START=1 **
    --name docker-elk sebp/elk:es240_l240_k460
    && docker logs -f docker-elk
    </pre>
  • 其余两个点的启动关闭Kibana(KIBANA_START=0), 虚机配置是4c8g(相对高配置)
    <pre>
    docker run --privileged=true -i -d -p 5601:5601 -p 9200:9200 -p 9300:9300 -p 5044:5044 -p 5000:5000
    --net="host"
    -v ~/dockerdata/es/config/:/etc/elasticsearch/:rw
    -v ~/dockerdata/es/plugins/:/etc/elasticsearch/plugins/:rw
    -v ~/dockerdata/es/data/:/etc/elasticsearch/data/:rw
    -v ~/dockerdata/es/work/:/etc/elasticsearch/work/:rw
    -v ~/dockerdata/es/logs/:/var/log/elasticsearch/:rw
    -v ~/dockerdata/logstash/config/:/etc/logstash/conf.d/:rw
    -v ~/dockerdata/logstash/patterns/:/opt/logstash/patterns/:rw
    -v ~/dockerdata/logstash/logs/:/var/log/logstash/:rw
    -v ~/dockerdata/kibana/config/:/opt/kibana/config/:rw
    -v ~/dockerdata/kibana/logs/:/var/log/kibana/:rw
    -v /etc/localtime:/etc/localtime:ro
    -e ES_JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
    -e ES_HEAP_SIZE="4g"
    -e LS_HEAP_SIZE="2g"
    **-e ELASTICSEARCH_START=1 -e LOGSTASH_START=1 -e KIBANA_START=0 **
    --name docker-elk sebp/elk:es240_l240_k460
    && docker logs -f docker-elk
    </pre>

打开下面网址校验安装成功与否:
Kibana Web : http://<your-host>:5601
Elasticsearch Json : http://<your-host>:9200/
ES的插件安装请自己进入docker然后下载, 比较好用的有 head, hq 等

四、Filebeat5 的安装

这个最简单了,官网上下载 filebeat-5.0.0-rc1-linux-x86_64.tar.gz 解压安装;

<pre>
vi /usr/local/src/filebeat5/filebeat.yml
编辑内容如下:

################### Filebeat Configuration Example #########################
############################# Filebeat ######################################
filebeat.prospectors:

Each - is a prospector. Below are the prospector specific configurations

  • input_type: log
    paths: ["/usr/local/src/logs/${appname}-${cellname}-${nodename}/sys-.log"]
    encoding: utf-8
    exclude_files: ['.
    \d{4}-\d{2}-\d{2}.*.log']

    document_type: syslog
    fields:
    mlogapp: ${appname}

    fields_under_root: true
    scan_frequency: 1s
    ignore_older: 30m

must set ignore_older to be greater than close_inactive.

close_inactive: 5m
close_removed: true
clean_removed: true

multiline:
pattern: ^[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}[[:blank:]][[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}.[[:digit:]]{3}]
negate: true
match: after
max_lines: 500

output.kafka:

initial brokers for reading cluster metadata

hosts: ["192.168.0.1:9092", "192.168.0.2:9092", "192.168.0.3:9092"]

message topic selection + partitioning

topic: '%{[type]}'
partition.round_robin:
reachable_only: false

required_acks: 1
compression: gzip
max_message_bytes: 1000000

############################# Logging #########################################

logging.level: info
logging.to_files: true
logging.to_syslog: false
logging.files:
path: /usr/local/logs/filebeat
name: filebeat.log
keepfiles: 7
.
.
.


启动Filebeat5:
export appname="uss-web" && export cellname="cell01" && export nodename="node01"
&& cd /usr/local/src/filebeat/
&& nohup ./filebeat -e > /usr/local/src/logs/filebeat/nohup.out 2>&1 &
</pre>

以上就是目前安装所有的配置说明了,当然里面的很多细节都需要好好琢磨的,有问题就看官方文档吧,比搜索出来的文章都要靠谱。

备注个信息
为什么文中docker启动都是用的--net=host共享主机地址的参数?不考虑安全或物理隔离的需求,这是elasticsearch 2.x版本的一个改动坑,2.x后es会默认绑定loopback的IP地址,到docker这里看就是docker的虚拟网卡地址了,而我们的es要提供服务明显需要我们虚机的真正地址,对于网络配置不是特别精通,谁有更优雅的方案,欢迎评论指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容