Nginx のアクセスカウントを Fluentd を使って Grafana で可視化する
nginx のアクセスカウントを Fluentd を使って Grafana で可視化する
今回は表題の OSS 群をとりあえず使ってみて慣れることを目標に、Docker(Compose) を使って、簡単なハンズオンをやってみました。
今回使用した OSS の主な役割は以下のとおりです。
- nginx: テスト用のアクセスログを生成します。
- Fluentd: nginx のアクセスログを Elasticsearch に転送します
- Elasticsearch: Fluentd から取得したデータを提供するサービスを提供します
- Grafana: Elasticsearch からアクセスログデータを取得し、アクセスカウントをダッシュボード上に表示します。
本稿で作成したコードはすべて以下のリポジトリにまとめてありますので、ご自由にお使いください。Pull Request 等も歓迎です。
nginx
docker-compose.yml
services:
nginx:
image: nginx:1.19.7-alpine
container_name: nginx
ports:
# バインドするポート番号は設定値として吐き出す
- ${NGINX_PORT}:80
volumes:
# ローカルで作成した `nginx.conf` をコンテナにマウントして設定を反映させます
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
# アクセスログ等をローカルから参照できるようにします
- ./outputs/nginx:/var/log/nginx
# コンテナ間通信を有効にするため、適当な共通の名前のネットワークを設定します
networks:
- shared-network
nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main 'time:$time_iso8601\t'
'remote_addr:$remote_addr\t'
'request_method:$request_method\t'
'request_length:$request_length\t'
'request_uri:$request_uri\t'
'https:$https\t'
'uri:$uri\t'
'query_string:$query_string\t'
'status:$status\t'
'bytes_sent:$bytes_sent\t'
'body_bytes_sent:$body_bytes_sent\t'
'referer:$http_referer\t'
'useragent:$http_user_agent\t'
'forwardedfor:$http_x_forwarded_for\t'
'request_time:$request_time\t'
'upstream_response_time:$upstream_response_time\t'
'host:$host';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
nginx の Docker イメージをデフォルト状態で起動した状態のファイルをベースにしています。
Fluentd でアクセスログを ElasticSearch に集約するため、log_format
をタブ区切りの文字列として出力するようにしました。
docker-compose up -d nginx
で nginx サービスが起動します。
http://localhost:${NGINX_PORT}
にアクセスすると、outputs/nginx/access.log
に以下の通りタブ区切りのアクセスログが出力されました。
time:2021-03-26T05:26:19+00:00 remote_addr:172.18.0.1 request_method:GET request_length:726 request_uri:/ https: uri:/index.html query_string:- status:200 bytes_sent:850 body_bytes_sent:612 referer:- useragent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 forwardedfor:- request_time:0.000 upstream_response_time:- host:localhost
Fluentd
docker-compose.yml
services:
fluentd:
build:
context: .
dockerfile: ./docker/fluentd/Dockerfile
container_name: fluentd
ports:
- ${FLUENTD_PORT}:24224
- ${FLUENTD_PORT}:24224/udp
volumes:
# 設定ファイルをマウントします。(詳細は後述)
- ./docker/fluentd/fluent.conf:/fluentd/etc/fluent.conf
# nginx のアクセスログを参照できるようにします。
- ./outputs/nginx:/var/log/nginx
networks:
- shared-network
Dockerfile
FROM fluent/fluentd:v1.3-1
# https://qiita.com/tamanobi/items/a57f2802c7fd1236ea52
USER root
# Elasticsearch のプラグインをイメージのビルド時にインストールしておきます。
RUN gem install fluent-plugin-elasticsearch
fluent.conf
タブ区切りの nginx のアクセスログを Elasticsearch に転送します。
<source>
type tail
format ltsv
path /var/log/nginx/access.log
tag nginx
pos_file /var/log/nginx/access.log.pos
</source>
<match nginx>
type elasticsearch
host elasticsearch
buffer_type memory
port 9200
index_name fluentd
type_name nginx
logstash_format true
logstash_prefix nginx.access
</match>
Elasticsearch
docker-compose.yml
Elasticsearch の公式イメージをシングルノードで構築します。
services:
elasticsearch:
image: elasticsearch:7.10.1
container_name: elasticsearch
ports:
- ${ELASTICSEARCH_PORT}:9200
environment:
- discovery.type=single-node
networks:
- shared-network
試しにアクセスすると以下の json が返ってきました。
curl -sL http://localhost:9200/ | jq .
{
"name": "d8e38c95c00d",
"cluster_name": "docker-cluster",
"cluster_uuid": "UNfF0G0yRS-aGCpmGUpWCA",
"version": {
"number": "7.10.1",
"build_flavor": "default",
"build_type": "docker",
"build_hash": "1c34507e66d7db1211f66f3513706fdf548736aa",
"build_date": "2020-12-05T01:00:33.671820Z",
"build_snapshot": false,
"lucene_version": "8.7.0",
"minimum_wire_compatibility_version": "6.8.0",
"minimum_index_compatibility_version": "6.0.0-beta1"
},
"tagline": "You Know, for Search"
}
Grafana
docker-compose.yml
ユーザ名、パスワード等はそれぞれ ${GRAFANA_SECURITY_ADMIN_USER}
、${GRAFANA_SECURITY_ADMIN_PASSWORD}
で設定できるようにしました。
http://localhost:${GRAFANA_PORT}
で Grafana が起動します。
services:
grafana:
image: grafana/grafana:7.4.3
container_name: grafana
ports:
- ${GRAFANA_PORT}:3000
environment:
- GF_SECURITY_ADMIN_USER=${GRAFANA_SECURITY_ADMIN_USER}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_SECURITY_ADMIN_PASSWORD}
volumes:
# datasources をマウント
- ./docker/grafana/datasources:/etc/grafana/provisioning/datasources
networks:
- shared-network
datasources.yml
datasource の設定は都度手動で設定しても良いですが、設定が静的であれば YAML ファイルとして書き出し、Grafana サービスにファイルをマウントするとよいです。
ファイルが適切にマウントされて Grafana が起動すると datasource が反映された状態でサービスが立ち上がってくれて便利です。
datasource の定義方法は、https://github.com/grafana/grafana/blob/master/devenv/datasources.yaml を参考にしました。
今回定義した datasource は以下の通りです。
apiVersion: 1
datasources:
- name: elasticsearch
type: elasticsearch
access: proxy
database: "[nginx.access-]YYYY.MM.DD"
url: http://elasticsearch:9200
jsonData:
timeInterval: 10s
interval: Daily
timeField: "@timestamp"
esVersion: 70
Dashboard から Elasticsearch を選択し、適切なクエリを設定すると nginx のアクセスログを Grafana のダッシュボードから確認できます。
なお、Elasticsearch への接続に失敗する場合は、テーブルが作成されていないことに起因するため、Nginx サーバにアクセスしてテーブルが生成されることを確認してください。
Discussion