引子
Docker的應(yīng)用為我們帶來(lái)便利的同時(shí)图贸,日志集中化問(wèn)題就越來(lái)越有必要性了。
Docker的日志處理
在收集之前,我們先來(lái)簡(jiǎn)單了解下docker日志處理的機(jī)制礁凡。當(dāng)啟動(dòng)一個(gè)容器的時(shí)候,它其實(shí)是docker daemon的一個(gè)子進(jìn)程慧妄,docker daemon可以拿到你容器里面進(jìn)程的標(biāo)準(zhǔn)輸出顷牌,拿到標(biāo)準(zhǔn)輸出后,它會(huì)通過(guò)自身的一個(gè)LogDriver模塊來(lái)處理塞淹,LogDriver支持的方式很多窟蓝,可以寫到本地的文件(默認(rèn)方式),可以發(fā)送到syslog等饱普,見(jiàn)下圖:
目前运挫,常見(jiàn)的收集方式有下面幾種:
-
應(yīng)用程序自行處理
這個(gè)好像并跟這次的主題沒(méi)有多少關(guān)系状共,比如:使用log4j可以將日志發(fā)送到遠(yuǎn)端的日志中心;
-
Docker Logging Driver
通過(guò)LogDriver將日志發(fā)送到不同的地方谁帕,目前官方支持的log driver類型如下:
-
旁路方式
利用docker API獲取日志的stream峡继,并發(fā)送到不同的地方。logspout 就是這個(gè)方式的一個(gè)開(kāi)源組件匈挖,另外碾牌,阿里云平臺(tái)的日志收集agent fluentd-pilot也是采用這種方案。
通過(guò)掛載volume的方式將容器內(nèi)的日志落地到宿主機(jī)关划,宿主機(jī)上通過(guò)日志采集agent采集小染,比較流行的agent有l(wèi)ogstash, fluentd等。
最佳實(shí)踐
在日志收集的過(guò)程中贮折,需要特別考慮性能的問(wèn)題裤翩。試想一下,當(dāng)容器的流量比較大的時(shí)候调榄,勢(shì)必日志也會(huì)隨著大量地產(chǎn)生踊赠,這時(shí)就會(huì)有個(gè)問(wèn)題,日志收集agent必然會(huì)跟容器搶占宿主機(jī)的資源每庆,為了避免這個(gè)問(wèn)題筐带,在收集選型的時(shí)候就需要注意:
- 限制日志收集agent使用的資源,這很容易就想到了docker容器的方式運(yùn)行agent缤灵,docker通過(guò)cgroup可以將一個(gè)容器的所使用的資源進(jìn)行完美的限制伦籍;
- docker logging driver的性能問(wèn)題,實(shí)測(cè)下來(lái)json-file(默認(rèn)方式腮出,寫文件到本地)效率是最高的帖鸦,fluentd logging driver, syslog logging driver會(huì)嚴(yán)重影響容器的QPS,容器QPS受后端日志收集agent處理快慢的影響胚嘲。
綜上所屬作儿,最佳實(shí)踐就是采用旁路模式來(lái)收集,并且使用容器方式來(lái)運(yùn)行并限定使用的資源馋劈;最終采用了logspout+Fluentd的方案(架構(gòu)圖見(jiàn)下)攻锰,采用的理由如下:
通過(guò)掛載volume的方式,無(wú)法取得容器運(yùn)行的一些元數(shù)據(jù)(container_id), 在我們的環(huán)境里妓雾,后續(xù)的日志處理會(huì)依賴這些元數(shù)據(jù)娶吞;
-
不方便為日志流添加一些自定義的字段;
logspout通過(guò)docker.sock監(jiān)聽(tīng)本地容器的啟動(dòng)君珠,通過(guò)docker API獲取到這個(gè)新容器的日志流寝志,并將這個(gè)日志流通過(guò)udp的協(xié)議發(fā)送給fluentd處理,fluentd處理完成后發(fā)送給后續(xù)的日志系統(tǒng)策添。
最后材部,受阿里云fluentd-pilot的影響,我將官方的logspout進(jìn)行一些小的修改唯竹,請(qǐng)見(jiàn):
-
日志采集的必需先聲明乐导,需要采集的容器需要在啟動(dòng)時(shí)添加label
docker run --label "xingren.log=true"
默認(rèn)采集docker env中的
MESOS_TASK_ID
, 因?yàn)槲覀兪褂玫膍arathon+mesos作為容器的平臺(tái),后續(xù)日志處理需要這個(gè)字段浸颓;
部署
下面?zhèn)€出個(gè)docker-compose.yml, 通過(guò)docker-compose up就可以運(yùn)行了物臂;
version: "2"
services:
logspout:
image: techwong/logspout
restart: on-failure
environment:
# 這個(gè)是發(fā)送給fluentd的日志內(nèi)容模版,JSON格式
RAW_FORMAT: '{ "container_id" : "{{ .Container.ID }}", "labels": {{ toJSON .Container.Config.Labels }}, "timestamp": "{{ .Time.Format "2006-01-02T15:04:05Z07:00" }}", "source" : "{{ .Source }}", "log": {{ toJSON .Data }}, "MESOS_TASK_ID": {{ getMESOS_TASK_ID .Container.Config.Env }} }'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "24222:80"
command: raw://fluent:5160
depends_on:
- fluent
cpu_quota: 30000 # 限制CPU資源
restart: always
fluent:
image: fluent/fluentd:v0.12
volumes:
- ./fluent:/fluentd/etc
ports:
- "24221:24221"
environment:
LOGSPOUT: ignore
FLUENTD_CONF: docker_log_collect.conf
cpu_quota: 30000
restart: always
fluent的簡(jiǎn)單配置:
<source>
@type udp
tag docker
format json
port 5160
</source>
<match docker>
@type stdout
</match>
最后产上,可以通過(guò)查看fluent的log來(lái)查看格式化的容器日志棵磷;