Dockerは仮想技術の一つ程度しか知らいない状態から、JJUG CCC 2018 Spring で「JavaエンジニアのためのDocker入門 ~ 仮想開発・テスト環境構築 ~ 」を聞いて少し勉強してみたのでDockerで環境を作ってみました。「今更Docker入門 - コンテナ化することで何が嬉しいか」の延長線で、Nginxのログを fluentd + elasticsearch + kibana で可視化してみました。ちなみに私は、fluentd も elasticsearch も kibana も聞いたことがあるだけで全く使ったことも無く予備知識もほぼないまま、環境を構築しているので、誤りがあるかもです。
環境
- macOS
- Docker for Mac Version 2.0.0.0-mac81 (Docker)
作るもの
nginxのログを収集して、kibanaでいつどれくらいのアクセスがあったのかを可視化します。今回は、細かい設定はなしで、可視化します。やり方として、nginxのログをfluentdで収集してelasticsearchに蓄積させます。蓄積したデータをもとにkibanaで可視化していきます。
作ったもの
gitを見てください。
cloneした後に、docker-compose build
して、docker-compose up -d
で起動できます。
コマンドを叩くとこんな感じになると思います。初回のbuildは、時間が少しかかります。
$ docker-compose build
Building elasticsearch
Step 1/1 : FROM elasticsearch:5.6
---> 671bb2d7da44
Successfully built 671bb2d7da44
Successfully tagged nginx-monitoring_elasticsearch:latest
Building fluentd
Step 1/2 : FROM fluent/fluentd:v1.3.2-1.0
---> 2b942cd70a7f
Step 2/2 : RUN gem install fluent-plugin-elasticsearch
---> Using cache
---> fb7ab6e052b3
Successfully built fb7ab6e052b3
Successfully tagged nginx-monitoring_fluentd:latest
Building nginx
Step 1/1 : FROM nginx:1.15.8
---> 02256cfb0e4b
Successfully built 02256cfb0e4b
Successfully tagged nginx-monitoring_nginx:latest
Building kibana
Step 1/1 : FROM kibana:5.6.14
---> 4e429ed92aeb
Successfully built 4e429ed92aeb
Successfully tagged nginx-monitoring_kibana:latest
$ docker-compose up -d
Creating network "nginx-monitoring_default" with the default driver
Creating nginx-monitoring_elasticsearch_1 ... done
Creating nginx-monitoring_fluentd_1 ... done
Creating nginx-monitoring_kibana_1 ... done
Creating nginx-monitoring_nginx_1 ... done
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
576dd2bce127 nginx-monitoring_nginx "nginx -g 'daemon of…" 9 seconds ago Up 14 seconds 0.0.0.0:8090->80/tcp nginx-monitoring_nginx_1
ab084c4416a3 nginx-monitoring_kibana "/bin/sh -c /usr/loc…" 10 seconds ago Up 15 seconds 0.0.0.0:5601->5601/tcp nginx-monitoring_kibana_1
ef28ec21fe2b nginx-monitoring_fluentd "/bin/entrypoint.sh …" 10 seconds ago Up 15 seconds 5140/tcp, 0.0.0.0:24224->24224/tcp nginx-monitoring_fluentd_1
2550dc320be2 nginx-monitoring_elasticsearch "/bin/bash bin/es-do…" 11 seconds ago Up 16 seconds 0.0.0.0:9200->9200/tcp, 9300/tcp nginx-monitoring_elasticsearch_1
nginx、fluentd、elasticsearch、kibanaが立ち上がったら、http://localhost:8090/にアクセスしてみます。
その後、kibanaにアクセス(localhost:5601)して、設定後(あとで説明)Timelineから下図のようにアクセス数がグラフで見れます。
そもそもnginx、fluentd、elasticsearch、kibanaを連携させていくために、それぞれについてある程度の知識が必要なので、簡単に次から説明していきます。
nginx
一言で言ってしまうとApacheと同じWebサーバです。が、中身はApacheとは大きく異なります。Apacheは、マルチプロセスモデルで同時アクセス数が増えると起動プロセス数×ヒープサイズの掛け算でメモリを食べにいくためメモリが枯渇しやすくなり、レスポンスが悪くなるます。世にいう、C10K(クライアント1万台)問題と呼ばれているやつです。これに比べ、nginxはC10K問題耐えうるように、イベンドドリブンモデルで同時アクセスに対する処理に特化しているので、Apacheのようにレスポンスが悪くなることはないです。シングルスレッドでプロセス数が増えないように処理しているからです。これだけだと、nginx一択に思えますが、Apacheにもメリットがあり、nginxにもデメリットはあります。nginxに比べApacheは、Webサーバとしての機能が豊富にあり、動的コンテンツの処理速度が速いようです。
スマホの登場でサイトへのアクセス数が増加しているので、nginxは知っておいて損はないですね。(むしろ知らないほうがやばい・・・?)
fluentd
OSSのデータ収集管理ツールです。fluentdの特徴は、データの収集とそのデータの記録先をカスタマイズできることです。データファイルをどこかに転送したり、収集・蓄積をリアルタイムに処理したい場合にとてもいいツールになります。ここでいうデータは主に、ログです。プラグインを使えば、Tweetデータなども収集できます。
イメージとして、上図のような感じです。DBのログやLinuxのログ、Twitterのデータなどをfluentdが収集して、kafkaや、hadoop、elasticsearch、S3などに渡すことができます。
fluentdには、以下のような機能を持ち合わせています。
- input(fluentdに入れる・収集するデータ)
- 必要に応じてパースできる
- タイムスタンプを管理が可能
- output(fluentdが吐き出すデータ)
- 必要に応じてフォーマットできる
- buffer(収集するデータを紛失しない仕組み)
- データのやり取りでなにかエラーがあればリトライしてくれる
- バッファはmemory bufferとfile bufferの2種類がある
memory buffer | file buffer | |
---|---|---|
バッファの場所 | メモリ | ファイル |
処理速度 | 早い | 遅い |
使用容量 | 少ない(メモリ枯渇の可能性有) | 大きい(ディスク容量に依存) |
運用面 | 運用しにくい | 運用しやすい |
bufferは上の表のような特徴がある。基本的には、file bufferがおすすめ。なんらかの理由で、fluentd自体が終了した場合にファイルとしてバッファが残るので確認が行いやすい。処理速度は、memory bufferに比べれば遅いというかだけでI/Oの時間を厳密にきにする状況で無ければメモリ枯渇を危険性を背負いながらmemory bufferを選ぶ理由は無いと思います。一つ注意するとすればデフォルトの設定の場合、memory bufferになっている事です。なので必要に応じてバッファの設定を書き換える必要があります。
elasticsearch
elasticsearchは、elastic社が開発しているオープンソースの全文検索エンジン(分散型RESTful検索/分析エンジン)です。RDBのようにSQLでのデータ操作は行いません。そのかわり、RESTful APIを使って操作します。そのため、様々な言語での操作が可能です。elasticsearchは、主にデータの保存と検索を担当するため、可視化やセキュリティといった部分は、Elastic Stackと呼ばれている関連システム群を使います。Elastic Stackには、elasticsearch、kinaba、Logstash、Beats、X-Pack、ECEといったものがあります。今回は、そこまで難しいことをしないので、あまり説明しません。
Kibana
elasticsearchに入っているデータを様々な形式で可視化することができます。また、elasticsearchに入っているデータの検索もできます。
ログの可視化まで
構成
.
├── docker-compose.yml
├── elasticsearch
│ └── Dockerfile
├── fluentd
│ ├── Dockerfile
│ └── config
│ └── fluent.conf
├── kibana
│ └── Dockerfile
└── nginx
├── Dockerfile
├── config
│ └── nginx.conf
└── html
├── index.html
└── test.html
version: "3.3"
services:
nginx:
build: ./nginx
volumes:
- ./nginx/config/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/log:/var/log/nginx
- ./nginx/html:/usr/share/nginx/html
ports:
- 8090:80
links:
- fluentd
fluentd:
build: ./fluentd
volumes:
- ./fluentd/config:/fluentd/etc
- ./nginx/log:/var/log/nginx
links:
- elasticsearch
ports:
- "24224:24224"
depends_on:
- elasticsearch
elasticsearch:
build: elasticsearch
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata:/usr/share/elasticsearch/data
kibana:
build: kibana
ports:
- "5601:5601"
links:
- elasticsearch:elasticsearch
volumes:
esdata:
driver: local
FROM elasticsearch:5.6.14
# RUN elasticsearch-plugin remove x-pack
elasticsearch:5.6.4の頃はelasticsearchのイメージをそのまま利用するとx-packが入っているため、削除が必要でした。x-packは、有料ツールのため、ライセンスキーが必要になるため、削除または無効化が必要です。5.6.14ではremoveが不要になったようです。
FROM fluent/fluentd:v1.3.2-1.0
RUN gem install fluent-plugin-elasticsearch
今回は、fluentdでelasticsearchにデータを送るために、fluent-plugin-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>
fluentdの設定で<source>
の部分が入力で<match>
が出力に当たります。
今回指定した設定
souece | 設定値 | 概要 |
---|---|---|
type | tail | 入力をtailで読む |
format | ltsv | ltsv形式としてファイル読み込み(加工するわけではない) |
path | /var/log/nginx/access.log | 取り込むデータの場所 |
tag | nginx | tailしたデータの吐き出す場所の指定 |
pos_file | /var/log/nginx/access.log.pos | どこまで読み込んだか記録しているposファイルを指定 |
match | 設定値 | 概要 |
---|---|---|
type | elasticsearch | fluent-plugin-elasticsearchプラグインで追加されたもので、elasticsearchに転送します |
host | elasticsearch | 転送先のホスト |
buffer_type | memory | メモリバッファを指定 |
port | 9200 | 転送先のポート |
index_name | fluentd | elasticsearchでのindex名、logstash_formatがtrueの場合は、利用されない |
type_name | nginx | elasticsearchのタイプ名 |
logstash_format | true | kibanaにlogstashフォーマットで出力するオプション |
logstash_prefix | nginx.access | kibanaに転送するデータのプレフィックス |
source
のtag
に書かれているタグによって出口のmatchを選択する。mathc
は<match nginx>
と設定している。なのでsource
のtag nginx
で収集したデータは<match nginx>
で転送先を仕分けることになります。以下のように複数の出口を設定することも可能です。
<source>
tag hoge.foo
・・・
</source>
<source>
tag hoge.huga
・・・
</source>
# tag hoge.fooの出口
<match hoge.foo>
・・・
</match>
# tag hoge.fooとtag hoge.hugaの両方の出口
<match hoge.**>
・・・
</match>
FROM kibana:5.6.14
# RUN kibana-plugin remove x-pack
kibanaも5.6.4の頃はx-packの削除が必要でしたが、5.6.14で不要のようです。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
# 他のファイルから設定読み込み
# mime.types : MIMEタイプと拡張子の関連付けを定義したファイル
include /etc/nginx/mime.types;
# レスポンスのデフォルトMIMEタイプ設定
default_type application/octet-stream;
# アクセスログの書式設定(ltsv)
log_format ltsv '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 ltsv;
# コンテンツのファイルの読み込みとクライアントへのレスポンスの送信にsendfile() APIを使うかを設定
# デフォルトは off
sendfile on;
include /etc/nginx/conf.d/*.conf;
}
FROM nginx:1.15.8
これで下準備完了。あとはdocker-compose build
してdocker-compose up -d
で起動します。起動したらnginxにアクセスしてログを吐かせます。次にkibanaにアクセスします。kibanaは、127.0.0.1:5601でアクセスできます。
アクセスするとこんな感じになると思います。この画面から、elasticsearchのインデックスを指定します。fluentdの設定でlogstash_prefixに指定したnginx.accessをindex patterに記述し、Createします。
次に、Visualizeから簡単な集計を行って見ます。ログからuseragentを見てブラウザ毎のアクセス数を集計してみます。VisualizeからPieを選択。Split Slicesを追加、AggregationにTermを指定、Fieldにuseragent.keywordを指定、Order ByにCustom Metricを指定してAggregationをCountに
あとは、各種ブラウザで適当にアクセスしてログを作り、Dashboardにグラフ登録したりすれば、可視化完了です。ログファイルを見るより、明らかに可視化した方が見やすく情報も読み取りやすいですね。