やること
Nginx2台をコンテナで構築し、コンテナごとにIndexを分けてElasticsearchに送るようにします。
Nginx2台を構築すると、ポートを切り替えてアクセスする必要があります。
しかし、構成的に綺麗ではないので、
Trafikというリバプロを利用してパスベースでアクセス先のNginxを振り分けられるようにしました。これにより、Traefikの80番ポートだけ公開すれば良くなります。
Trafikの構成については以下を参考にしました。
ソース
ソースは以下にアップしています。
Quick Start
git clone https://github.com/v1tam1nb2/traefik-nginx-fluentd-elasticsearch.git
cd traefik-nginx-fluentd-elasticsearch
docker-compose build
docker-compose up -d
curl http://localhost/service-a.html
curl http://localhost/service-b.html
アクセス後、Kibanaにアクセスしてログを確認できるようにします。
初回は以下でデータビューの作成が必要になります。
データビューについては以下を参考にしてください。
最終的にこのようにログが確認できればOKです。
ソース
Traefik
以下がTraefikのセクションです。ポートの18000:8080
はTraefikのDashboardにアクセスするためのものです。今回はあまり気にしなくてもOKです。
# リバプロ
traefik:
image: traefik:latest
container_name: "traefik"
ports:
- "80:80"
- "18000:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- ./src/traefik/traefik.yml:/etc/traefik/traefik.yml
# Provider
providers:
docker:
exposedByDefault: false
# エントリーポイント
entryPoints:
http:
address: ":80"
# clickhouse:
# address: ":9000"
# udp-test:
# address: ":3179/udp"
api:
# Dashboard有効化
dashboard: true
insecure: true
# ログレベル
log:
level: DEBUG
Nginx
nginx_a:
image: nginx
container_name: nginx_a
hostname: nginx_a
volumes:
- ${PWD}/src/nginx/service-a.html:/usr/share/nginx/html/service-a.html
labels:
- "traefik.enable=true"
- "traefik.http.routers.service-a.rule=PathPrefix(`/service-a`)"
- "traefik.http.routers.service-a.entrypoints=http"
depends_on:
- fluentd
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: nginx.a.access
# 起動時に接続を確立的無くても contaienr は起動する設定
fluentd-async-connect: "true"
nginx_b:
image: nginx
container_name: nginx_b
hostname: nginx_b
volumes:
- ${PWD}/src/nginx/service-b.html:/usr/share/nginx/html/service-b.html
labels:
- "traefik.enable=true"
- "traefik.http.routers.service-b.rule=PathPrefix(`/service-b`)"
- "traefik.http.routers.service-b.entrypoints=http"
depends_on:
- fluentd
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: nginx.b.access
# 起動時に接続を確立的無くても contaienr は起動する設定
fluentd-async-connect: "true"
labels
でTraefikによるルーティング設定を定義しています。以下はhttp://localhost/service-a.html
にアクセスすると、nginx_a
コンテナのservice-a.html
を見るようにする設定です。
traefik.http.routers.service-a.entrypoints
にはtraefik.yml
に定義したentrypoint
を指定します。今回はhttp
という名前で定義しています。
labels:
- "traefik.enable=true"
- "traefik.http.routers.service-a.rule=PathPrefix(`/service-a`)"
- "traefik.http.routers.service-a.entrypoints=http"
以下はコンテナのログをFluentdに転送するための設定です。コンテナごとにIndexを分けるために、tag
で識別できるようにしています。
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: nginx.a.access
# 起動時に接続を確立的無くても contaienr は起動する設定
fluentd-async-connect: "true"
Fluentd
Elastisearch用のプラグインをインストールしています。
# https://docs.fluentd.org/output/elasticsearch
FROM fluent/fluentd:v1.15.0-debian-1.0
USER root
# FluentdとElasticsearchを連携させるためのプラグインをインストール
RUN gem install fluent-plugin-elasticsearch --no-document --version 5.2.4
USER fluent
fluentd:
build: ./src/fluentd
container_name: fluentd
hostname: fluentd
restart: always
ports:
- "24224:24224"
- "24220:24220"
- "24224:24224/udp"
# depends_on:
# - es
volumes:
#- ${PWD}/log:/fluentd/log
- ${PWD}/src/fluentd/fluent.conf:/fluentd/etc/fluent.conf:ro
confでは、tag
ごとにアウトプット先のIndexを分けるようにしています。nginx_a
コンテナのログはIndex nginx-a-log*
に、nginx_b
コンテナのログはIndex nginx-b-log*
に入れるようにします。
# Fluentdの内部メトリックをHTTPで取得できる設定
# https://docs.fluentd.org/input/monitor_agent
<source>
@type monitor_agent
bind 0.0.0.0
port 24220
</source>
# データのInput設定
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
# データのOutput設定 (FluentdからElasticsearch)
# tag "nginx.a"にマッチするログをESに転送
<match nginx.a.**>
@type copy
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix nginx-a-log
logstash_dateformat %Y%m%d
include_tag_key true
type_name access_log
tag_key @log_name
flush_interval 1s
</store>
<store>
@type stdout
</store>
# バッファの定義
<buffer>
@type file
flush_mode interval
flush_interval 10s
path /var/log/fluentd/elasticsearch
chunk_limit_size 512m
flush_at_shutdown true
</buffer>
</match>
# データのOutput設定 (FluentdからElasticsearch)
# tag "nginx.b"にマッチするログをESに転送
<match nginx.b.**>
@type copy
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix nginx-b-log
logstash_dateformat %Y%m%d
include_tag_key true
type_name access_log
tag_key @log_name
flush_interval 1s
</store>
<store>
@type stdout
</store>
# バッファの定義
<buffer>
@type file
flush_mode interval
flush_interval 10s
path /var/log/fluentd/elasticsearch
chunk_limit_size 512m
flush_at_shutdown true
</buffer>
</match>
Elasticsearch/Kibana
今回は8.4.3
を利用しました。簡単にするためにシングルノードで構築している点に注意してください。
# Elasticsearchコンテナ
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.4.3
container_name: elasticsearch
hostname: elasticsearch
restart: always
environment:
- discovery.type="single-node"
- cluster.name="es-cluster"
- node.name="elasticsearch"
- bootstrap.memory_lock=true
- xpack.security.enabled=false
- TZ=Asia/Tokyo
ulimits:
memlock:
soft: -1
hard: -1
# volumes:
# # データを永続化
# - ${PWD}/data:/usr/share/elasticsearch/data
ports:
- 9200:9200
# Kibanaのコンテナ
kibana:
image: docker.elastic.co/kibana/kibana:8.4.3
container_name: kibana
hostname: kibana
ports:
- 5601:5601
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
- TZ=Asia/Tokyo
- I18N_LOCALE=ja-JP
depends_on:
- elasticsearch
restart: always
まとめ
コンテナのログをFluentd経由でElasticsearchに転送し、Kibanaで確認することができました。
Fluentdのtagを利用することでアウトプット先のIndexを分けることができました。
今回はログの加工などは行いませんでしたが、機会があればやってみたいと思います。