2013年以來docker迅速火了起來颤殴,它的理念帶來了非常大的便利性杭跪,不過在實際應(yīng)用過程中會發(fā)現(xiàn)還有各種各樣的問題需要我們自己解決完善通惫,例如:日志茂翔、監(jiān)控、網(wǎng)絡(luò)等等履腋,本文會結(jié)合實例分享容器日志的管理經(jīng)驗珊燎。
1.日志系統(tǒng)簡介
日志收集是大數(shù)據(jù)的基礎(chǔ),為了許多公司的業(yè)務(wù)平臺每天都會產(chǎn)生大量的日志數(shù)據(jù)遵湖,為了實現(xiàn)數(shù)據(jù)分析悔政,需要將生產(chǎn)服務(wù)器上的所有日志收集后進(jìn)行大數(shù)據(jù)處理分析,高可用性延旧,高可靠性和可擴(kuò)展性是日志收集系統(tǒng)所必備的要素谋国。ELK是現(xiàn)在比較流行的日志一體化解決方案,提供了日志收集芦瘾、處理、存儲集畅、搜索近弟、展示等功能藐吮。但是因為容器的隔離性,收集容器內(nèi)的日志很不方便哄陶,對于容器標(biāo)準(zhǔn)輸出日志的話我們最常用的查詢方式是通過docker命令 docker logs containerid來查看docker的日志帆阳。但是當(dāng)面對一個大型的系統(tǒng)面對成百上千甚至更多的時候,我們是不可能通過單一的命令對日志進(jìn)行管理的屋吨,所以我們需要一個對于容器日志統(tǒng)一檢索管理的方案蜒谤。基于ELK我們實現(xiàn)了一套自己的容器日志管理方案至扰,如圖:
2.日志采集
傳統(tǒng)的日志采集有一些比較成熟解決方案鳍徽,例如:flume、logstash等等敢课,但是對于容器的日志這樣采集是非常不方便的阶祭。docker本身提供了log driver的功能,可以利用不同的driver把日志輸出到不同的地方直秆,logdriver具體有以下幾種:
- none
- json-file
- syslog
- journals
- self
- fluent
- awslogs
- splunk
- etwlogs
- gcplogs
docker默認(rèn)的logdriver是json-file胖翰,是把日志以json文件的方式存儲在本地,none是把日志設(shè)置成不在輸出切厘,syslog可以把標(biāo)準(zhǔn)輸出的日志通過syslog的方式傳輸出去萨咳,對于這些logdriver就不一一詳細(xì)介紹了,大家有興趣可以去docker官網(wǎng)查看疫稿∨嗨可見docker對于日志的處理還是提供了比較豐富的處理方式。另外還有一些比較優(yōu)秀的開源項目例如logspout等也為我們提供了更多的選擇遗座。然而這并不是我們想要的最終結(jié)果舀凛,如果只是對于容器的標(biāo)準(zhǔn)輸出日志我們可以從其中選擇一種認(rèn)為對自己合適的方式,通過收集需求其實對于傳統(tǒng)用戶它們比較接受的方式還是文件輸出日志途蒋,所以對于這種容器內(nèi)的文件日志docker并沒有提供采集的能力猛遍,如果通過把日志內(nèi)的文件掛載出來進(jìn)行采集,對于多個實例同名日志將會混在一起無法區(qū)分,所以我們需要一種無感知的方式能夠同時收集容器內(nèi)的文件日志懊烤,這其中還包括一些多行錯誤日志處理等功能梯醒。所以現(xiàn)在是自己動手豐衣足食的時候。
(1).標(biāo)準(zhǔn)日志輸出
數(shù)人云的調(diào)度環(huán)境是marathon+mesos腌紧。針對數(shù)人云的環(huán)境我們開發(fā)了自己的日志采集工具茸习。docker的標(biāo)準(zhǔn)輸出日志json-file默認(rèn)持久化在本地上,除了這一份以外mesos同樣對于標(biāo)準(zhǔn)輸出日志也存了一份在sandbox下面:
所以對于標(biāo)準(zhǔn)輸出日志也可以通過mesos文件的方式進(jìn)行采集壁肋。
(2).容器內(nèi)文件日志
數(shù)人云支持的文件存儲是overlay号胚,避免了許多復(fù)雜環(huán)境的處理。關(guān)于overlay這里盜用一張圖:
容器的存儲驅(qū)動運用的是寫時復(fù)制(Copy On Write)浸遗,overlay主要分為lower和upper, 當(dāng)需要修改一個文件時猫胁,使用CoW將文件從只讀的lower層復(fù)制到可寫層upper層進(jìn)行修改,在docker中跛锌,底部的只讀層是image杜漠,可寫層是container,因此容器內(nèi)的文件日志在宿主機(jī)上通過upper層的文件存儲系統(tǒng)是可以找到的察净,例如我在容器內(nèi)的/var/log/test.log中寫了一個test字符驾茴,如圖:
所以無論是標(biāo)準(zhǔn)輸出日志還是容器內(nèi)的文件日志,都可以通過文件的方式進(jìn)行采集處理氢卡,也可以同時把logdriver關(guān)閉可以減輕docker本身的壓力锈至。
3.數(shù)人云日志采集
基于上述方式開發(fā)了一個日志采集工具對日志進(jìn)行統(tǒng)一收集管理,日志最后通過tcp把json格式化的日志輸出到logstash译秦。其中包括應(yīng)用id峡捡,容器name,容器id筑悴,taskid等等们拙,當(dāng)然開發(fā)的過程中也遇到許多其他的問題,例如:日志的斷點續(xù)傳和多行錯誤日志進(jìn)行合并等等阁吝,這其中參考了elastic的filebeat對于日志的處理方式砚婆,filebeat是采用go開發(fā)的,個人認(rèn)為如果對于傳統(tǒng)日志文件進(jìn)行處理filebeat是一個不錯的選擇突勇,對這個工具進(jìn)行了簡單的測試對于穩(wěn)定可靠性方面感覺做的不錯装盯。數(shù)人云日志采集器功能第一步支持:
- 容器標(biāo)準(zhǔn)輸出日志采集
- 容器內(nèi)文件日志采集,支持同時采集多個文件
- 斷點續(xù)傳 (如果agent崩潰甲馋,從上次offset采集)
- 多行日志合并 (如:多行錯誤日志合并)
- 日志文件異常處理 (如:日志被rotate可以重新采集)
- tcp傳輸
- --add-env --add-label標(biāo)簽埂奈,可以通過指定命令把container的env或者label加到日志數(shù)據(jù)里,如(--add-env hostname=HOST --add-env test=ENV_NAME1 --* add-label tlabel=label_name)
- prometheus指標(biāo)數(shù)據(jù)
日志處理需要提供快速的數(shù)據(jù)處理能力定躏,在開發(fā)的過程中發(fā)現(xiàn)程序遇到了程序性能問題账磺,發(fā)現(xiàn)cpu占用非常高芹敌,對程序作了一個調(diào)優(yōu)的工作,使用的是golang內(nèi)置的包net/http/pprof垮抗,對于golang程序調(diào)優(yōu)非常好用氏捞,可以把程序中每個函數(shù)占用cpu內(nèi)存的比例通過生成svg的方式非常直觀的反映出來,這里再次盜用一站圖(與日志采集程序無關(guān)):
最后發(fā)現(xiàn)golang內(nèi)置包encoding/json json的序列化借宵、正則、反射矾削、字節(jié)轉(zhuǎn)字符串對于資源的消耗比較高壤玫,針對這幾個方面以及程序本身進(jìn)行了調(diào)整。
4.后端架構(gòu)介紹
對于日志匯聚功能有很多方案logstash哼凯、heka欲间、fluentd等,logstash是基于ruby的断部,支持功能非常豐富猎贴,但是性能方面應(yīng)該是大家詬病最多的地方。fluentd也是基于ruby的蝴光,沒有做過對比她渴。heka基于go,性能方面比logstash好很多,不過heka好像已經(jīng)不維護(hù)了蔑祟。綜合考慮到社區(qū)活躍度趁耗、迭代速度以及穩(wěn)定性方面最終選擇了logstash,實際應(yīng)用過程中有幾個比較重要的參數(shù):
- --pipeline-workers (命令行參數(shù))
- --pipeline-batch-size (命令行參數(shù))
- LS_HEAP_SIZE=${LS_HEAP_SIZE} (根據(jù)自己的實際情況填寫疆虚,可以寫到環(huán)境變量活著命令行參數(shù)里面)
- workers => 8 (根據(jù)自己實際情況苛败,一般等于cpu數(shù),配置文件參數(shù))
- flush_size => 3000 (根據(jù)自己的實際情況測試)
針對以上參數(shù)可以根據(jù)自己的實際環(huán)境進(jìn)行調(diào)試径簿。
如果日志量較大罢屈,考慮到架構(gòu)的穩(wěn)定性可以在中間加一層消息隊列,比較常用的應(yīng)該是kafka篇亭、redis等缠捌,相信大家對這方面的應(yīng)用比較多,這里不在贅述译蒂。
es應(yīng)該是索引存儲的不二選擇鄙币,整個架構(gòu)的緩解包括es通過docker的方式部署,壓測時用marvel對es的索引方式監(jiān)控蹂随,對于es網(wǎng)上也有很多調(diào)優(yōu)的文章十嘿,可自行實驗。日志的展示是通過自己定制的岳锁,kibana本身的功能比較強(qiáng)大的同時也略微有些學(xué)習(xí)成本绩衷,最終客戶想要的是很簡單的東西。
壓測工具選擇的是分布式壓測工具tsung,通過壓測一個應(yīng)用產(chǎn)生日志然后通過log-agent對日志進(jìn)行采集咳燕,模擬真實環(huán)境日志采集勿决。
5.日志告警
通過需求收集,對于日志處理有根據(jù)關(guān)鍵字報警的功能招盲,對于監(jiān)控報警這塊我們主要是采用的prometheus+alertmanager實現(xiàn)的低缩。應(yīng)用運行過程中,根據(jù)日志關(guān)鍵字告警部的應(yīng)用場景曹货,從logstash部分對日志做分流咆繁,具體方案可以看上面圖的報警部分,自研g(shù)rok_export對于日志進(jìn)行過濾分析生成prometheus格式的數(shù)據(jù)顶籽,然后從prometheus配置報警策略通過alertmanager報警玩般。log-agent本身也支持prometheus數(shù)據(jù),prometheus通過特定的規(guī)則查看日志的統(tǒng)計信息礼饱。
- prometheus:
prometheus是開源的監(jiān)控告警系統(tǒng),通過pull的方式采集時間序列坏为,以及用http傳輸,數(shù)據(jù)存儲在本地镊绪,支持豐富的查詢語法和簡單的dashboard展示匀伏。 - alertmanager:
alertmanager作為prometheus的組件,所有達(dá)到閥值的時間都通過alertmanager報警蝴韭,alertmanager支持非常強(qiáng)大的告警功能帘撰,包括http,email通知,以及靜默重復(fù)報警屏蔽等功能万皿。