以下文章來(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è)很好的選擇。
-
服務(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
- 安裝完成后需要開(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ù)
- 到目前為止幽崩,已經(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 中查看到
- 已經(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)
- 然后我們的負(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è)流程的部署