fluentd是一個(gè)開源的日志收集系統(tǒng),能夠收集各式各樣的日志, 并將日志轉(zhuǎn)換成方便機(jī)器處理的json格式蔓倍。
安裝
不同操作系統(tǒng)的安裝方式不同,具體可以參考:
另外在生產(chǎn)環(huán)境中安裝Fluentd之前,也需要對(duì)操作系統(tǒng)做一些配置睬罗,如:
- 設(shè)置好NTP時(shí)間同步
- 調(diào)整允許操作的文件符最大個(gè)數(shù)
- 優(yōu)化內(nèi)核中與網(wǎng)絡(luò)相關(guān)的參數(shù)等
具體配置可以參考:
本文為了便于快速測(cè)試患朱,直接使用fluentd的docker鏡像來啟動(dòng)fluentd服務(wù)鲁僚。
# 下載fluentd鏡像
$ docker pull fluent/fluentd:v1.7-1
準(zhǔn)備配置文件
首先創(chuàng)建一些簡單的文件方便測(cè)試。本文所有使用到的配置文件都已經(jīng)上傳到github,可以直接下載使用
$ git clone https://github.com/crazygit/fluentd_demo
當(dāng)然也可以自己動(dòng)手完成
$ mkdir fluentd_demo
# 注意: 本文后續(xù)所有命令都在fluentd_demo目錄下執(zhí)行
$ cd fluentd_demo
# 創(chuàng)建用于保存fluentd的配置文件的etc目錄和保存日志文件的log目錄
$ mkdir -p etc log
# 再創(chuàng)建一個(gè)簡單的配置文件
$ cat etc/fluentd_basic_setup.conf
<source>
@type http
port 8888
bind 0.0.0.0
</source>
<match test.cycle>
@type stdout
</match>
配置文件解釋:
source
部分使用了http
輸入插件裁厅,在8888
端口啟動(dòng)一個(gè)web服務(wù)用于收集日志match
部分定義只要日志匹配test.cycle
標(biāo)簽冰沙,就將日志輸出到標(biāo)準(zhǔn)輸出
目前不用太關(guān)心配置文件的格式,后面會(huì)有詳細(xì)的介紹执虹。
創(chuàng)建好的目錄結(jié)構(gòu)如下:
$ tree
.
├── etc
│ └── fluentd_basic_setup.conf
└── log
啟動(dòng)容器
$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc -v $(pwd)/log:/fluentd/log fluent/fluentd:v1.7-1 -c /fluentd/etc/fluentd_basic_setup.conf -v
命令參數(shù)解釋如下:
-
-p
參數(shù)映射容器的8888
端口到宿主機(jī)的8888
端口拓挥,方便我們直接從宿主機(jī)直接訪問容器 - 第一個(gè)
-v
參數(shù)用于掛載本地的etc
目錄到容器內(nèi)的etc
目錄,讓容器能夠使用本地的配置文件 - 第二個(gè)
-v
參數(shù)用于掛載本地的log
目錄到容器內(nèi)的log
目錄声畏,便于保存輸出的日志文件 -
-c
參數(shù)用于設(shè)置容器內(nèi)的fluentd
時(shí)候啟動(dòng)的使用/fluentd/etc/fluentd_basic_setup.conf
配置文件 - 最后一個(gè)參數(shù)
-v
用于設(shè)置容器內(nèi)的fluentd
時(shí)候啟動(dòng)的開啟verbose
模式撞叽,便于調(diào)試發(fā)現(xiàn)問題。
正常啟動(dòng)后插龄,能看到如下輸出
fluentd -c /fluentd/etc/fluentd_basic_setup.conf -v
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: parsing config file is succeeded path="/fluentd/etc/fluentd_basic_setup.conf"
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: using configuration file: <ROOT>
<source>
@type http
port 8888
bind "0.0.0.0"
</source>
<match test.cycle>
@type stdout
</match>
</ROOT>
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: starting fluentd-1.7.4 pid=6 ruby="2.5.7"
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: spawn command to main: cmdline=["/usr/bin/ruby", "-Eascii-8bit:ascii-8bit", "/usr/bin/fluentd", "-c", "/fluentd/etc/fluentd_basic_setup.conf", "-v", "-p", "/fluentd/plugins", "--under-supervisor"]
2019-11-27 02:03:23 +0000 [info]: fluent/log.rb:322:info: gem 'fluentd' version '1.7.4'
2019-11-27 02:03:23 +0000 [info]: fluent/log.rb:322:info: adding match pattern="test.cycle" type="stdout"
2019-11-27 02:03:23 +0000 [info]: fluent/log.rb:322:info: adding source type="http"
2019-11-27 02:03:23 +0000 [info]: #0 fluent/log.rb:322:info: starting fluentd worker pid=14 ppid=6 worker=0
2019-11-27 02:03:23 +0000 [debug]: #0 fluent/log.rb:302:debug: listening http bind="0.0.0.0" port=8888
2019-11-27 02:03:23 +0000 [info]: #0 fluent/log.rb:322:info: fluentd worker is now running worker=0
另外愿棋,也可以通過環(huán)境變量FLUENTD_CONF
設(shè)置需要使用的配置文件
# 下面的命令和上面的是等效的
$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc/ -e FLUENTD_CONF=fluentd_basic_setup.conf fluent/fluentd:v1.7-1
測(cè)試
# 任意偽造一個(gè)用戶登錄的日志,向fluentd服務(wù)提交日志
$ 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
在fluentd
的容器里能看到如下輸出
2019-11-27 02:05:16.583154500 +0000 test.cycle: {"action":"login","user":2}
Fluentd事件的生命周期
什么是事件(Event)
正如開篇提到過均牢,F(xiàn)luentd是一個(gè)日志收集系統(tǒng)糠雨,那么一條日志消息,在Fluentd里就認(rèn)為是一個(gè)事件(Event
)徘跪。
事件結(jié)構(gòu)
Fluentd的事件由下面三部分組成
- 標(biāo)簽(
tag
): 用于說明這個(gè)事件是哪里產(chǎn)生的甘邀,可用于后面的事件路由 - 時(shí)間(
time
): 事件是什么時(shí)候發(fā)生的,時(shí)間格式為: Epoch time, 即Unix時(shí)間戳 - 記錄(
record
): 事件內(nèi)容本身垮庐,JSON格式
所有的輸入插件都需要解析原始日志松邪,生成滿足上面結(jié)構(gòu)的事件字段,比如哨查,一條Apache的訪問日志:
192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777
通過in_tail
輸入插件處理之后逗抑,將會(huì)得到下面的輸出
tag: apache.access # 由配置文件指定
time: 1362020400 # 28/Feb/2013:12:00:00 +0900
record: {"user":"-","method":"GET","code":200,"size":777,"host":"192.168.0.1","path":"/"}
事件的處理流程
當(dāng)fluentd收到一個(gè)事件之后,會(huì)經(jīng)過一系列的處理流程:
- 如修改事件的相關(guān)字段
- 過濾掉一些不關(guān)心的事件
- 路由事件輸出到不同的地方
下面將一一介紹介紹事件的處理流程
過濾器(Filter)
Filter用于定義一個(gè)事件是該被接受或者是被過濾掉(拋棄掉)。使用示例如下:
$ cat etc/fluentd_filter_demo.conf
<source>
@type http
port 8888
bind 0.0.0.0
</source>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^logout$
</exclude>
</filter>
<match test.cycle>
@type stdout
</match>
上面的示例配置了讓我們直接過濾掉用戶logout
的事件邮府。
重啟fluentd,使用上面的定義的配置文件
$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc -v $(pwd)/log:/fluentd/log fluent/fluentd:v1.7-1 -c /fluentd/etc/fluentd_filter_demo.conf -v
測(cè)試
$ 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
我們向fluentd發(fā)送了兩個(gè)事件荧关,分別是用戶login
和logout
的事件。
檢查fluend
的輸出
2019-11-27 03:38:28.973757600 +0000 test.cycle: {"action":"login","user":2}
可以看到只輸出了用戶login
的事件褂傀,logout
事件被過濾掉了忍啤。
標(biāo)識(shí)符(Labels)
從前面的例子里,我們可以看到仙辟,fluentd
的處理流程是根據(jù)我們?cè)谂渲梦募械亩x同波,從上到下依次執(zhí)行的。假如我們?cè)谂渲梦募锒x了比較多輸入源叠国,不同的輸入源需要使用不同的filters時(shí)参萄,如果仍然按照從上到下執(zhí)行的順序的話,由于不同的處理需求煎饼,我們的配置文件可能變得非常復(fù)雜。
通過label
校赤,我們可以為不同的輸入源指定不同的處理流程吆玖,示例如下:
$ cat etc/fluentd_labels.conf
<source>
@type http
bind 0.0.0.0
port 8888
@label @STAGING # 注意這里我們添加了label
</source>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^login$
</exclude>
</filter>
<label @STAGING>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^logout$
</exclude>
</filter>
<match test.cycle>
@type stdout
</match>
</label>
上面的示例文件里,我們首先定義了一個(gè)filter過濾掉login
事件
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^login$
</exclude>
</filter>
接著又在label
塊里面過濾掉了logout
事件
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^login$
</exclude>
</filter>
如果按照從上到下的順序執(zhí)行马篮,那么我們將看不到任何login
和logout
的事件沾乘。但是實(shí)際結(jié)果如何呢?讓我們來測(cè)試一下浑测。
使用上面定義的配置文件啟動(dòng)fluentd
$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc -v $(pwd)/log:/fluentd/log fluent/fluentd:v1.7-1 -c /fluentd/etc/fluentd_labels.conf -v
提交事件來測(cè)試, 同樣向fluentd發(fā)送兩個(gè)事件翅阵,分別是用戶login
和logout
的事件。
$ 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
查看fluentd輸出
2019-11-27 03:51:45.088464900 +0000 test.cycle: {"action":"login","user":2}
可以看到迁央,只有logout
事件被過濾了掷匠,原因是我們?yōu)檩斎朐O(shè)置了label
<source>
@type http
bind 0.0.0.0
port 8888
@label @STAGING # 注意這里我們添加了label
</source>
因此跳過中間設(shè)置的一些filter,只運(yùn)行了<label @STAGING>...</lable>
標(biāo)簽塊里的filter
緩沖區(qū)(Buffers)
在前面的例子中岖圈,我們使用的都是stdout
這樣一個(gè)沒有緩沖區(qū)的輸出讹语,在生產(chǎn)環(huán)境中,我們用到的輸出基本都是有緩沖區(qū)
的,比如s3
, forward
,mongodb
等蜂科,這些輸出插件在收到事件之后顽决,會(huì)將事件先保存到緩沖區(qū),然后等滿足特定條件之后导匣,再將事件輸出到目標(biāo)輸出才菠。
配置文件語法
配置文件由一下幾部分組成
配置文件中的術(shù)語
-
source
: 指定輸入源例如:
# 在24224端口接受TCP事件 <source> @type forward port 24224 </source> <source> @type http port 9880 </source>
輸入源可以一次指定多個(gè),
@type
參數(shù)指定使用哪一個(gè)輸入插件贡定。
fluentd支持各種輸入插件, 比如:- in_tail
- in_forward
- in_udp
- in_tcp
- in_unix
- in_http
- in_syslog
- in_exec
- in_dummy
- in_windows_eventlog
插件的具體使用可以參考文檔:
https://docs.fluentd.org/input -
match
: 指定輸出的目的地例如:
# 將滿足myapp.acccess標(biāo)簽的事件全部輸出到 # /var/log/fluent/access.%Y-%m-%d <match myapp.access> @type file path /var/log/fluent/access </match>
輸出也可以一次指定多個(gè)赋访,
@type
參數(shù)指定使用哪一個(gè)輸出插件。
fluentd支持各種輸出插件, 比如:- out_copy
- out_null
- out_roundrobin
- out_stdout
- out_exec_filter
- out_forward
- out_mongo or out_mongo_replset
- out_exec
- out_file
- out_s3
- out_webhdfs
插件的具體使用可以參考文檔:
https://docs.fluentd.org/output -
filter
: 指定事件的處理流程可以多個(gè)filter串聯(lián)起來,比如:
Input -> filter 1 -> ... -> filter N -> Output
例如:
<filter myapp.access> @type record_transformer <record> host_param "#{Socket.gethostname}" </record> </filter>
上面的
filter
會(huì)添加host_param
參數(shù)到事件fluentd也內(nèi)置了各種
filter
, 比如:- grep
- record-transformer
- filter_stdout
- geoip
- parser
filter的具體使用可以參考文檔:
-
system
: 指定系統(tǒng)級(jí)別的配置可以設(shè)置的參數(shù)有
- log_level
- suppress_repeated_stacktrace
- emit_error_log_interval
- suppress_config_dump
- without_source
- process_name (only available in system directive. No fluentd option)
例如:
<system> # equal to -qq option log_level error # equal to --without-source option without_source # ... </system>
-
label
: 用于分組特定的filter和match例如:
<source> @type forward </source> <source> @type tail @label @SYSTEM </source> <filter access.**> @type record_transformer <record> # ... </record> </filter> <match **> @type elasticsearch # ... </match> <label @SYSTEM> <filter var.log.middleware.**> @type grep # ... </filter> <match **> @type s3 # ... </match> </label>
上面的配置文件中:
in_forward
的事件將經(jīng)過record_transformer
過濾器和elasticsearch
輸出进每。in_tail
輸入的事件將經(jīng)過grep
過濾器和s3
輸出汹粤。
另外: <label @ERROR>
屬于內(nèi)置的配置,用于保存內(nèi)部錯(cuò)誤田晚,比如:
緩沖區(qū)已經(jīng)滿了或者無效的事件等嘱兼。
-
@include
: 引入其它的配置文件∠屯剑可以將配置文件拆分為多個(gè)芹壕,便于復(fù)用。當(dāng)要使用的時(shí)候接奈,直接使用@include
引入即可踢涌,例如:# 通過絕對(duì)路徑引入 @include /path/to/config.conf # 通過相對(duì)路徑引入,相對(duì)于當(dāng)前配置文件的路徑 @include extra.conf # 模糊匹配序宦,所有符合條件的會(huì)根據(jù)文件名的字母順序依次導(dǎo)入 # 比如: a.conf, b.conf, ..., z.conf # 因此, 要注意各個(gè)配置文件不應(yīng)該有順#序依賴睁壁,如果有順序依賴,請(qǐng)明確指出導(dǎo)入的文件名 @include config.d/*.conf # 使用在線的配置 @include http://example.com/fluent.conf
@include
指定也可以用于導(dǎo)入相關(guān)的參數(shù)信息互捌,比如:有如下配置文件
<match pattern> @type forward # other parameters... <buffer> @type file path /path/to/buffer/forward @include /path/to/out_buf_params.conf </buffer> </match> <match pattern> @type elasticsearch # other parameters... <buffer> @type file path /path/to/buffer/es @include /path/to/out_buf_params.conf </buffer> </match>
參數(shù)配置文件
/path/to/out_buf_params.conf
flush_interval 5s total_limit_size 100m chunk_limit_size 1m
配置文件的模式匹配(patterns)
通配符
如前面的示例可以看到潘明,fluented主要根據(jù)事件的tag來分區(qū)不同的處理流程
雖然我們可以明確指定需要處理的tag,比如:<filter app.log>
來指定只處理tag為app.log
的事件秕噪。我們也可以在filter
和match
中通過通配符钳降,來處理同一類tag的事件
tag通常是一個(gè)字符串,由.
分隔腌巾,比如myapp.access
*
: 匹配滿足一個(gè)tag部分的事件, 比如:a.*
, 它將匹配a.b
這樣的tag, 但是不會(huì)處理a
或者a.b.c
這類tag**
: 匹配滿足0個(gè)或多個(gè)tag部分遂填,比如:a.**
, 它將匹配a
,a.b
,a.b.c
這三種tag-
{X, Y, Z}
: 匹配滿足X
,Y
或者Z
的tag, 比如:{a, b}
將匹配a
或者b
,但是不會(huì)匹配c
。這種格式也可以和通配符組合使用,比如
a.{b.c}.*
或a.{b.c}.**
-
#{...}
會(huì)把花括號(hào)內(nèi)的字符串當(dāng)做是ruby
的表達(dá)式處理澈蝙。比如<match "app.#{ENV['FLUENTD_TAG']}"> @type stdout </match>
如果設(shè)置了環(huán)境變量
FLUENTD_TAG
為dev
,那上面等價(jià)于app.dev
-
當(dāng)指定了多個(gè)模式時(shí)(使用一個(gè)或多個(gè)空格分開),只要滿足其中任意一個(gè)就行吓坚。
比如:
<match a b>
匹配a
和b
<match a.** b.*>
匹配a
,a.b
,a.b.c
,b.d
等
多個(gè)match之間的順序注意
當(dāng)有多個(gè)match, 需要注意一下它們的順序, 如下面的例子灯荧,第二個(gè)match永遠(yuǎn)也不會(huì)生效
# ** matches all tags. Bad :(
<match **>
@type blackhole_plugin
</match>
<match myapp.access>
@type file
path /var/log/fluent/access
</match>
正確的寫發(fā)應(yīng)該是將確定的tag盡量寫在前面凌唬,模糊匹配的寫在后面。
<match myapp.access>
@type file
path /var/log/fluent/access
</match>
# Capture all unmatched tags. Good :)
<match **>
@type blackhole_plugin
</match>
如果需要將輸出到多個(gè)match,需要使用out_copy
插件漏麦。
另外需要注意順序的是filter
和match
, 如果將filter
放在match
之后客税,那么它也永遠(yuǎn)不會(huì)生效,正確的用法如下:
# You should NOT put this <filter> block after the <match> block below.
# If you do, Fluentd will just emit events without applying the filter.
<filter myapp.access>
@type record_transformer
...
</filter>
<match myapp.access>
@type file
path /var/log/fluent/access
</match>
常見的配置文件示例
下面給出了一些常見的使用場景的配置文件寫法
簡單的輸入撕贞,過濾更耻,輸出
<source>
@type forward
</source>
<filter app.**>
@type record_transformer
<record>
hostname "#{Socket.gethostname}"
</record>
</filter>
<match app.**>
@type file
# ...
</match>
多個(gè)輸入
<source>
@type forward
</source>
<source>
@type tail
tag system.logs
# ...
</source>
<filter app.**>
@type record_transformer
<record>
hostname "#{Socket.gethostname}"
</record>
</filter>
<match {app.**,system.logs}>
@type file
# ...
</match>
使用Label的輸出
<source>
@type forward
</source>
<source>
@type dstat
@label @METRICS # dstat events are routed to <label @METRICS>
# ...
</source>
<filter app.**>
@type record_transformer
<record>
# ...
</record>
</filter>
<match app.**>
@type file
# ...
</match>
<label @METRICS>
<match **>
@type elasticsearch
# ...
</match>
</label>
重新設(shè)置標(biāo)簽并重新路由(fluent-plugin-route插件的使用)
<match worker.**>
@type route
remove_tag_prefix worker
add_tag_prefix metrics.event
<route **>
copy # For fall-through. Without copy, routing is stopped here.
</route>
<route **>
copy
@label @BACKUP
</route>
</match>
<match metrics.event.**>
@type stdout
</match>
<label @BACKUP>
<match metrics.event.**>
@type file
path /var/log/fluent/bakcup
</match>
</label>
根據(jù)事件內(nèi)容重新路由(fluent-plugin-rewrite-tag-filter插件的使用)
<source>
@type forward
</source>
# event example: app.logs {"message":"[info]: ..."}
<match app.**>
@type rewrite_tag_filter
<rule>
key message
pattern ^\[(\w+)\]
tag $1.${tag}
</rule>
# you can put more <rule>
</match>
# send mail when receives alert level logs
<match alert.app.**>
@type mail
# ...
</match>
# other logs are stored into file
<match *.app.**>
@type file
# ...
</match>
重新路由事件到其它的Label(out_relabel插件的使用)
<source>
@type forward
</source>
<match app.**>
@type copy
<store>
@type forward
# ...
</store>
<store>
@type relabel
@label @NOTIFICATION
</store>
</match>
<label @NOTIFICATION>
<filter app.**>
@type grep
regexp1 message ERROR
</filter>
<match app.**>
@type mail
</match>
</label>
配置文件中的參數(shù)類型
在配置文件中使用的插件,大部分都可以接受1個(gè)或多個(gè)參數(shù)捏膨,也可以指定參數(shù)類型
string
: 字符串類型integer
: 整型float
: 浮點(diǎn)型-
size
: 字節(jié)(bytes)類型.為了便于閱讀秧均,它的值有幾種常見的寫法-
<INTEGER>k
或<INTEGER>K
表示使用單位KB
-
<INTEGER>m
或<INTEGER>M
表示使用單位M
-
<INTEGER>g
或<INTEGER>G
表示使用單位G
-
<INTEGER>t
或<INTEGER>T
表示使用單位T
- 純數(shù)字時(shí)表示使用默認(rèn)單位為
B
-
-
time
: 時(shí)間類型食侮,默認(rèn)單位為秒, 同樣為了便于閱讀目胡,它的值也有幾種常見的寫法-
<INTEGER>s
, 表示使用單位秒
-
<INTEGER>m
, 表示使用單位分鐘
-
<INTEGER>h
, 表示使用單位小時(shí)
-
<INTEGER>d
, 表示使用單位天
- 純數(shù)字時(shí)表示使用默認(rèn)單位為
秒
锯七,0.1
表示100ms
-
-
array
: 數(shù)組類型。有兩種寫法:- 完整格式的寫法:
["key1", "key2"]
- 簡寫:
key1,key2
- 完整格式的寫法:
-
hash
: 字典類型誉己。也有兩種寫法:- 完整格式的寫法:
{"key1":"value1", "key2":"value2"}
- 簡寫:
key1:value1,key2:value2
- 完整格式的寫法:
常見的參數(shù)
以@
開始的參數(shù)表示fluented的保留參數(shù)
-
@type
: 指定使用的參加類型 -
@id
: 指定插件的ID -
@label
: 指定事件的標(biāo)識(shí)符 -
@log_level
: 指定類型
模塊(section)支持
下面的模塊并不是所有的插件都支持眉尸,具體使用請(qǐng)結(jié)合使用的插件查看
-
parse
: 指明如何解析原始內(nèi)容,如解析nginx, apache日志等 -
buffer
: 配置如何緩沖輸出 -
format
: 配置如何格式化事件 -
extract
: 從事件中提取值 -
inject
: 向事件注入一些屬性 -
transport
: 用于指定某些插件的輸入輸出時(shí)server
的連接信息 -
storage
: 指定如何保存插件本身的狀態(tài)
每個(gè)模塊都有對(duì)應(yīng)的插件巨双,使用詳情可以查看官方文檔
檢查配置文件的格式
可以使用下面的命令檢查配置文件的格式是否正確
$ docker run --rm -v $(pwd)/etc:/fluentd/etc/ fluent/fluentd:v1.7-1 --dry-run -c /fluentd/etc/fluentd_basic_setup.conf
使用Fluentd收集docker容器的日志
docker容器日志格式
在使用fluentd收集docker日志時(shí)噪猾,默認(rèn)會(huì)將日志分成4個(gè)部分:
分別是:
-
container_id
: 容器的ID -
container_name
:容器的名字 -
source
: 日志的類型,stdout
或stderr
-
log
: 日志本身
收集Docker容器的日志示例
- 首先創(chuàng)建一個(gè)配置文件
etc/fluentd_docker.conf
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
<match **>
@type stdout
</match>
# 啟動(dòng)一個(gè)fluentd服務(wù)
$ docker run -it -p 24224:24224 -v $(pwd)/etc:/fluentd/etc/ -e FLUENTD_CONF=fluentd_docker.conf fluent/fluentd:v1.7-1
# 啟動(dòng)一個(gè)docker容器并使用fluentd收集日志
$ docker run --log-driver=fluentd -p 5000:80 httpd
# 訪問服務(wù)產(chǎn)生日志
$ curl http://127.0.0.1:5000
<html><body><h1>It works!</h1></body></html>
在fluentd的容器日志里筑累,能看到下面的輸出
2019-11-28 01:43:23.000000000 +0000 8da5b8365552: {"container_id":"8da5b8365552b4c0c610ff5df3dc28509bfc5781ec580628143b00cf997d5b72","container_name":"/confident_curie","source":"stdout","log":"172.17.0.1 - - [28/Nov/2019:01:43:23 +0000] \"GET / HTTP/1.1\" 200 45"}
在docker-compose中使用示例
為了介紹下對(duì)日志常用的處理場景袱蜡,這里將收集的日志分成三部分:
- 輸出到fluentd的容器的標(biāo)準(zhǔn)輸出,方便直接查看
- 保存一份到文件慢宗,按照日期自動(dòng)切割日志
- 保存一份到Elasticsearch坪蚁,方便通過Kibana面板直接查看
同時(shí)為了方便人查看,輸出到fluentd標(biāo)準(zhǔn)輸出和保存到日志文件的镜沽,只顯示log字段的信息(不用contanier_id
, container_name
等暫時(shí)不關(guān)心的信息)迅细,保存到Elastisearch的日志保存完整的結(jié)構(gòu)。
首先淘邻,根據(jù)我們上面的需求,創(chuàng)建fluentd配置文件
$ cat etc/fluentd_docker_compose.conf
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
# docker相關(guān)的日志處理
<match docker.**>
# docker相關(guān)的日志輸出三份湘换,一份輸出到fluentd容器的標(biāo)準(zhǔn)輸出宾舅,便于實(shí)時(shí)查看,另一份保存到文件, 還有一份保存到Elasticsearch
@type copy
# 輸出到標(biāo)準(zhǔn)輸出
<store>
@type stdout
# 默認(rèn)輸出的格式是json格式彩倚,由于docker生成的日志筹我,包含了容器信息等其他信息,不是很方便人去閱讀帆离。
# 這里只輸出我們關(guān)心的log字段
# 使用stdout作為主format蔬蕊,single_value為子format,這樣可以在輸出log的同時(shí)保留直接tag和time信息
<format>
@type stdout
output_type single_value
message_key log
add_newline true
</format>
</store>
# 輸出到文件
<store>
@type file
# 使用tag和日期作為保存日志的文件名
path /fluentd/log/${tag}/%Y%m%d
# 合并多個(gè)flush chunk塊到一個(gè)文件
append true
# 使用gzip壓縮生成的日志文件
compress gzip
<format>
@type stdout
output_type single_value
message_key log
add_newline true
</format>
# 使用文件作為緩沖區(qū)
<buffer tag, time>
@type file
chunk_limit_size 1M
# 每隔1分鐘寫一次日志
flush_interval 1m
flush_at_shutdown true
flush_mode interval
</buffer>
</store>
# 輸出到Eleastichsearch
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix fluentd
logstash_dateformat %Y%m%d
include_tag_key true
type_name access_log
tag_key @log_name
</store>
</match>
# 其它日志處理
<match **>
@type copy
<store>
@type stdout
</store>
# 輸出到others目錄
<store>
@type file
path /fluentd/log/others/${tag}/%Y%m%d
append true
<buffer tag, time>
@type file
chunk_limit_size 1M
flush_interval 1m
flush_at_shutdown true
flush_mode interval
</buffer>
</store>
</match>
由于使用到了elasticsearch輸出插件哥谷,而默認(rèn)的fluentd中并沒有安裝這個(gè)插件岸夯,因此,我們需要自己定義Dockfile
來安裝elasticsearch插件
$ cat fluentd/Dockerfile
FROM fluent/fluentd:v1.7-1
USER root
RUN ["fluent-gem", "install", "fluent-plugin-elasticsearch"]
USER fluent
最后創(chuàng)建docker-compose.yaml
文件
$ cat docker-compose.yaml
version: '3'
services:
httpd:
image: httpd
ports:
- "5000:80"
networks:
- webnet
depends_on:
- fluentd
logging:
driver: fluentd
options:
fluentd-address: "localhost:24224"
fluentd-retry-wait: '1s'
fluentd-max-retries: '10'
tag: docker.httpd
fluentd:
build: ./fluentd/
volumes:
- ./etc/:/fluentd/etc
- ./log/:/fluentd/log
ports:
- "24224:24224"
- "24224:24224/udp"
environment:
- FLUENTD_CONF=fluentd_docker_compose.conf
networks:
- webnet
depends_on:
- elasticsearch
- kibana
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.3
ports:
- "9200:9200"
networks:
- webnet
ports:
- "9200:9200"
- "9300:9300"
environment:
- discovery.type=single-node
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- http.host=0.0.0.0
- transport.host=127.0.0.1
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- es_data:/usr/share/elasticsearch/data
kibana:
image: docker.elastic.co/kibana/kibana-oss:6.2.3
environment:
SERVER_NAME: kibana-server
ELASTICSEARCH_URL: http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- webnet
networks:
webnet:
volumes:
es_data:
driver: local
最后啟動(dòng)服務(wù)
$ docker-compose up --build
實(shí)際使用中發(fā)現(xiàn)们妥,采用上面的方式啟動(dòng)服務(wù)后猜扮,有時(shí)間fluentd沒法收集到httpd服務(wù)的日志,最后發(fā)現(xiàn)原因是如果在fluentd服務(wù)還沒準(zhǔn)備就緒的情況下就啟動(dòng)httpd服務(wù)监婶,就會(huì)產(chǎn)生這種現(xiàn)象旅赢。因此齿桃,建議的做法是先啟動(dòng)fluentd, 再啟動(dòng)httpd
$ docker-compose up --build fluentd
# 等fluentd服務(wù)就緒后,再啟動(dòng)httpd服務(wù)
$ docker-compose up httpd
當(dāng)然更優(yōu)雅點(diǎn)的做法是控制docker-compose中服務(wù)的啟動(dòng)順序煮盼,具體可以參考:
https://docs.docker.com/compose/startup-order/
測(cè)試短纵,訪問 httpd服務(wù)
# 可以多執(zhí)行幾次,產(chǎn)生多一些訪問記錄
$ curl http://127.0.0.1:5000
最后可以分別在fluentd的容器的終端僵控,log目錄香到,以及elasticsearch中看到保存的訪問記錄信息了。如下是通過Kibana面板看到的請(qǐng)求情況
更多
更多關(guān)于Fluentd的使用方式可以參考官方文檔