快速搭建 ELK + Docker + Gunicorn + Flask 日志統(tǒng)一收集平臺(tái)

以下文章來(lái)源于:https://blog.csdn.net/u014720624/article/details/89308649
作者:CSDN博主「jeff_yxj」

目前生產(chǎn)環(huán)境的日志基本都是采用 Flask 文件日志寫(xiě)入 + Gunicorn 文件日志寫(xiě)入 + logrotate做按日切割,日志文件保留30天的數(shù)量鲤桥,這樣的方案比較適合簡(jiǎn)單的場(chǎng)景褐鸥,長(zhǎng)時(shí)間下來(lái)就有以下幾個(gè)問(wèn)題:

服務(wù)程序都是分布式部署,所以每個(gè)服務(wù)器都有自己的本地日志脚囊,如果有問(wèn)題需要查看日志,需要連接到每個(gè)服務(wù)器來(lái)查看
日志是按日切割的,所以排查日志跨度比較大曹锨,則需要查看多個(gè)日志文件切換排查
日志下載則受限服務(wù)器出口帶寬下載慢临扮,在線查看vim的搜索機(jī)制比較單一
所以根據(jù)資料查詢论矾,目前確定將日志都統(tǒng)一使用 ELK 收集, 對(duì)于以上的問(wèn)題都有比較好的解決杆勇,除此之外還可以保留更長(zhǎng)時(shí)間的日志及美觀的可視化操作贪壳,ElasticSearch提供比較優(yōu)秀的開(kāi)源關(guān)鍵字搜索,而且這個(gè)方案已經(jīng)被很多人驗(yàn)證蚜退,又有商業(yè)公司專門維護(hù)開(kāi)源版本闰靴,所以是一個(gè)很好的選擇。

  1. 服務(wù)器版本是 Centos 7.2 版本关霸,ELK 則直接使用 Docker 來(lái)安裝传黄,并且可以通過(guò)Docker直接托管進(jìn)程,非常的方便队寇。我們使用的是一個(gè)開(kāi)源的 ELK 鏡像配置項(xiàng)目,該項(xiàng)目要求 Docker 17.05+


yum自帶的Docker 版本比較低章姓,需要安裝更新版本的 Docker佳遣,如果已經(jīng)安裝了舊版本的Docker,需要先手動(dòng)卸載

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine

然后安裝Docker 必須的依賴庫(kù)及凡伊、添加Dokcer官方的yum源及安裝 Docker

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
 
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
 
$ sudo yum install -y docker-ce

安裝完成后輸入docker -v 可以查看 Docker 的版本

$ docker -v
Docker version 18.09.4-rc1, build 9d6081e

將 Docker 配置為開(kāi)機(jī)自動(dòng)啟動(dòng)

$ systemctl enable docker
$ systemctl daemon-reload
 
$ systemctl start docker
  1. 安裝完成后需要開(kāi)始安裝 ELK零渐,這里我們使用ELK的一個(gè)開(kāi)源Docker 配置項(xiàng)目,該項(xiàng)目提供 Docker-compose 的編排腳本方便統(tǒng)一管理系忙,github地址是:https://github.com/deviantony/docker-elk#how-can-i-tune-the-elasticsearch-configuration

可以下載也可以直接使用git將此項(xiàng)目clone到本地诵盼,另外項(xiàng)目啟動(dòng)需要安裝docker-compose,這個(gè)是由python編寫(xiě)的基于Docker官方API的一個(gè)編排工具银还,我已經(jīng)安裝了python3環(huán)境风宁,所以直接使用pip3安裝了docker-compose這個(gè)庫(kù)即可使用docker-compose的相關(guān)命令。

$ pip3 install docker-compose
 
$ yum install -y git
 
$ git clone https://github.com/deviantony/docker-elk.git
 
$ cd docker-elk
 
$ docker-compose up

第一次使用 docker-compose up 命令后會(huì)直接開(kāi)始自動(dòng)安裝 ELK 各自的鏡像文件蛹疯,完成安裝后即可開(kāi)始工作戒财,如果需要以deamon的形式運(yùn)行可以加入 -d 參數(shù)

如果下載 Docker 鏡像很慢可以使用能科學(xué)上網(wǎng)的代理或者使用阿里云的容器鏡像服務(wù)里面的鏡像加速器


完成安裝之后可以在項(xiàng)目中直接修改ELK的運(yùn)行配置,例如直接在 docker-compose.yml 中修改 ElasticSearch 的數(shù)據(jù)庫(kù)目錄捺弦,但是這樣修改后需要把文件目錄授權(quán)給用戶 1000饮寞,這里默認(rèn)使用1000這個(gè)用戶來(lái)啟動(dòng) ELK 的服務(wù)的

  elasticsearch:
    build:
      context: elasticsearch/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
      - /data/elasticsearch:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xmx256m -Xms256m"
    networks:
      - elk

logstash中修改下pipe配置,編碼使用json類型列吼,修改 logstash/pipeline/logstash.conf 下配置文件

input {
        tcp {
                port => 5000
                codec => json
        }
}

然后 docker-compose 重啟服務(wù)

  1. 到目前為止幽崩,已經(jīng)完成了 ELK 日志收集的搭建,然后需要在 Flask 中的logger中加入一個(gè)將日志數(shù)據(jù)導(dǎo)入 logstash 的日志文件寞钥,這里我們使用 python-logstash 這個(gè)庫(kù)
class MyLogstashFormatter(LogstashFormatterBase):
 
    def __init__(self, message_type='Logstash', tags=None, fqdn=False, status=None):
        super(MyLogstashFormatter, self).__init__(message_type, tags, fqdn)
        self.status = status if status else {}
 
    def format(self, record):
        message = {
            '@timestamp': self.format_timestamp(record.created),
            '@version': '1',
            'message': self.format_exception(record.exc_info) if self.format_exception(
                record.exc_info) else record.getMessage(),
            'host': local_ip,
            'hostId': HOST_ID,
            'path': '[line:{}]{}'.format(record.lineno, record.pathname),
            'tags': self.tags,
            'process': record.processName,
            'msgType': self.message_type,
            'app': 'api/' + env,
 
            # Extra Fields
            'level': record.levelname,
            'logger_name': self.host,
        }
        # Add extra fields
        message.update(self.get_extra_fields(record))
        
        # delete random item if length of status over 1000
        [self.status.popitem() for i in range(len(self.status)-1000) if len(self.status) >= 1000]
        return self.serialize(message)
 
 
class LogHandler(TCPLogstashHandler):
 
    def __init__(self, host, port, message_type='flask', tags=None, fqdn=False, version=0):
        super(LogHandler, self).__init__(host, port, message_type, tags, fqdn, version)
        self.formatter = MyLogstashFormatter(message_type, tags, fqdn)
 
 
def init(app):
    app.logger.addHandler(LogHandler(LOG_STASH_HOST, LOG_STASH_PORT, tags=''))

LOG_STASH_HOST 和 LOG_STASH_PORT 就是部署 ELK 的地址及端口慌申,然后通過(guò) app.logger 輸出的日志會(huì)直接導(dǎo)入到 logstash中,然后可以在 kibana 中查看到


  1. 已經(jīng)完成了 Flask 的日志導(dǎo)入凑耻,接下去還可以繼續(xù)完成 Gunicorn 的日志導(dǎo)出太示,Gunicorn 我們使用配置文件的形式來(lái)配置參數(shù)
import logging
import multiprocessing
import os
 
from app.config import LOG_STASH_HOST, LOG_STASH_PORT, LOG_PATH
from app.utils.logger import LogHandler
 
debug = False
deamon = False
loglevel = 'info'
bind = '0.0.0.0:12345'
max_requests = 50000
worker_connections = 50000
 
x_forwarded_for_header = "X-Real-IP"
 
# 啟動(dòng)的進(jìn)程數(shù)
workers = multiprocessing.cpu_count()
# workers = 3
worker_class = "gevent"
 
accesslog = os.path.join(LOG_PATH, 'access.log')
access_log_format = '%({X-Real-IP}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
errorlog = os.path.join(LOG_PATH, 'error.log')
 
timeout = 60
 
err_handler = LogHandler(LOG_STASH_HOST, LOG_STASH_PORT, 'error', tags='')
access_handler = LogHandler(LOG_STASH_HOST, LOG_STASH_PORT, 'access', tags='')
err_handler.setLevel(logging.ERROR)
access_handler.setLevel(logging.INFO)
logging.getLogger('gunicorn.error').addHandler(err_handler)
logging.getLogger('gunicorn.access').addHandler(access_handler)
  1. 然后我們的負(fù)載均衡使用 Haproxy臼勉,而 Kibana 的登錄認(rèn)證需要使用付費(fèi)的模塊餐弱,所以我們目前先使用基于負(fù)載均衡的簡(jiǎn)單的http認(rèn)證來(lái)實(shí)現(xiàn)需要登錄才能訪問(wèn) Kibana的功能,Haproxy 和 Nginx都有提供相關(guān)的功能
listen api
    bind *:80
    mode http
 
    acl log_page hdr_beg(host) -i logs.xxxxxx.com
    acl kibana-admin http_auth(kibana-auth-list)
    use_backend kibana if log_page
 
    default_backend api-backend
 
 
userlist kibana-auth-list
    group admin
    user jeff password $5$ySIPTQpg$9tk7BU7DF3tdZhUk8JztPH65Sfxnr.XZWDc5TLD1/3B 
    groups admin
 
 
backend kibana
    acl kibana-admin http_auth(kibana-auth-list)
    http-request auth realm ibeelinkLogger unless kibana-admin
 
    mode http
    server kibana_1 172.19.19.39:5601 check

具體的配置方式可以參考:
https://blog.sleeplessbeastie.eu/2018/03/08/how-to-define-basic-authentication-on-haproxy/

以上就完成了日志到ELK的整個(gè)流程的部署

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驮瞧,一起剝皮案震驚了整個(gè)濱河市论笔,隨后出現(xiàn)的幾起案子蒜埋,更是在濱河造成了極大的恐慌整份,老刑警劉巖烈评,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異沟启,居然都是意外死亡德迹,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門筷转,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)呜舒,“玉大人,你說(shuō)我怎么就攤上這事到腥∠绶叮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵连舍,是天一觀的道長(zhǎng)索赏。 經(jīng)常有香客問(wèn)我埃儿,道長(zhǎng),這世上最難降的妖魔是什么剃斧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮脓杉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沛婴。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著约计,像睡著了一般诀拭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天尉桩,我揣著相機(jī)與錄音翰苫,去河邊找鬼析恋。 笑死滑沧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棚潦。 我是一名探鬼主播令漂,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妹窖!你這毒婦竟也來(lái)了纬朝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤骄呼,失蹤者是張志新(化名)和其女友劉穎共苛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蜓萄,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隅茎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嫉沽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辟犀。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绸硕,靈堂內(nèi)的尸體忽然破棺而出踪蹬,到底是詐尸還是另有隱情,我是刑警寧澤臣咖,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站漱牵,受9級(jí)特大地震影響夺蛇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酣胀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一刁赦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闻镶,春花似錦甚脉、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春猴凹,著一層夾襖步出監(jiān)牢的瞬間夷狰,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工郊霎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沼头,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓书劝,卻偏偏與公主長(zhǎng)得像进倍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子购对,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容