はじめに
Docker Compose でミニマムに ELK スタックに入門する記録 – oki2a24 の続きです。
前回までは、 Nginx コンテナの、 Nginx のログ、 /var/log/nginx/access.log
などのログファイルを、ディレクトリ共有することで Logstash もアクセス可能にし、読み取る、というやり方でやってきました。
今回は、ログファイルをファイルに書き込むのではなく標準出力にして (変更するというよりも、標準出力がデフォルト) 、そうするとログは Nginx コンテナのログとして出力されますので、これを Logstash で扱う、ということをやっていきます。
無事できたので、ワクワクしています♪
ポイント
- Docker のロギング・ドライバ gelf を使用する。これは Graylog Extendef ログ・フォーマット(GELF)ロギング・ドライバといい、ログ・メッセージを Graylog のエンドポイントや Logstash に記録する。
- ログを出力するコンテナ (Logstash 用にログを出力したコンテナ) の
logging
オプションで設定する。driver: gelf
、options:
のgelf-address: udp://localhost:12201
、 の 2 つが最低必要。gelf-address: udp://<Logstash サーバのアドレス>:<Logstash サーバのポート>
というフォーマット。 Docker Compose で同じマシンのコンテナを指定したい場合、アドレスはlocalhost
と指定する。たとえば services で logstash と定義しても、gelf-address: udp://logstash:12201
では動かない。
- Logstash コンテナ
- Docker Compose で、
ports:
で "12201:12201/udp" を追加し、送られてくるログを受け入られるようにしておく。 - 設定ファイル (logstash.conf など) の
input
では、gelf
を指定し、type => docker
、port => 12201
と設定する。
- Docker Compose で、
コード
前回 から変更した所は、コメントにしています。
docker-compose.yml
version: "3"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0
ports:
- "9200:9200"
- "9300:9300"
environment:
discovery.type: "single-node"
volumes:
- "es_data:/usr/share/elasticsearch/data"
kibana:
image: docker.elastic.co/kibana/kibana-oss:7.0.0
ports:
- "5601:5601"
environment:
ELASTICSEARCH_URL: "http://elasticsearch:9200"
depends_on:
- elasticsearch
logstash:
image: docker.elastic.co/logstash/logstash-oss:7.0.0
ports:
- "12201:12201/udp"
volumes:
- "./data/logstash/pipeline:/usr/share/logstash/pipeline"
# - "./data/nginx/log:/var/log/nginx"
depends_on:
- elasticsearch
nginx:
image: nginx:latest
ports:
- "80:80"
#volumes:
# - "./data/nginx/log:/var/log/nginx"
logging:
driver: gelf
options:
gelf-address: udp://localhost:12201
tag: "docker.{{.Name}}"
depends_on:
- logstash
volumes:
es_data:
driver: local
data/logstash/pipeline/logstash.conf
input {
#file {
# path => "/var/log/nginx/access.log"
# start_position => beginning
#}
gelf {
type => docker
port => 12201
}
}
filter {
grok {
match => { "message" => ["%{IPORHOST:[nginx][access][remote_ip]} - %{DATA:[nginx][access][user_name]} \[%{HTTPDATE:[nginx][access][time]}\] \"%{WORD:[nginx][access][method]} %{DATA:[nginx][access][url]} HTTP/%{NUMBER:[nginx][access][http_version]}\" %{NUMBER:[nginx][access][response_code]} %{NUMBER:[nginx][access][body_sent][bytes]} \"%{DATA:[nginx][access][referrer]}\" \"%{DATA:[nginx][access][agent]}\""] }
remove_field => "message"
}
mutate {
add_field => { "read_timestamp" => "%{@timestamp}" }
}
date {
match => [ "[nginx][access][time]", "dd/MMM/YYYY:H:m:s Z" ]
remove_field => "[nginx][access][time]"
}
useragent {
source => "[nginx][access][agent]"
target => "[nginx][access][user_agent]"
remove_field => "[nginx][access][agent]"
}
geoip {
source => "[nginx][access][remote_ip]"
target => "[nginx][access][geoip]"
}
}
output {
elasticsearch {
hosts => [ 'elasticsearch' ]
index => "access_log1"
}
}
参考ページ
- ベースとさせていただいた具体例
- Docker ロギング・ドライバ の gelf オプション
- なぜ
gelf-address: udp://logstash:12201
ではなくgelf-address: udp://localhost:12201
なのか?
補足。なぜ gelf-address: udp://logstash:12201
ではなく gelf-address: udp://localhost:12201
なのか?
ロギング・ドライバに設定するアドレスは Docker コンテナからではなく、Docker ホストから到達可能な URL でなければならないから。
gelf-address needs to use a hostname/IP that is reachable from the host
it doesn’t work because the log driver urls needs to be accessible by the daemon, not by the container.
おわりに
少しずつ進んでいます♪
次は、ログを送る側と、ログを受け取る側を分離して、動かせるようにしたいです。
以上です。