ELK Stackでロギング on Docker
TODO: gunicornのLogstashHandlerを使ってTCP経由でESにログを流し込む
今回はflaskでテキトーにログを吐くアプリを作ってアプリとgunicornのロギングをした.
https://gyazo.com/2568e29c00a0001aeaa86803c6635330
code:ファイル構成
$ tree
.
├── app
│ ├── Dockerfile
│ ├── main.py
│ ├── Pipfile
│ └── Pipfile.lock
├── docker-compose.yml
└── logstash
└── logstash.conf
2 directories, 6 files
app
最初に必要なライブラリ等のインストール.ここではpipenvをつかった.
code: 準備
$ cd ./app
$ pipenv install flask gunicorn
$ cat << EOF > Dockerfile
FROM python:3.7-alpine
RUN pip install pipenv
EOF
すごくテキトーなアプリ./にアクセスするとランダムにいくつかのログを吐く:
code:app/main.py
import logging
import os
import random
from flask import Flask, jsonify
LOGPATH = os.environ.get('LOGPATH', '/tmp/app.log')
logging.basicConfig(filename=LOGPATH,
filemode='a',
format='%(asctime)s %(levelname)s-%(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
app = Flask(__name__)
@app.route('/')
def main():
for _ in range(0, 10):
x = random.randint(0, 2)
if x == 0:
app.logger.warning('this is WARNING message')
elif x == 1:
app.logger.critical('this is CRITICAL message')
else:
app.logger.error('this is ERROR message')
return jsonify('Hello, world!')
logstash
logstashの設定.ログのパースにはgrokを使う.
code:logstash/logstash.conf
input {
file {
path => "/logs/*.log"
start_position => "beginning"
}
}
filter {
mutate { replace => { type => "access_logs" } }
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
date {
}
} else if path =~ "app" { mutate { replace => { type => "app_logs" } }
grok {
match => {"message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:log-level}-%{GREEDYDATA:message}"}
}
date {
}
} else {
mutate { replace => { type => "random_logs" } }
}
}
output{
elasticsearch {
index => "myapp_logs"
}
stdout { codec => rubydebug }
}
docker-compose.yml
アプリとlogstashのどちらのコンテナからもログファイルにアクセスできるように,それぞれ同じdata volume (logs) をマウントしてそこにログファイルを設置している.
code:docker-compose.yml
version: '3'
services:
app:
build: ./app
environment:
- LOGPATH=/logs/app.log
ports:
- "5000:5000"
command:
- "sh"
- "-c"
- "pipenv sync && pipenv run gunicorn -w5 -b :5000 --access-logfile=/logs/access.log main:app"
volumes:
- ./app:/app
- logs:/logs
working_dir: /app
kibana:
image: docker.elastic.co/kibana/kibana:6.6.1
ports:
- "5601:5601"
links:
- elasticsearch
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.6.1
links:
- logstash
logstash:
image: docker.elastic.co/logstash/logstash:6.6.1
volumes:
- ./logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
- logs:/logs
volumes:
logs:
実行
最初,普通にdocker-compose upしたらbootstrap checks failedなど出てきてelasticsearchの起動ができなかった.
$ sudo sysctl -w vm.max_map_count=262144
すべて起動するまでしばらく待ってアプリ localhost:5000 にアクセスしてログをためる.
その後 ブラウザで localhost:5601 にアクセスすればkibanaの画面がみれるので好きに可視化すればよい.
参考: